You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by ju...@apache.org on 2010/10/15 16:30:22 UTC

svn commit: r1022942 - in /jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/util: BundleBinding.java BundleReader.java BundleWriter.java

Author: jukka
Date: Fri Oct 15 14:30:22 2010
New Revision: 1022942

URL: http://svn.apache.org/viewvc?rev=1022942&view=rev
Log:
JCR-2762: Optimize bundle serialization

Use a bit field to optimize for common mixin type, property, child node, and shared set counts.

Modified:
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/util/BundleBinding.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/util/BundleReader.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/util/BundleWriter.java

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/util/BundleBinding.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/util/BundleBinding.java?rev=1022942&r1=1022941&r2=1022942&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/util/BundleBinding.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/util/BundleBinding.java Fri Oct 15 14:30:22 2010
@@ -34,12 +34,12 @@ public class BundleBinding {
     static final int BINARY_IN_DATA_STORE = -2;
 
     /**
-     * A special UUID used to mark a <code>null</code> {@link NodeId} value.
-     * This is a proper type 1 UUID to prevent collisions with other
-     * identifiers, even special non-random ones like
+     * A special UUID used to mark the <code>null</code> parent identifier
+     * of the root node. This is a proper type 1 UUID to prevent collisions
+     * with other identifiers, even special non-random ones like
      * <code>00000000-0000-0000-0000-000000000000</code>.
      */
-    static final NodeId NULL_NODE_ID =
+    static final NodeId NULL_PARENT_ID =
         new NodeId("bb4e9d10-d857-11df-937b-0800200c9a66");
 
     /**

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/util/BundleReader.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/util/BundleReader.java?rev=1022942&r1=1022941&r2=1022942&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/util/BundleReader.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/util/BundleReader.java Fri Oct 15 14:30:22 2010
@@ -16,8 +16,6 @@
  */
 package org.apache.jackrabbit.core.persistence.util;
 
-import static org.apache.jackrabbit.core.persistence.util.BundleBinding.NULL_NODE_ID;
-
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.apache.jackrabbit.core.id.NodeId;
@@ -127,152 +125,149 @@ class BundleReader {
      */
     public NodePropBundle readBundle(NodeId id) throws IOException {
         NodePropBundle bundle = new NodePropBundle(id);
-
-        // read primary type...special handling
-        Name nodeTypeName;
         if (version >= BundleBinding.VERSION_3) {
-            nodeTypeName = readName();
+            readBundleNew(bundle);
         } else {
-            int a = in.readUnsignedByte();
-            int b = in.readUnsignedByte();
-            int c = in.readUnsignedByte();
-            String uri = binding.nsIndex.indexToString(a << 16 | b << 8 | c);
-            String local = binding.nameIndex.indexToString(in.readInt());
-            nodeTypeName = NameFactoryImpl.getInstance().create(uri, local);
+            readBundleOld(bundle);
         }
-        bundle.setNodeTypeName(nodeTypeName);
+        return bundle;
+    }
 
-        // parentUUID
-        bundle.setParentId(readNodeId());
+    private void readBundleNew(NodePropBundle bundle) throws IOException {
+        // node type
+        bundle.setNodeTypeName(readName());
 
-        if (version < BundleBinding.VERSION_3) {
-            // definitionId
-            in.readUTF();
+        // parentUUID
+        NodeId parentId = readNodeId();
+        if (BundleBinding.NULL_PARENT_ID.equals(parentId)) {
+            parentId = null;
         }
+        bundle.setParentId(parentId);
 
-        // mixin types
-        readMixinTypes(bundle);
-
-        // properties
-        readProperties(bundle);
-
-        // set referenceable flag
-        bundle.setReferenceable(in.readBoolean());
+        // read modcount
+        bundle.setModCount((short) readVarInt());
 
-        // child nodes (list of uuid/name pairs)
-        readChildNodeEntries(bundle);
+        int b = in.readUnsignedByte();
+        bundle.setReferenceable((b & 1) != 0);
 
-        // read modcount, since version 1.0
-        if (version >= BundleBinding.VERSION_3) {
-            bundle.setModCount((short) readVarInt());
-        } else if (version >= BundleBinding.VERSION_1) {
-            bundle.setModCount(in.readShort());
+        // mixin types
+        int mn = readVarInt((b >> 7) & 1, 1);
+        if (mn == 0) {
+            bundle.setMixinTypeNames(Collections.<Name>emptySet());
+        } else if (mn == 1) {
+            bundle.setMixinTypeNames(Collections.singleton(readName()));
+        } else {
+            Set<Name> mixins = new HashSet<Name>(mn * 2);
+            for (int i = 0; i < mn; i++) {
+                mixins.add(readName());
+            }
+            bundle.setMixinTypeNames(mixins);
         }
 
-        // read shared set, since version 2.0
-        readSharedSet(bundle);
+        // properties
+        int pn = readVarInt((b >> 4) & 7, 7);
+        for (int i = 0; i < pn; i++) {
+            PropertyId id = new PropertyId(bundle.getId(), readName());
+            bundle.addProperty(readPropertyEntry(id));
+        }
 
-        return bundle;
-    }
+        // child nodes (list of name/uuid pairs)
+        int nn = readVarInt((b >> 2) & 3, 3);
+        for (int i = 0; i < nn; i++) {
+            Name name = readQName();
+            NodeId id = readNodeId();
+            bundle.addChildNodeEntry(name, id);
+        }
 
-    private void readMixinTypes(NodePropBundle bundle) throws IOException {
-        if (version >= BundleBinding.VERSION_3) {
-            int n = readVarInt();
-            if (n == 0) {
-                bundle.setMixinTypeNames(Collections.<Name>emptySet());
-            } else if (n == 1) {
-                bundle.setMixinTypeNames(Collections.singleton(readName()));
-            } else {
-                Set<Name> mixins = new HashSet<Name>(n * 2);
-                for (int i = 0; i < n; i++) {
-                    mixins.add(readName());
-                }
-                bundle.setMixinTypeNames(mixins);
-            }
+        // read shared set
+        int sn = readVarInt((b >> 1) & 1, 1);
+        if (sn == 0) {
+            bundle.setSharedSet(Collections.<NodeId>emptySet());
+        } else if (sn == 1) {
+            bundle.setSharedSet(Collections.singleton(readNodeId()));
         } else {
-            Name name = readIndexedQName();
-            if (name == null) {
-                bundle.setMixinTypeNames(Collections.<Name>emptySet());
-            } else {
-                Set<Name> mixinTypeNames = new HashSet<Name>();
-                do {
-                    mixinTypeNames.add(name);
-                    name = readIndexedQName();
-                } while (name != null);
-                bundle.setMixinTypeNames(mixinTypeNames);
+            Set<NodeId> shared = new HashSet<NodeId>();
+            for (int i = 0; i < sn; i++) {
+                shared.add(readNodeId());
             }
+            bundle.setSharedSet(shared);
         }
     }
 
-    private void readProperties(NodePropBundle bundle) throws IOException {
-        if (version >= BundleBinding.VERSION_3) {
-            int n = readVarInt();
-            for (int i = 0; i < n; i++) {
-                PropertyId id = new PropertyId(bundle.getId(), readName());
-                bundle.addProperty(readPropertyEntry(id));
-            }
-        } else {
-            Name name = readIndexedQName();
-            while (name != null) {
-                PropertyId pId = new PropertyId(bundle.getId(), name);
-                NodePropBundle.PropertyEntry pState = readPropertyEntry(pId);
-                // skip redundant primaryType, mixinTypes and uuid properties
-                if (!name.equals(NameConstants.JCR_PRIMARYTYPE)
-                        && !name.equals(NameConstants.JCR_MIXINTYPES)
-                        && !name.equals(NameConstants.JCR_UUID)) {
-                    bundle.addProperty(pState);
-                }
+    private void readBundleOld(NodePropBundle bundle) throws IOException {
+        // read primary type...special handling
+        int a = in.readUnsignedByte();
+        int b = in.readUnsignedByte();
+        int c = in.readUnsignedByte();
+        String uri = binding.nsIndex.indexToString(a << 16 | b << 8 | c);
+        String local = binding.nameIndex.indexToString(in.readInt());
+        bundle.setNodeTypeName(
+                NameFactoryImpl.getInstance().create(uri, local));
+
+        // parentUUID
+        bundle.setParentId(readNodeId());
+
+        // definitionId
+        in.readUTF();
+
+        // mixin types
+        Name name = readIndexedQName();
+        if (name != null) {
+            Set<Name> mixinTypeNames = new HashSet<Name>();
+            do {
+                mixinTypeNames.add(name);
                 name = readIndexedQName();
-            }
+            } while (name != null);
+            bundle.setMixinTypeNames(mixinTypeNames);
+        } else {
+            bundle.setMixinTypeNames(Collections.<Name>emptySet());
         }
-    }
 
-    private void readSharedSet(NodePropBundle bundle) throws IOException {
-        Set<NodeId> sharedSet;
-        if (version >= BundleBinding.VERSION_3) {
-            int n = readVarInt();
-            if (n == 0) {
-                sharedSet = Collections.emptySet();
-            } else if (n == 1) {
-                sharedSet = Collections.singleton(readNodeId());
-            } else {
-                sharedSet = new HashSet<NodeId>();
-                for (int i = 0; i < n; i++) {
-                    sharedSet.add(readNodeId());
-                }
+        // properties
+        name = readIndexedQName();
+        while (name != null) {
+            PropertyId pId = new PropertyId(bundle.getId(), name);
+            NodePropBundle.PropertyEntry pState = readPropertyEntry(pId);
+            // skip redundant primaryType, mixinTypes and uuid properties
+            if (!name.equals(NameConstants.JCR_PRIMARYTYPE)
+                    && !name.equals(NameConstants.JCR_MIXINTYPES)
+                    && !name.equals(NameConstants.JCR_UUID)) {
+                bundle.addProperty(pState);
             }
-        } else if (version == BundleBinding.VERSION_2) {
+            name = readIndexedQName();
+        }
+
+        // set referenceable flag
+        bundle.setReferenceable(in.readBoolean());
+
+        // child nodes (list of uuid/name pairs)
+        NodeId childId = readNodeId();
+        while (childId != null) {
+            bundle.addChildNodeEntry(readQName(), childId);
+            childId = readNodeId();
+        }
+
+        // read modcount, since version 1.0
+        if (version >= BundleBinding.VERSION_1) {
+            bundle.setModCount(in.readShort());
+        }
+
+        // read shared set, since version 2.0
+        if (version >= BundleBinding.VERSION_2) {
             // shared set (list of parent uuids)
             NodeId parentId = readNodeId();
             if (parentId != null) {
-                sharedSet = new HashSet<NodeId>();
+                Set<NodeId> shared = new HashSet<NodeId>();
                 do {
-                    sharedSet.add(parentId);
+                    shared.add(parentId);
                     parentId = readNodeId();
                 } while (parentId != null);
+                bundle.setSharedSet(shared);
             } else {
-                sharedSet = Collections.emptySet();
-            }
-        } else {
-            sharedSet = Collections.emptySet();
-        }
-        bundle.setSharedSet(sharedSet);
-    }
-
-    private void readChildNodeEntries(NodePropBundle bundle) throws IOException {
-        if (version >= BundleBinding.VERSION_3) {
-            int n = readVarInt();
-            for (int i = 0; i < n; i++) {
-                NodeId id = readNodeId();
-                Name name = readQName();
-                bundle.addChildNodeEntry(name, id);
+                bundle.setSharedSet(Collections.<NodeId>emptySet());
             }
         } else {
-            NodeId childId = readNodeId();
-            while (childId != null) {
-                bundle.addChildNodeEntry(readQName(), childId);
-                childId = readNodeId();
-            }
+            bundle.setSharedSet(Collections.<NodeId>emptySet());
         }
     }
 
@@ -419,12 +414,7 @@ class BundleReader {
         if (version >= BundleBinding.VERSION_3 || in.readBoolean()) {
             long msb = in.readLong();
             long lsb = in.readLong();
-            if (msb != NULL_NODE_ID.getMostSignificantBits()
-                    || lsb != NULL_NODE_ID.getLeastSignificantBits()) {
-                return new NodeId(msb, lsb);
-            } else {
-                return null;
-            }
+            return new NodeId(msb, lsb);
         } else {
             return null;
         }
@@ -526,6 +516,14 @@ class BundleReader {
         }
     }
 
+    private int readVarInt(int value, int base) throws IOException {
+        if (value < base) {
+            return value;
+        } else {
+            return readVarInt() + base;
+        }
+    }
+
     /**
      * Deserializes a variable-length long written using bundle
      * serialization version 3.
@@ -639,10 +637,7 @@ class BundleReader {
     }
 
     private byte[] readBytes(int len, int base) throws IOException {
-        if (len == base) {
-            len += readVarInt();
-        }
-        byte[] bytes = new byte[len];
+        byte[] bytes = new byte[readVarInt(len, base)];
         in.readFully(bytes);
         return bytes;
     }

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/util/BundleWriter.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/util/BundleWriter.java?rev=1022942&r1=1022941&r2=1022942&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/util/BundleWriter.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/util/BundleWriter.java Fri Oct 15 14:30:22 2010
@@ -25,8 +25,6 @@ import java.math.BigDecimal;
 import java.util.Calendar;
 import java.util.Collection;
 import java.util.GregorianCalendar;
-import java.util.List;
-import java.util.Set;
 
 import javax.jcr.PropertyType;
 import javax.jcr.RepositoryException;
@@ -93,62 +91,62 @@ class BundleWriter {
         writeName(bundle.getNodeTypeName());
 
         // parentUUID
-        writeNodeId(bundle.getParentId());
-
-        // mixin types
-        writeMixinTypes(bundle);
-
-        // properties
-        writeProperties(bundle);
-
-        // write uuid flag
-        out.writeBoolean(bundle.isReferenceable());
-
-        // child nodes (list of uuid/name pairs)
-        writeChildNodeEntries(bundle);
+        NodeId parentId = bundle.getParentId();
+        if (parentId == null) {
+            parentId = BundleBinding.NULL_PARENT_ID;
+        }
+        writeNodeId(parentId);
 
         // write mod count
         writeVarInt(bundle.getModCount());
 
-        // write shared set
-        writeSharedSet(bundle);
+        Collection<Name> mixins = bundle.getMixinTypeNames();
+        Collection<PropertyEntry> properties = bundle.getPropertyEntries();
+        Collection<ChildNodeEntry> nodes = bundle.getChildNodeEntries();
+        Collection<NodeId> shared = bundle.getSharedSet();
 
-        // set size of bundle
-        bundle.setSize(out.size() - size);
-    }
+        int mn = mixins.size();
+        int pn = properties.size();
+        int nn = nodes.size();
+        int sn = shared.size();
+        int referenceable = 0;
+        if (bundle.isReferenceable()) {
+            referenceable = 1;
+        }
+        out.writeByte(
+                Math.min(mn, 1) << 7
+                | Math.min(pn, 7) << 4
+                | Math.min(nn, 3) << 2
+                | Math.min(sn, 1) << 1
+                | referenceable);
 
-    private void writeMixinTypes(NodePropBundle bundle) throws IOException {
-        Set<Name> mixins = bundle.getMixinTypeNames();
-        writeVarInt(mixins.size());
+        // mixin types
+        writeVarInt(mn, 1);
         for (Name name : mixins) {
             writeName(name);
         }
-    }
 
-    private void writeProperties(NodePropBundle bundle) throws IOException {
-        Collection<PropertyEntry> properties = bundle.getPropertyEntries();
-        writeVarInt(properties.size());
+        // properties
+        writeVarInt(pn, 7);
         for (PropertyEntry property : properties) {
             writeState(property);
         }
-    }
 
-    private void writeChildNodeEntries(NodePropBundle bundle)
-            throws IOException {
-        List<ChildNodeEntry> chilren = bundle.getChildNodeEntries();
-        writeVarInt(chilren.size());
-        for (ChildNodeEntry child : chilren) {
-            writeNodeId(child.getId());   // uuid
+        // child nodes (list of name/uuid pairs)
+        writeVarInt(nn, 3);
+        for (ChildNodeEntry child : nodes) {
             writeName(child.getName());   // name
+            writeNodeId(child.getId());   // uuid
         }
-    }
 
-    private void writeSharedSet(NodePropBundle bundle) throws IOException {
-        Set<NodeId> sharedSet = bundle.getSharedSet();
-        writeVarInt(sharedSet.size());
-        for (NodeId nodeId: sharedSet) {
+        // write shared set
+        writeVarInt(sn, 1);
+        for (NodeId nodeId: shared) {
             writeNodeId(nodeId);
         }
+
+        // set size of bundle
+        bundle.setSize(out.size() - size);
     }
 
     /**
@@ -381,9 +379,6 @@ class BundleWriter {
      * @throws IOException in an I/O error occurs.
      */
     private void writeNodeId(NodeId id) throws IOException {
-        if (id == null) {
-            id = BundleBinding.NULL_NODE_ID;
-        }
         out.writeLong(id.getMostSignificantBits());
         out.writeLong(id.getLeastSignificantBits());
     }
@@ -517,6 +512,12 @@ class BundleWriter {
         }
     }
 
+    private void writeVarInt(int value, int base) throws IOException {
+        if (value >= base) {
+            writeVarInt(value - base);
+        }
+    }
+
     /**
      * Serializes a long value using a variable length encoding like the
      * one used by {@link #writeVarInt(int)} for integer values. Before