jackrabbit-oak-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ju...@apache.org
Subject svn commit: r1445999 - in /jackrabbit/oak/trunk/oak-core/src: main/java/org/apache/jackrabbit/oak/api/ main/java/org/apache/jackrabbit/oak/plugins/memory/ main/java/org/apache/jackrabbit/oak/plugins/segment/ main/java/org/apache/jackrabbit/oak/security...
Date Thu, 14 Feb 2013 00:42:37 GMT
Author: jukka
Date: Thu Feb 14 00:42:36 2013
New Revision: 1445999

URL: http://svn.apache.org/r1445999
Log:
OAK-593: Segment-based MK

Node templates. The size of a basic ACL with four ACEs comes down from 631 bytes to 394 bytes, amortized to 140 bytes.

Added:
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/AbstractPropertyState.java
Modified:
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/EmptyPropertyState.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/NodeTemplate.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/PropertyTemplate.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentNodeState.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentNodeStoreBranch.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentPropertyState.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentReader.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentWriter.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeBits.java
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/segment/SegmentSizeTest.java

Added: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/AbstractPropertyState.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/AbstractPropertyState.java?rev=1445999&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/AbstractPropertyState.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/AbstractPropertyState.java Thu Feb 14 00:42:36 2013
@@ -0,0 +1,97 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.jackrabbit.oak.api;
+
+import javax.jcr.PropertyType;
+
+import com.google.common.collect.Iterables;
+import org.apache.jackrabbit.oak.api.PropertyState;
+import org.apache.jackrabbit.oak.api.Type;
+
+import static org.apache.jackrabbit.oak.api.Type.BINARIES;
+import static org.apache.jackrabbit.oak.api.Type.STRING;
+import static org.apache.jackrabbit.oak.api.Type.STRINGS;
+
+/**
+ * Abstract base class for {@link PropertyState} implementations. This
+ * class provides default implementations of basic {@link Object} methods,
+ * for consistency across all property states.
+ */
+public abstract class AbstractPropertyState implements PropertyState {
+
+    /**
+     * Checks whether the given object is equal to this one. Two property
+     * states are considered equal if their names and types match and
+     * their string representation of their values are equal.
+     * Subclasses may override this method with a more efficient
+     * equality check if one is available.
+     *
+     * @param other target of the comparison
+     * @return {@code true} if the objects are equal, {@code false} otherwise
+     */
+    @Override
+    public boolean equals(Object other) {
+        if (this == other) {
+            return true;
+        } else if (other instanceof PropertyState) {
+            PropertyState that = (PropertyState) other;
+            if (!getName().equals(that.getName())) {
+                return false;
+            } else if (!getType().equals(that.getType())) {
+                return false;
+            } else if (getType().tag() == PropertyType.BINARY) {
+                return Iterables.elementsEqual(
+                        getValue(BINARIES), that.getValue(BINARIES));
+            } else {
+                return Iterables.elementsEqual(
+                        getValue(STRINGS), that.getValue(STRINGS));
+            }
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * Returns a hash code that's compatible with how the
+     * {@link #equals(Object)} method is implemented. The current
+     * implementation simply returns the hash code of the property name
+     * since {@link PropertyState} instances are not intended for use as
+     * hash keys.
+     *
+     * @return hash code
+     */
+    @Override
+    public int hashCode() {
+        return getName().hashCode();
+    }
+
+    @Override
+    public String toString() {
+        if (getType() == Type.BINARIES) {
+            return getName() + " = [" + count() + " binaries]"; 
+        } else if (getType() == Type.BINARY) {
+            return getName() + " = {" + size() + " bytes}"; 
+        } else if (isArray()) {
+            return getName() + " = " + getValue(STRINGS);
+        } else {
+            return getName() + " = " + getValue(STRING);
+        }
+    }
+
+}

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/EmptyPropertyState.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/EmptyPropertyState.java?rev=1445999&r1=1445998&r2=1445999&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/EmptyPropertyState.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/EmptyPropertyState.java Thu Feb 14 00:42:36 2013
@@ -24,6 +24,8 @@ import javax.annotation.Nonnull;
 import javax.jcr.PropertyType;
 
 import com.google.common.collect.Iterables;
+
+import org.apache.jackrabbit.oak.api.AbstractPropertyState;
 import org.apache.jackrabbit.oak.api.PropertyState;
 import org.apache.jackrabbit.oak.api.Type;
 
@@ -38,7 +40,8 @@ import static org.apache.jackrabbit.oak.
  * providing default implementation which correspond to a property
  * without any value.
  */
-public abstract class EmptyPropertyState implements PropertyState {
+abstract class EmptyPropertyState extends AbstractPropertyState {
+
     private final String name;
 
     /**
@@ -126,63 +129,4 @@ public abstract class EmptyPropertyState
         return 0;
     }
 
-    //------------------------------------------------------------< Object >--
-
-    /**
-     * Checks whether the given object is equal to this one. Two property
-     * states are considered equal if their names and types match and
-     * their string representation of their values are equal.
-     * Subclasses may override this method with a more efficient
-     * equality check if one is available.
-     *
-     * @param other target of the comparison
-     * @return {@code true} if the objects are equal, {@code false} otherwise
-     */
-    @Override
-    public boolean equals(Object other) {
-        if (this == other) {
-            return true;
-        } else if (other instanceof PropertyState) {
-            PropertyState that = (PropertyState) other;
-            if (!getName().equals(that.getName())) {
-                return false;
-            }
-            if (!getType().equals(that.getType())) {
-                return false;
-            }
-            if (getType().tag() == PropertyType.BINARY) {
-                return Iterables.elementsEqual(
-                        getValue(BINARIES), that.getValue(BINARIES));
-            } else {
-                return Iterables.elementsEqual(
-                        getValue(STRINGS), that.getValue(STRINGS));
-            }
-        } else {
-            return false;
-        }
-    }
-
-    /**
-     * Returns a hash code that's compatible with how the
-     * {@link #equals(Object)} method is implemented. The current
-     * implementation simply returns the hash code of the property name
-     * since {@link PropertyState} instances are not intended for use as
-     * hash keys.
-     *
-     * @return hash code
-     */
-    @Override
-    public int hashCode() {
-        return name.hashCode();
-    }
-
-    @Override
-    public String toString() {
-        if (isArray()) {
-            return getName() + '=' + getValue(STRINGS);
-        } else {
-            return getName() + '=' + getValue(STRING);
-        }
-    }
-
 }

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/NodeTemplate.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/NodeTemplate.java?rev=1445999&r1=1445998&r2=1445999&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/NodeTemplate.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/NodeTemplate.java Thu Feb 14 00:42:36 2013
@@ -19,23 +19,30 @@ package org.apache.jackrabbit.oak.plugin
 import static com.google.common.base.Preconditions.checkState;
 
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.List;
-import java.util.Map;
 
 import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
 
 import org.apache.jackrabbit.oak.api.PropertyState;
 import org.apache.jackrabbit.oak.api.Type;
+import org.apache.jackrabbit.oak.plugins.memory.MemoryChildNodeEntry;
+import org.apache.jackrabbit.oak.plugins.segment.MapRecord.Entry;
+import org.apache.jackrabbit.oak.spi.state.ChildNodeEntry;
 import org.apache.jackrabbit.oak.spi.state.NodeState;
 
+import com.google.common.base.Function;
 import com.google.common.base.Objects;
+import com.google.common.collect.Iterables;
 import com.google.common.collect.Lists;
 
 class NodeTemplate {
 
-    private final String ZERO_CHILD_NODES = null;
+    static final String ZERO_CHILD_NODES = null;
 
-    private final String MANY_CHILD_NODES = "";
+    static final String MANY_CHILD_NODES = "";
 
     /**
      * The {@code jcr:primaryType} property, if present as a single-valued
@@ -55,6 +62,7 @@ class NodeTemplate {
      * Templates of all the properties of a node, excluding the
      * above-mentioned {@code NAME}-valued type properties, if any.
      */
+    @Nonnull
     private final PropertyTemplate[] properties;
 
     /**
@@ -62,7 +70,17 @@ class NodeTemplate {
      * Otherwise {@link #ZERO_CHILD_NODES} (i.e. {@code null}) if there are
      * no children, or {@link #MANY_CHILD_NODES} if there are more than one.
      */
-    private final String nodeName;
+    @CheckForNull
+    private final String childName;
+
+    NodeTemplate(
+            PropertyState primaryType, PropertyState mixinTypes,
+            PropertyTemplate[] properties, String childName) {
+        this.primaryType = primaryType;
+        this.mixinTypes = mixinTypes;
+        this.properties = properties;
+        this.childName = childName;
+    }
 
     NodeTemplate(NodeState state) {
         PropertyState primary = null;
@@ -89,12 +107,60 @@ class NodeTemplate {
 
         long count = state.getChildNodeCount();
         if (count == 0) {
-            nodeName = ZERO_CHILD_NODES;
+            childName = ZERO_CHILD_NODES;
         } else if (count == 1) {
-            nodeName = state.getChildNodeNames().iterator().next();
-            checkState(nodeName != null && !nodeName.equals(MANY_CHILD_NODES));
+            childName = state.getChildNodeNames().iterator().next();
+            checkState(childName != null && !childName.equals(MANY_CHILD_NODES));
+        } else {
+            childName = MANY_CHILD_NODES;
+        }
+    }
+
+    public boolean hasPrimaryType() {
+        return primaryType != null;
+    }
+
+    public String getPrimaryType() {
+        if (primaryType != null) {
+            return primaryType.getValue(Type.NAME);
         } else {
-            nodeName = MANY_CHILD_NODES;
+            return null;
+        }
+    }
+
+    public boolean hasMixinTypes() {
+        return mixinTypes != null;
+    }
+
+    public Iterable<String> getMixinTypes() {
+        if (mixinTypes != null) {
+            return mixinTypes.getValue(Type.NAMES);
+        } else {
+            return null;
+        }
+    }
+
+    public PropertyTemplate[] getPropertyTemplates() {
+        return properties;
+    }
+
+    public boolean hasNoChildNodes() {
+        return childName == ZERO_CHILD_NODES;
+    }
+
+    public boolean hasOneChildNode() {
+        return !hasNoChildNodes() && !hasManyChildNodes();
+    }
+
+    public boolean hasManyChildNodes() {
+        return childName == MANY_CHILD_NODES;
+    }
+
+    public String getChildName() {
+        if (hasOneChildNode()) {
+            return childName;
+        } else {
+            return null;
         }
     }
 
@@ -108,6 +174,140 @@ class NodeTemplate {
         }
     }
 
+    public PropertyState getProperty(
+            String name, SegmentReader reader, RecordId recordId) {
+        if ("jcr:primaryType".equals(name) && primaryType != null) {
+            return primaryType;
+        } else if ("jcr:mixinTypes".equals(name) && mixinTypes != null) {
+            return mixinTypes;
+        } else {
+            int offset = 8;
+            if (hasNoChildNodes()) {
+                offset = 4;
+            }
+            for (int i = 0; i < properties.length; i++) {
+                int diff = name.compareTo(properties[i].getName());
+                if (diff == 0) {
+                    return new SegmentPropertyState(
+                            properties[i], reader,
+                            reader.readRecordId(recordId, offset + i * 4));
+                } else if (diff < 0) {
+                    return null;
+                }
+            }
+            return null;
+        }
+    }
+
+    public Iterable<PropertyState> getProperties(
+            SegmentReader reader, RecordId recordId) {
+        List<PropertyState> list =
+                Lists.newArrayListWithCapacity(properties.length + 2);
+        if (primaryType != null) {
+            list.add(primaryType);
+        }
+        if (mixinTypes != null) {
+            list.add(mixinTypes);
+        }
+        int offset = 8;
+        if (hasNoChildNodes()) {
+            offset = 4;
+        }
+        for (int i = 0; i < properties.length; i++) {
+            RecordId propertyId = reader.readRecordId(recordId, offset + i * 4);
+            list.add(new SegmentPropertyState(
+                    properties[i], reader, propertyId));
+        }
+        return list;
+    }
+
+    public long getChildNodeCount(SegmentReader reader, RecordId recordId) {
+        if (hasNoChildNodes()) {
+            return 0;
+        } else if (hasManyChildNodes()) {
+            RecordId childNodesId = reader.readRecordId(recordId, 4);
+            return new MapRecord(childNodesId).size(reader);
+        } else {
+            return 1;
+        }
+    }
+
+    public boolean hasChildNode(
+            String name, SegmentReader reader, RecordId recordId) {
+        if (hasNoChildNodes()) {
+            return false;
+        } else if (hasManyChildNodes()) {
+            RecordId childNodesId = reader.readRecordId(recordId, 4);
+            return new MapRecord(childNodesId).getEntry(reader, name) != null;
+        } else {
+            return name.equals(childName);
+        }
+    }
+
+    public NodeState getChildNode(
+            String name, SegmentReader reader, RecordId recordId) {
+        if (hasNoChildNodes()) {
+            return null;
+        } else if (hasManyChildNodes()) {
+            RecordId childNodesId = reader.readRecordId(recordId, 4);
+            RecordId childNodeId =
+                    new MapRecord(childNodesId).getEntry(reader, name);
+            if (childNodeId != null) {
+                return new SegmentNodeState(reader, childNodeId);
+            } else {
+                return null;
+            }
+        } else if (name.equals(childName)) {
+            RecordId childNodeId =
+                    reader.readRecordId(recordId, 4);
+            return new SegmentNodeState(reader, childNodeId);
+        } else {
+            return null;
+        }
+    }
+
+    public Iterable<String> getChildNodeNames(
+            SegmentReader reader, RecordId recordId) {
+        if (hasNoChildNodes()) {
+            return Collections.emptyList();
+        } else if (hasManyChildNodes()) {
+            RecordId childNodesId = reader.readRecordId(recordId, 4);
+            return Iterables.transform(
+                    new MapRecord(childNodesId).getEntries(reader),
+                    new Function<MapRecord.Entry, String>() {
+                        @Override @Nullable
+                        public String apply(@Nullable Entry input) {
+                            return input.getKey();
+                        }
+                    });
+        } else {
+            return Collections.singletonList(childName);
+        }
+    }
+
+    public Iterable<? extends ChildNodeEntry> getChildNodeEntries(
+            final SegmentReader reader, RecordId recordId) {
+        if (hasNoChildNodes()) {
+            return Collections.emptyList();
+        } else if (hasManyChildNodes()) {
+            RecordId childNodesId = reader.readRecordId(recordId, 4);
+            return Iterables.transform(
+                    new MapRecord(childNodesId).getEntries(reader),
+                    new Function<MapRecord.Entry, ChildNodeEntry>() {
+                        @Override @Nullable
+                        public ChildNodeEntry apply(@Nullable Entry input) {
+                            return new MemoryChildNodeEntry(
+                                    input.getKey(),
+                                    new SegmentNodeState(reader, input.getValue()));
+                        }
+                    });
+        } else {
+            RecordId childNodeId = reader.readRecordId(recordId, 4);
+            return Collections.singletonList(new MemoryChildNodeEntry(
+                    childName, new SegmentNodeState(reader, childNodeId)));
+        }
+    }
+
     //------------------------------------------------------------< Object >--
 
     @Override
@@ -119,7 +319,7 @@ class NodeTemplate {
             return Objects.equal(primaryType, that.primaryType)
                     && Objects.equal(mixinTypes, that.mixinTypes)
                     && Arrays.equals(properties, that.properties)
-                    && Objects.equal(nodeName, that.nodeName);
+                    && Objects.equal(childName, that.childName);
         } else {
             return false;
         }
@@ -127,7 +327,35 @@ class NodeTemplate {
 
     @Override
     public int hashCode() {
-        return Objects.hashCode(primaryType, mixinTypes, properties, nodeName);
+        return Objects.hashCode(
+                primaryType, mixinTypes, Arrays.asList(properties), childName);
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder builder = new StringBuilder();
+        builder.append("{ ");
+        if (primaryType != null) {
+            builder.append(primaryType);
+            builder.append(", ");
+        }
+        if (mixinTypes != null) {
+            builder.append(mixinTypes);
+            builder.append(", ");
+        }
+        for (int i = 0; i < properties.length; i++) {
+            builder.append(properties[i]);
+            builder.append(" = ?, ");
+        }
+        if (hasNoChildNodes()) {
+            builder.append("<no children>");
+        } else if (hasManyChildNodes()) {
+            builder.append("<many children>");
+        } else {
+            builder.append(childName + " = <node>");
+        }
+        builder.append(" }");
+        return builder.toString();
     }
 
 }

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/PropertyTemplate.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/PropertyTemplate.java?rev=1445999&r1=1445998&r2=1445999&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/PropertyTemplate.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/PropertyTemplate.java Thu Feb 14 00:42:36 2013
@@ -29,6 +29,11 @@ class PropertyTemplate implements Compar
 
     private final Type<?> type;
 
+    PropertyTemplate(String name, Type<?> type) {
+        this.name = checkNotNull(name);
+        this.type = checkNotNull(type);
+    }
+
     PropertyTemplate(PropertyState state) {
         checkNotNull(state);
         this.name = state.getName();

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentNodeState.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentNodeState.java?rev=1445999&r1=1445998&r2=1445999&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentNodeState.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentNodeState.java Thu Feb 14 00:42:36 2013
@@ -48,92 +48,59 @@ class SegmentNodeState extends AbstractN
 
     private final RecordId recordId;
 
-    private final MapRecord properties;
-
-    private final MapRecord childNodes;
+    private NodeTemplate template = null;
 
     SegmentNodeState(SegmentReader reader, RecordId id) {
         this.reader = checkNotNull(reader);
         this.recordId = checkNotNull(id);
-        this.properties = new MapRecord(reader.readRecordId(id, 0));
-        this.childNodes = new MapRecord(reader.readRecordId(id, 4));
+    }
+
+    private synchronized NodeTemplate getTemplate() {
+        if (template == null) {
+            template = reader.readTemplate(reader.readRecordId(recordId, 0));
+        }
+        return template;
     }
 
     @Override
     public long getPropertyCount() {
-        return properties.size(reader);
+        return getTemplate().getPropertyCount();
     }
 
     @Override @CheckForNull
     public PropertyState getProperty(String name) {
         checkNotNull(name);
-        RecordId propertyId = properties.getEntry(reader, name);
-        if (propertyId != null) {
-            return new SegmentPropertyState(reader, name, propertyId);
-        } else {
-            return null;
-        }
+        return getTemplate().getProperty(name, reader, recordId);
     }
 
     @Override @Nonnull
-    public Iterable<? extends PropertyState> getProperties() {
-        return Iterables.transform(
-                properties.getEntries(reader),
-                new Function<MapRecord.Entry, PropertyState>() {
-                    @Override @Nullable
-                    public PropertyState apply(@Nullable Entry input) {
-                        return new SegmentPropertyState(
-                                reader, input.getKey(), input.getValue());
-                    }
-                });
+    public Iterable<PropertyState> getProperties() {
+        return getTemplate().getProperties(reader, recordId);
     }
 
     @Override
     public long getChildNodeCount() {
-        return childNodes.size(reader);
+        return getTemplate().getChildNodeCount(reader, recordId);
     }
 
     @Override
     public boolean hasChildNode(String name) {
-        checkNotNull(name);
-        return childNodes.getEntry(reader, name) != null;
+        return getTemplate().hasChildNode(checkNotNull(name), reader, recordId);
     }
 
     @Override @CheckForNull
     public NodeState getChildNode(String name) {
-        checkNotNull(name);
-        RecordId childNodeId = childNodes.getEntry(reader, name);
-        if (childNodeId != null) {
-            return new SegmentNodeState(reader, childNodeId);
-        } else {
-            return null;
-        }
+        return getTemplate().getChildNode(checkNotNull(name), reader, recordId);
     }
 
     @Override
     public Iterable<String> getChildNodeNames() {
-        return Iterables.transform(
-                childNodes.getEntries(reader),
-                new Function<MapRecord.Entry, String>() {
-                    @Override @Nullable
-                    public String apply(@Nullable Entry input) {
-                        return input.getKey();
-                    }
-                });
+        return getTemplate().getChildNodeNames(reader, recordId);
     }
 
     @Override @Nonnull
     public Iterable<? extends ChildNodeEntry> getChildNodeEntries() {
-        return Iterables.transform(
-                childNodes.getEntries(reader),
-                new Function<MapRecord.Entry, ChildNodeEntry>() {
-                    @Override @Nullable
-                    public ChildNodeEntry apply(@Nullable Entry input) {
-                        return new MemoryChildNodeEntry(
-                                input.getKey(),
-                                new SegmentNodeState(reader, input.getValue()));
-                    }
-                });
+        return getTemplate().getChildNodeEntries(reader, recordId);
     }
 
     @Override @Nonnull

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentNodeStoreBranch.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentNodeStoreBranch.java?rev=1445999&r1=1445998&r2=1445999&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentNodeStoreBranch.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentNodeStoreBranch.java Thu Feb 14 00:42:36 2013
@@ -32,7 +32,6 @@ import javax.annotation.Nonnull;
 import org.apache.jackrabbit.oak.api.CommitFailedException;
 import org.apache.jackrabbit.oak.api.PropertyState;
 import org.apache.jackrabbit.oak.commons.PathUtils;
-import org.apache.jackrabbit.oak.plugins.commit.MergingNodeStateDiff;
 import org.apache.jackrabbit.oak.plugins.memory.MemoryNodeBuilder;
 import org.apache.jackrabbit.oak.spi.commit.CommitHook;
 import org.apache.jackrabbit.oak.spi.state.NodeBuilder;

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentPropertyState.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentPropertyState.java?rev=1445999&r1=1445998&r2=1445999&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentPropertyState.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentPropertyState.java Thu Feb 14 00:42:36 2013
@@ -17,59 +17,59 @@
 package org.apache.jackrabbit.oak.plugins.segment;
 
 import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkElementIndex;
 import static com.google.common.base.Preconditions.checkNotNull;
 
 import java.util.Iterator;
 import java.util.NoSuchElementException;
 
 import javax.annotation.Nonnull;
-import javax.jcr.PropertyType;
 
+import org.apache.jackrabbit.oak.api.AbstractPropertyState;
 import org.apache.jackrabbit.oak.api.Type;
-import org.apache.jackrabbit.oak.plugins.memory.EmptyPropertyState;
 import org.apache.jackrabbit.oak.plugins.value.Conversions;
 import org.apache.jackrabbit.oak.plugins.value.Conversions.Converter;
 
-class SegmentPropertyState extends EmptyPropertyState {
+class SegmentPropertyState extends AbstractPropertyState {
 
-    private final SegmentReader reader;
-
-    private final int tag;
-
-    private final int count;
+    private final PropertyTemplate template;
 
-    private final ListRecord values;
+    private final SegmentReader reader;
 
-    SegmentPropertyState(SegmentReader reader, String name, RecordId id) {
-        super(name);
+    private final RecordId recordId;
 
+    public SegmentPropertyState(
+            PropertyTemplate template,
+            SegmentReader reader, RecordId recordId) {
+        this.template = checkNotNull(template);
         this.reader = checkNotNull(reader);
+        this.recordId = checkNotNull(recordId);
+    }
 
-        checkNotNull(id);
-        this.tag = reader.readInt(id, 0);
-        this.count = reader.readInt(id, 4);
-        this.values = new ListRecord(reader.readRecordId(id, 8), count());
+    @Override @Nonnull
+    public String getName() {
+        return template.getName();
+    }
+
+    @Override
+    public Type<?> getType() {
+        return template.getType();
     }
 
     @Override
     public boolean isArray() {
-        return count != -1;
+        return getType().isArray();
     }
 
     @Override
     public int count() {
         if (isArray()) {
-            return count;
+            return reader.readInt(recordId, 0);
         } else {
             return 1;
         }
     }
 
-    @Override
-    public Type<?> getType() {
-        return Type.fromTag(tag, isArray());
-    }
-
     @Override @Nonnull @SuppressWarnings("unchecked")
     public <T> T getValue(Type<T> type) {
         if (type.isArray()) {
@@ -113,6 +113,19 @@ class SegmentPropertyState extends Empty
         checkNotNull(type);
         checkArgument(!type.isArray(), "Type must not be an array type");
 
+        Type<?> base;
+        ListRecord values;
+        if (isArray()) {
+            base = getType().getBaseType();
+            int size = reader.readInt(recordId, 0);
+            RecordId listId = reader.readRecordId(recordId, 4);
+            values = new ListRecord(listId, size);
+        } else {
+            base = getType();
+            values = new ListRecord(recordId, 1);
+        }
+        checkElementIndex(index, values.size());
+
         RecordId valueId = values.getEntry(reader, index);
         if (type == Type.BINARY) {
             return (T) new SegmentBlob(reader, valueId);
@@ -124,13 +137,13 @@ class SegmentPropertyState extends Empty
                 return (T) value;
             } else {
                 Converter converter = Conversions.convert(value);
-                if (tag == PropertyType.DATE) {
+                if (base == Type.DATE) {
                     converter = Conversions.convert(converter.toCalendar());
-                } else if (tag == PropertyType.DECIMAL) {
+                } else if (base == Type.DECIMAL) {
                     converter = Conversions.convert(converter.toDecimal());
-                } else if (tag == PropertyType.DOUBLE) {
+                } else if (base == Type.DOUBLE) {
                     converter = Conversions.convert(converter.toDouble());
-                } else if (tag == PropertyType.LONG) {
+                } else if (base == Type.LONG) {
                     converter = Conversions.convert(converter.toLong());
                 }
                 if (type == Type.BOOLEAN) {
@@ -153,8 +166,16 @@ class SegmentPropertyState extends Empty
 
     @Override
     public long size(int index) {
-        RecordId valueId = values.getEntry(reader, index);
-        return reader.readLong(valueId, 0);
+        ListRecord values;
+        if (isArray()) {
+            int size = reader.readInt(recordId, 0);
+            RecordId listId = reader.readRecordId(recordId, 4);
+            values = new ListRecord(listId, size);
+        } else {
+            values = new ListRecord(recordId, 1);
+        }
+        checkElementIndex(index, values.size());
+        return reader.readLength(values.getEntry(reader, 0));
     }
 
 }

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentReader.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentReader.java?rev=1445999&r1=1445998&r2=1445999&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentReader.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentReader.java Thu Feb 14 00:42:36 2013
@@ -21,54 +21,195 @@ import static com.google.common.base.Pre
 import static com.google.common.base.Preconditions.checkPositionIndexes;
 import static org.apache.jackrabbit.oak.plugins.segment.SegmentWriter.BLOCK_SIZE;
 
+import java.util.Arrays;
+import java.util.concurrent.ExecutionException;
+
+import org.apache.jackrabbit.oak.api.PropertyState;
+import org.apache.jackrabbit.oak.api.Type;
+import org.apache.jackrabbit.oak.plugins.memory.PropertyStates;
+
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
+import com.google.common.cache.Weigher;
+
 public class SegmentReader {
 
     private final SegmentStore store;
 
+    private final LoadingCache<RecordId, String> strings =
+            CacheBuilder.newBuilder()
+            .maximumWeight(1 << 20) // 1 MB
+            .weigher(newStringWeigher())
+            .build(newStringLoader());
+
+    private final LoadingCache<RecordId, NodeTemplate> templates =
+            CacheBuilder.newBuilder()
+            .maximumSize(1000)
+            .build(newTemplateLoader());
+
     public SegmentReader(SegmentStore store) {
         this.store = store;
     }
 
+    private static Weigher<RecordId, String> newStringWeigher() {
+        return new Weigher<RecordId, String>() {
+            @Override
+            public int weigh(RecordId key, String value) {
+                return 32 + value.length() * 2;
+            }
+        };
+    }
+
+    private CacheLoader<RecordId, String> newStringLoader() {
+        return new CacheLoader<RecordId, String>() {
+            @Override
+            public String load(RecordId key) throws Exception {
+                SegmentStream stream = readStream(key);
+                try {
+                    return stream.getString();
+                } finally {
+                    stream.close();
+                }
+            }
+        };
+    }
+
+    private CacheLoader<RecordId, NodeTemplate> newTemplateLoader() {
+        return new CacheLoader<RecordId, NodeTemplate>() {
+            @Override
+            public NodeTemplate load(RecordId key) throws Exception {
+                Segment segment = store.readSegment(key.getSegmentId());
+                int offset = key.getOffset();
+
+                int head = segment.readInt(offset);
+                boolean hasPrimaryType = (head & (1 << 31)) != 0;
+                boolean hasMixinTypes = (head & (1 << 30)) != 0;
+                boolean zeroChildNodes = (head & (1 << 29)) != 0;
+                boolean manyChildNodes = (head & (1 << 28)) != 0;
+                int mixinCount = (head >> 18) & ((1 << 10) - 1);
+                int propertyCount = head & ((1 << 18) - 1);
+                offset += 4;
+
+                PropertyState primaryType = null;
+                if (hasPrimaryType) {
+                    RecordId primaryId = segment.readRecordId(offset);
+                    primaryType = PropertyStates.createProperty(
+                            "jcr:primaryType", readString(primaryId), Type.NAME);
+                    offset += 4;
+                }
+
+                PropertyState mixinTypes = null;
+                if (hasMixinTypes) {
+                    String[] mixins = new String[mixinCount];
+                    for (int i = 0; i < mixins.length; i++) {
+                        RecordId mixinId = segment.readRecordId(offset);
+                        mixins[i] = readString(mixinId);
+                        offset += 4;
+                    }
+                    mixinTypes = PropertyStates.createProperty(
+                            "jcr:mixinTypes", Arrays.asList(mixins), Type.NAMES);
+                }
+
+                String childName = NodeTemplate.ZERO_CHILD_NODES;
+                if (manyChildNodes) {
+                    childName = NodeTemplate.MANY_CHILD_NODES;
+                } else if (!zeroChildNodes) {
+                    RecordId childNameId = segment.readRecordId(offset);
+                    childName = readString(childNameId);
+                    offset += 4;
+                }
+
+                PropertyTemplate[] properties =
+                        new PropertyTemplate[propertyCount];
+                for (int i = 0; i < properties.length; i++) {
+                    RecordId propertyNameId = segment.readRecordId(offset);
+                    byte type = segment.readByte(offset + 4);
+                    properties[i] = new PropertyTemplate(
+                            readString(propertyNameId),
+                            Type.fromTag(Math.abs(type), type < 0));
+                    offset += 5;
+                }
+
+                return new NodeTemplate(
+                        primaryType, mixinTypes, properties, childName);
+            }
+        };
+    }
+
+    public NodeTemplate readTemplate(RecordId recordId) {
+        try {
+            return templates.get(recordId);
+        } catch (ExecutionException e) {
+            throw new IllegalStateException(
+                    "Unable to access template record " + recordId, e);
+        }
+    }
+
     public String readString(RecordId recordId) {
-        SegmentStream stream = readStream(recordId);
         try {
-            return stream.getString();
-        } finally {
-            stream.close();
+            return strings.get(recordId);
+        } catch (ExecutionException e) {
+            throw new IllegalStateException(
+                    "Unable to access string record " + recordId, e);
         }
     }
 
-    public SegmentStream readStream(RecordId recordId) {
+    public long readLength(RecordId recordId) {
+        checkNotNull(recordId);
         Segment segment = store.readSegment(recordId.getSegmentId());
-        int offset = recordId.getOffset();
+        return readLength(segment, recordId.getOffset());
+    }
+
+    private long readLength(Segment segment, int offset) {
         int length = segment.readByte(offset++) & 0xff;
         if ((length & 0x80) == 0) {
-            byte[] data = new byte[length];
-            segment.readBytes(offset, data, 0, length);
-            return new SegmentStream(recordId, data);
+            return length;
         } else if ((length & 0x40) == 0) {
-            length = (length & 0x3f) << 8;
-            length |= segment.readByte(offset++) & 0xff;
-            length += 0x80;
-            byte[] data = new byte[length];
-            segment.readBytes(offset, data, 0, length);
-            return new SegmentStream(recordId, data);
+            return ((length & 0x3f) << 8
+                    | segment.readByte(offset) & 0xff)
+                    + 0x80;
         } else {
-            long l = ((long) length & 0x3f) << 56
+            return (((long) length & 0x3f) << 56
                     | ((long) (segment.readByte(offset++) & 0xff)) << 48
                     | ((long) (segment.readByte(offset++) & 0xff)) << 40
                     | ((long) (segment.readByte(offset++) & 0xff)) << 32
                     | ((long) (segment.readByte(offset++) & 0xff)) << 24
                     | ((long) (segment.readByte(offset++) & 0xff)) << 16
                     | ((long) (segment.readByte(offset++) & 0xff)) << 8
-                    | ((long) (segment.readByte(offset++) & 0xff));
-            int size = (int) ((l + BLOCK_SIZE - 1) / BLOCK_SIZE);
+                    | ((long) (segment.readByte(offset) & 0xff)))
+                    + 0x4080;
+        }
+    }
+
+    public SegmentStream readStream(RecordId recordId) {
+        Segment segment = store.readSegment(recordId.getSegmentId());
+        int offset = recordId.getOffset();
+        long length = readLength(segment, offset);
+        if (length < 0x4080) {
+            if (length < 0x80) {
+                offset += 1;
+            } else {
+                offset += 2;
+            }
+            byte[] data = new byte[(int) length];
+            segment.readBytes(offset, data, 0, data.length);
+            return new SegmentStream(recordId, data);
+        } else {
+            int size = (int) ((length + BLOCK_SIZE - 1) / BLOCK_SIZE);
             ListRecord list =
-                    new ListRecord(segment.readRecordId(offset), size);
-            return new SegmentStream(this, recordId, list, l);
+                    new ListRecord(segment.readRecordId(offset + 8), size);
+            return new SegmentStream(this, recordId, list, length);
         }
     }
 
+    public byte readByte(RecordId recordId, int position) {
+        checkNotNull(recordId);
+        checkArgument(position >= 0);
+        Segment segment = store.readSegment(recordId.getSegmentId());
+        return segment.readByte(recordId.getOffset() + position);
+    }
+
     public int readInt(RecordId recordId, int position) {
         checkNotNull(recordId);
         checkArgument(position >= 0);

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentWriter.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentWriter.java?rev=1445999&r1=1445998&r2=1445999&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentWriter.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentWriter.java Thu Feb 14 00:42:36 2013
@@ -18,12 +18,14 @@ package org.apache.jackrabbit.oak.plugin
 
 import static com.google.common.base.Preconditions.checkNotNull;
 import static com.google.common.base.Preconditions.checkPositionIndexes;
+import static com.google.common.base.Preconditions.checkState;
 
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.nio.ByteBuffer;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashSet;
@@ -34,13 +36,13 @@ import java.util.UUID;
 
 import javax.jcr.PropertyType;
 
+import org.apache.jackrabbit.oak.api.Blob;
 import org.apache.jackrabbit.oak.api.PropertyState;
 import org.apache.jackrabbit.oak.api.Type;
 import org.apache.jackrabbit.oak.spi.state.ChildNodeEntry;
 import org.apache.jackrabbit.oak.spi.state.NodeState;
 
 import com.google.common.base.Charsets;
-import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
 import com.google.common.io.ByteStreams;
@@ -63,6 +65,8 @@ public class SegmentWriter {
 
     private final Map<String, RecordId> strings = Maps.newHashMap();
 
+    private final Map<NodeTemplate, RecordId> templates = Maps.newHashMap();
+
     private UUID uuid = UUID.randomUUID();
 
     private List<UUID> uuids = new ArrayList<UUID>(255);
@@ -255,7 +259,7 @@ public class SegmentWriter {
     private synchronized RecordId writeValueRecord(
             long length, RecordId blocks) {
         RecordId valueId = prepare(8, Collections.singleton(blocks));
-        buffer.putLong(length | (0x3L << 62));
+        buffer.putLong((length - 0x4080) | (0x3L << 62));
         writeRecordId(blocks);
         return valueId;
     }
@@ -403,8 +407,8 @@ public class SegmentWriter {
         for (int i = 0; i < count; i++) {
             if (type.tag() == PropertyType.BINARY) {
                 try {
-                    valueIds.add(writeStream(
-                            state.getValue(Type.BINARY, i).getNewStream()));
+                    Blob blob = state.getValue(Type.BINARY, i);
+                    valueIds.add(writeStream(blob.getNewStream()));
                 } catch (IOException e) {
                     throw new IllegalStateException("Unexpected IOException", e);
                 }
@@ -414,15 +418,89 @@ public class SegmentWriter {
         }
         RecordId valueId = writeList(valueIds);
 
-        RecordId propertyId = prepare(8, Collections.singleton(valueId));
-        buffer.putInt(type.tag());
-        if (state.isArray()) {
+        if (type.isArray()) {
+            RecordId propertyId = prepare(4, Collections.singleton(valueId));
             buffer.putInt(count);
+            writeRecordId(valueId);
+            return propertyId;
         } else {
-            buffer.putInt(-1);
+            return valueId;
+        }
+    }
+
+    public synchronized RecordId writeTemplate(NodeTemplate template) {
+        checkNotNull(template);
+        RecordId id = templates.get(template);
+        if (id == null) {
+            Collection<RecordId> ids = Lists.newArrayList();
+            int head = 0;
+
+            RecordId primaryId = null;
+            if (template.hasPrimaryType()) {
+                head |= 1 << 31;
+                primaryId = writeString(template.getPrimaryType());
+                ids.add(primaryId);
+            }
+
+            List<RecordId> mixinIds = null;
+            if (template.hasMixinTypes()) {
+                head |= 1 << 30;
+                mixinIds = Lists.newArrayList();
+                for (String mixin : template.getMixinTypes()) {
+                    mixinIds.add(writeString(mixin));
+                }
+                ids.addAll(mixinIds);
+                checkState(mixinIds.size() < (1 << 10));
+                head |= mixinIds.size() << 18;
+            }
+
+            RecordId childNameId = null;
+            if (template.hasNoChildNodes()) {
+                head |= 1 << 29;
+            } else if (template.hasManyChildNodes()) {
+                head |= 1 << 28;
+            } else {
+                childNameId = writeString(template.getChildName());
+                ids.add(childNameId);
+            }
+
+            PropertyTemplate[] properties = template.getPropertyTemplates();
+            RecordId[] propertyNames = new RecordId[properties.length];
+            byte[] propertyTypes = new byte[properties.length];
+            for (int i = 0; i < properties.length; i++) {
+                propertyNames[i] = writeString(properties[i].getName());
+                Type<?> type = properties[i].getType();
+                if (type.isArray()) {
+                    propertyTypes[i] = (byte) -type.tag();
+                } else {
+                    propertyTypes[i] = (byte) type.tag();
+                }
+            }
+            ids.addAll(Arrays.asList(propertyNames));
+            checkState(propertyNames.length < (1 << 18));
+            head |= propertyNames.length;
+
+            id = prepare(4 + propertyTypes.length, ids);
+            buffer.putInt(head);
+            if (primaryId != null) {
+                writeRecordId(primaryId);
+            }
+            if (mixinIds != null) {
+                for (RecordId mixinId : mixinIds) {
+                    writeRecordId(mixinId);
+                }
+            }
+            if (childNameId != null) {
+                writeRecordId(childNameId);
+            }
+            for (int i = 0; i < propertyNames.length; i++) {
+                writeRecordId(propertyNames[i]);
+                buffer.put(propertyTypes[i]);
+            }
+
+            templates.put(template, id);
         }
-        writeRecordId(valueId);
-        return propertyId;
+        return id;
     }
 
     public RecordId writeNode(NodeState state) {
@@ -431,22 +509,30 @@ public class SegmentWriter {
             return nodeId;
         }
 
-        Map<String, RecordId> childNodes = Maps.newHashMap();
-        for (ChildNodeEntry entry : state.getChildNodeEntries()) {
-            childNodes.put(entry.getName(), writeNode(entry.getNodeState()));
+        NodeTemplate template = new NodeTemplate(state);
+
+        List<RecordId> ids = Lists.newArrayList();
+        ids.add(writeTemplate(template));
+
+        if (template.hasManyChildNodes()) {
+            Map<String, RecordId> childNodes = Maps.newHashMap();
+            for (ChildNodeEntry entry : state.getChildNodeEntries()) {
+                childNodes.put(entry.getName(), writeNode(entry.getNodeState()));
+            }
+            ids.add(writeMap(childNodes));
+        } else if (!template.hasNoChildNodes()) {
+            ids.add(writeNode(state.getChildNode(template.getChildName())));
         }
-        RecordId childNodesId = writeMap(childNodes);
 
-        Map<String, RecordId> properties = Maps.newHashMap();
-        for (PropertyState property : state.getProperties()) {
-            properties.put(property.getName(), writeProperty(property));
+        for (PropertyTemplate property : template.getPropertyTemplates()) {
+            ids.add(writeProperty(state.getProperty(property.getName())));
         }
-        RecordId propertiesId = writeMap(properties);
 
-        RecordId id = prepare(0, ImmutableList.of(propertiesId, childNodesId));
-        writeRecordId(propertiesId);
-        writeRecordId(childNodesId);
-        return id;
+        RecordId recordId = prepare(0, ids);
+        for (RecordId id : ids) {
+            writeRecordId(id);
+        }
+        return recordId;
     }
 
 }

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeBits.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeBits.java?rev=1445999&r1=1445998&r2=1445999&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeBits.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeBits.java Thu Feb 14 00:42:36 2013
@@ -138,11 +138,15 @@ public final class PrivilegeBits impleme
             return EMPTY;
         }
 
-        List<Long> vs = (List<Long>) property.getValue(Type.LONGS);
-        if (vs.size() == 1) {
-            return getInstance(vs.get(0));
-        } else {
-            return getInstance(Longs.toArray(vs));
+        int size = property.count();
+        if (size == 1) {
+            return getInstance(property.getValue(Type.LONG, 0));
+        } else {
+            long[] longs = new long[size];
+            for (int i = 0; i < longs.length; i++) {
+                longs[i] = property.getValue(Type.LONG, i);
+            }
+            return getInstance(longs);
         }
     }
 

Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/segment/SegmentSizeTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/segment/SegmentSizeTest.java?rev=1445999&r1=1445998&r2=1445999&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/segment/SegmentSizeTest.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/segment/SegmentSizeTest.java Thu Feb 14 00:42:36 2013
@@ -25,6 +25,7 @@ import org.apache.jackrabbit.oak.api.Typ
 import org.apache.jackrabbit.oak.plugins.memory.MemoryNodeState;
 import org.apache.jackrabbit.oak.plugins.memory.PropertyStates;
 import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
 import org.apache.jackrabbit.util.ISO8601;
 import org.junit.Test;
 
@@ -40,25 +41,30 @@ public class SegmentSizeTest {
     @Test
     public void testNodeSize() {
         NodeBuilder builder = MemoryNodeState.EMPTY_NODE.builder();
-        assertEquals(16, getSize(builder.getNodeState().builder()));
+        assertEquals(8, getSize(builder));
+        assertEquals(4, getAmortizedSize(builder));
 
         builder = MemoryNodeState.EMPTY_NODE.builder();
         builder.setProperty("foo", "bar");
-        assertEquals(48, getSize(builder));
+        assertEquals(25, getSize(builder));
+        assertEquals(8, getAmortizedSize(builder));
 
         builder = MemoryNodeState.EMPTY_NODE.builder();
         builder.setProperty("foo", "bar");
         builder.setProperty("baz", 123);
-        assertEquals(80, getSize(builder));
+        assertEquals(42, getSize(builder));
+        assertEquals(12, getAmortizedSize(builder));
 
         builder = MemoryNodeState.EMPTY_NODE.builder();
         builder.child("foo");
-        assertEquals(48, getSize(builder));
+        assertEquals(28, getSize(builder));
+        assertEquals(12, getAmortizedSize(builder));
 
         builder = MemoryNodeState.EMPTY_NODE.builder();
         builder.child("foo");
         builder.child("bar");
-        assertEquals(80, getSize(builder));
+        assertEquals(60, getSize(builder));
+        assertEquals(44, getAmortizedSize(builder));
     }
 
     @Test
@@ -101,21 +107,24 @@ public class SegmentSizeTest {
     public void testAccessControlNodes() {
         NodeBuilder builder = MemoryNodeState.EMPTY_NODE.builder();
         builder.setProperty("jcr:primaryType", "rep:ACL", Type.NAME);
-        assertEquals(64, getSize(builder));
+        assertEquals(20, getSize(builder));
+        assertEquals(4, getAmortizedSize(builder));
 
         NodeBuilder deny = builder.child("deny");
         deny.setProperty("jcr:primaryType", "rep:DenyACE", Type.NAME);
         deny.setProperty("rep:principalName", "everyone");
         builder.setProperty(PropertyStates.createProperty(
                 "rep:privileges", ImmutableList.of("jcr:read"), Type.NAMES));
-        assertEquals(232, getSize(builder));
+        assertEquals(134, getSize(builder));
+        assertEquals(28, getAmortizedSize(builder));
 
         NodeBuilder allow = builder.child("allow");
         allow.setProperty("jcr:primaryType", "rep:GrantACE");
         allow.setProperty("rep:principalName", "administrators");
         allow.setProperty(PropertyStates.createProperty(
                 "rep:privileges", ImmutableList.of("jcr:all"), Type.NAMES));
-        assertEquals(374, getSize(builder));
+        assertEquals(259, getSize(builder));
+        assertEquals(80, getAmortizedSize(builder));
 
         NodeBuilder deny0 = builder.child("deny0");
         deny0.setProperty("jcr:primaryType", "rep:DenyACE", Type.NAME);
@@ -123,14 +132,16 @@ public class SegmentSizeTest {
         deny0.setProperty("rep:glob", "*/activities/*");
         builder.setProperty(PropertyStates.createProperty(
                 "rep:privileges", ImmutableList.of("jcr:read"), Type.NAMES));
-        assertEquals(504, getSize(builder));
+        assertEquals(331, getSize(builder));
+        assertEquals(104, getAmortizedSize(builder));
 
         NodeBuilder allow0 = builder.child("allow0");
         allow0.setProperty("jcr:primaryType", "rep:GrantACE");
         allow0.setProperty("rep:principalName", "user-administrators");
         allow0.setProperty(PropertyStates.createProperty(
                 "rep:privileges", ImmutableList.of("jcr:all"), Type.NAMES));
-        assertEquals(631, getSize(builder));
+        assertEquals(394, getSize(builder));
+        assertEquals(140, getAmortizedSize(builder));
     }
 
     private int getSize(NodeBuilder builder) {
@@ -142,4 +153,16 @@ public class SegmentSizeTest {
         return segment.getData().length;
     }
 
+    private int getAmortizedSize(NodeBuilder builder) {
+        SegmentStore store = new MemoryStore();
+        SegmentWriter writer = new SegmentWriter(store);
+        NodeState state = builder.getNodeState();
+        writer.writeNode(state);
+        writer.flush();
+        RecordId id = writer.writeNode(state);
+        writer.flush();
+        Segment segment = store.readSegment(id.getSegmentId());
+        return segment.getData().length;
+    }
+
 }



Mime
View raw message