You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by th...@apache.org on 2011/09/07 10:54:47 UTC

svn commit: r1166067 - in /jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk: index/ mem/ util/

Author: thomasm
Date: Wed Sep  7 08:54:47 2011
New Revision: 1166067

URL: http://svn.apache.org/viewvc?rev=1166067&view=rev
Log:
Trying to support large child node lists (WIP) and other changes (exception handling).

Modified:
    jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/index/Indexer.java
    jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/mem/MemoryKernelImpl.java
    jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/mem/NodeImpl.java
    jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/mem/NodeList.java
    jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/mem/NodeListLarge.java
    jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/mem/NodeListSmall.java
    jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/mem/NodeMap.java
    jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/mem/Revision.java
    jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/util/IOUtils.java

Modified: jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/index/Indexer.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/index/Indexer.java?rev=1166067&r1=1166066&r2=1166067&view=diff
==============================================================================
--- jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/index/Indexer.java (original)
+++ jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/index/Indexer.java Wed Sep  7 08:54:47 2011
@@ -328,7 +328,7 @@ public class Indexer {
                 index.addOrRemoveNode(n, true);
             }
         }
-        for (Iterator<String> it = n.getChildNodeNames(); it.hasNext();) {
+        for (Iterator<String> it = n.getChildNodeNames(Integer.MAX_VALUE); it.hasNext();) {
             addOrRemoveRecursive(n.getNode(it.next()), remove, add);
         }
     }

Modified: jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/mem/MemoryKernelImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/mem/MemoryKernelImpl.java?rev=1166067&r1=1166066&r2=1166067&view=diff
==============================================================================
--- jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/mem/MemoryKernelImpl.java (original)
+++ jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/mem/MemoryKernelImpl.java Wed Sep  7 08:54:47 2011
@@ -17,13 +17,13 @@
 package org.apache.jackrabbit.mk.mem;
 
 import org.apache.jackrabbit.mk.api.MicroKernel;
-import org.apache.jackrabbit.mk.api.MicroKernelException;
 import org.apache.jackrabbit.mk.blobs.AbstractBlobStore;
 import org.apache.jackrabbit.mk.blobs.FileBlobStore;
 import org.apache.jackrabbit.mk.blobs.MemoryBlobStore;
 import org.apache.jackrabbit.mk.json.JsopBuilder;
 import org.apache.jackrabbit.mk.json.JsopTokenizer;
 import org.apache.jackrabbit.mk.util.CommitGate;
+import org.apache.jackrabbit.mk.util.ExceptionFactory;
 import org.apache.jackrabbit.mk.util.NonDescendingClock;
 import org.apache.jackrabbit.mk.util.PathUtils;
 import org.apache.jackrabbit.mk.util.SmallLRUCache;
@@ -33,6 +33,7 @@ import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Iterator;
+import java.util.Map.Entry;
 
 /*
 
@@ -71,6 +72,9 @@ public class MemoryKernelImpl implements
     private String lastJournalRevRange, lastJournal;
 
     private MemoryKernelImpl(String name) {
+        if (DEBUG) {
+            log("open " + name);
+        }
         nodeMap = new NodeMap();
         if (name.startsWith("fs:")) {
             String dir = name.substring("fs:".length());
@@ -81,8 +85,10 @@ public class MemoryKernelImpl implements
         if (nodeMap.getRootId() == 0) {
             clear();
         } else {
-            String rev = getRoot().getNode("head").getProperty("rev");
+            NodeImpl head = getRoot().getNode("head");
+            String rev = head.getProperty("rev");
             headRevId = Revision.parseId(JsopTokenizer.decodeQuoted(rev));
+            applyConfig(head);
         }
     }
 
@@ -96,6 +102,9 @@ public class MemoryKernelImpl implements
     }
 
     public void clear() {
+        if (DEBUG) {
+            log("clear");
+        }
         headRevId = 0;
         ds.clear();
         nodeMap.clear();
@@ -103,112 +112,124 @@ public class MemoryKernelImpl implements
         Revision revNode = new Revision(0, 0, "", "");
         head = revNode.store(head, new NodeImpl(nodeMap, 0));
         head.addChildNode("data", new NodeImpl(nodeMap, 0));
+        head.addChildNode("config", new NodeImpl(nodeMap, 0));
         NodeImpl root = new NodeImpl(nodeMap, 0);
         root.addChildNode("head", head);
         root.addChildNode("old", new NodeImpl(nodeMap, 0));
         nodeMap.commit(root);
     }
 
+    private void applyConfig(NodeImpl head) {
+        NodeImpl config = head.getNode("config");
+        for (Entry<String, String> e : config.getProperties()) {
+            nodeMap.setSetting(e.getKey(), e.getValue());
+        }
+    }
+
     public synchronized String commit(String rootPath, String jsonDiff, String revisionId, String message) {
         // TODO do we really need 'path'? store the path is in the diff instead
         // TODO what is the exact meaning of 'revisionId'? is it allowed to commit
         // using an old revision, if yes when is it allowed, or how is it different from using head?
         // TODO increment headRevId less often? commit in the background?
         // would be possible if we don't (always) return the head revision
-        // TODO property type as comment versus as special property
         // TODO metadata in storage (version)
         // TODO optional read / write version in json 'api' (as comments?)
         if (DEBUG) {
-            System.out.println("commit " + jsonDiff);
+            log("commit " + rootPath + " " + jsonDiff + " " + message);
         }
-        long oldRevision = headRevId;
-        long rev = headRevId + 1;
+        try {
+            return doCommit(rootPath, jsonDiff, revisionId, message);
+        } catch (Exception e) {
+            if (DEBUG) {
+                log("commit failed with exception: " + e);
+            }
+            throw ExceptionFactory.convert(e);
+        }
+    }
+
+    private String doCommit(String rootPath, String jsonDiff, String revisionId, String message) {
+        long oldRevision = headRevId, rev = headRevId + 1;
         NodeImpl root = nodeMap.getNode(nodeMap.getRootId());
-        NodeImpl head = root.getNode("head");
-        NodeImpl oldHead = head;
+        NodeImpl head = root.getNode("head"), oldHead = head;
         NodeImpl data = head.getNode("data");
-        JsopBuilder w = new JsopBuilder();
+        JsopBuilder diff = new JsopBuilder();
         JsopTokenizer t = new JsopTokenizer(jsonDiff);
-        String fromRoot = PathUtils.relativize("/", rootPath);
         while (true) {
             int r = t.read();
             if (r == JsopTokenizer.END) {
                 break;
             }
-            String path;
+            String path = PathUtils.concat(rootPath, t.readString());
+            String from = PathUtils.relativize("/", path);
             switch (r) {
             case '+':
-                path = t.readString();
-                w.appendTag("+ ").key(PathUtils.concat(rootPath, path));
                 t.read(':');
+                diff.appendTag("+ ").key(path);
                 // TODO support adding a property?
                 t.read('{');
                 NodeImpl n = NodeImpl.parse(nodeMap, t, rev);
-                data = data.cloneAndAddChildNode(PathUtils.concat(fromRoot, path), false, null, n, rev);
-                n.append(w, -1, 0, -1, false);
-                w.newline();
+                data = data.cloneAndAddChildNode(from, false, null, n, rev);
+                n.append(diff, -1, 0, Integer.MAX_VALUE, false);
+                diff.newline();
                 break;
             case '-':
-                path = t.readString();
-                w.appendTag("- ").value(PathUtils.concat(rootPath, path));
-                data = data.cloneAndRemoveChildNode(PathUtils.concat(fromRoot, path), rev);
-                w.newline();
+                diff.appendTag("- ").value(path).newline();
+                data = data.cloneAndRemoveChildNode(from, rev);
                 break;
             case '^':
-                path = t.readString();
                 t.read(':');
+                boolean isConfigChange = from.startsWith(":root/head/config/");
                 String value;
                 if (t.matches(JsopTokenizer.NULL)) {
                     value = null;
-                    w.appendTag("^ ").key(PathUtils.concat(rootPath, path));
-                    w.value(null);
+                    diff.appendTag("^ ").key(path).value(null);
                 } else {
                     value = t.readRawValue().trim();
-                    String nodeName = PathUtils.concat(fromRoot, PathUtils.getParentPath(path));
-                    String propertyName = PathUtils.getName(path);
-                    if (data.getNode(nodeName).hasProperty(propertyName)) {
-                        w.appendTag("^ ").key(PathUtils.concat(rootPath, path));
+                    String nodeName = PathUtils.getParentPath(from);
+                    String propertyName = PathUtils.getName(from);
+                    if (isConfigChange || data.getNode(nodeName).hasProperty(propertyName)) {
+                        diff.appendTag("^ ");
                     } else {
-                        w.appendTag("+ ").key(PathUtils.concat(rootPath, path));
+                        diff.appendTag("+ ");
                     }
-                    w.encodedValue(value);
+                    diff.key(path).encodedValue(value);
                 }
-                data = data.cloneAndSetProperty(PathUtils.concat(fromRoot, path), value, rev);
-                w.newline();
+                if (isConfigChange) {
+                    String p = PathUtils.relativize(":root/head", from);
+                    head = head.cloneAndSetProperty(p, value, rev);
+                    applyConfig(head);
+                } else {
+                    data = data.cloneAndSetProperty(from, value, rev);
+                }
+                diff.newline();
                 break;
             case '>':
-                path = t.readString();
-                String from = PathUtils.concat(fromRoot, path);
-                String name = PathUtils.getName(from);
-                w.appendTag("> ").key(PathUtils.concat(rootPath, from));
                 t.read(':');
-                String position, target;
+                diff.appendTag("> ").key(path);
+                String name = PathUtils.getName(from);
+                String position, target, to;
                 boolean rename;
-                String to;
                 if (t.matches('{')) {
                     rename = false;
                     position = t.readString();
                     t.read(':');
                     target = t.readString();
                     t.read('}');
-                    w.object().key(position);
-                    if (PathUtils.isAbsolute(target)) {
-                        w.value(target);
-                    } else {
-                        w.value(PathUtils.concat(rootPath, target));
+                    diff.object().key(position);
+                    if (!PathUtils.isAbsolute(target)) {
+                        target = PathUtils.concat(rootPath, target);
                     }
-                    w.endObject();
+                    diff.value(target).endObject();
                 } else {
                     rename = true;
                     position = null;
                     target = t.readString();
-                    if (PathUtils.isAbsolute(target)) {
-                        w.value(target);
-                    } else {
-                        w.value(PathUtils.concat(rootPath, target));
+                    if (!PathUtils.isAbsolute(target)) {
+                        target = PathUtils.concat(rootPath, target);
                     }
+                    diff.value(target);
                 }
-                w.newline();
+                diff.newline();
                 boolean before = false;
                 if ("last".equals(position)) {
                     target = PathUtils.concat(target, name);
@@ -229,13 +250,9 @@ public class MemoryKernelImpl implements
                 } else if (position == null) {
                     // move
                 } else {
-                    throw new AssertionError("position: " + position);
-                }
-                if (PathUtils.isAbsolute(target)) {
-                    to = PathUtils.relativize("/", target);
-                } else {
-                    to = PathUtils.concat(fromRoot, target);
+                    throw ExceptionFactory.get("position: " + position);
                 }
+                to = PathUtils.relativize("/", target);
                 boolean inPlaceRename = false;
                 if (rename) {
                     if (PathUtils.getParentPath(from).equals(PathUtils.getParentPath(to))) {
@@ -253,11 +270,14 @@ public class MemoryKernelImpl implements
                 }
                 break;
             default:
-                throw new AssertionError("token: " + (char) t.getTokenType());
+                throw ExceptionFactory.get("token: " + (char) t.getTokenType());
             }
         }
+        if (DEBUG) {
+            log(diff.toString());
+        }
         head = head.setChild("data", data, rev);
-        Revision revNode = new Revision(rev, clock.time(), w.toString(), message);
+        Revision revNode = new Revision(rev, clock.time(), diff.toString(), message);
         revisionCache.put(rev, revNode);
         head = revNode.store(head, new NodeImpl(nodeMap, rev));
         root = root.setChild("head", head, rev);
@@ -275,7 +295,7 @@ public class MemoryKernelImpl implements
         return headRev;
     }
 
-    NodeImpl getRoot() {
+    private NodeImpl getRoot() {
         return nodeMap.getNode(nodeMap.getRootId());
     }
 
@@ -285,7 +305,7 @@ public class MemoryKernelImpl implements
 
     public String getRevisions(long since, int maxEntries) {
         if (DEBUG) {
-            System.out.println("getRevisions " + since);
+            log("getRevisions " + since);
         }
         NodeImpl node = getRoot();
         ArrayList<Revision> revisions = new ArrayList<Revision>();
@@ -294,7 +314,7 @@ public class MemoryKernelImpl implements
             revisions.add(r);
             while (node.exists("old")) {
                 node = node.getNode("old");
-                for (Iterator<String> it = node.getChildNodeNames(); it.hasNext();) {
+                for (Iterator<String> it = node.getChildNodeNames(Integer.MAX_VALUE); it.hasNext();) {
                     r = Revision.get(revisionCache, node.getNode(it.next()));
                     if (r != null) {
                         revisions.add(r);
@@ -312,7 +332,11 @@ public class MemoryKernelImpl implements
                 buff.encodedValue(rev.toString());
             }
         }
-        return buff.endArray().toString();
+        String result = buff.endArray().toString();
+        if (DEBUG) {
+            log("getRevisions returned " + getHead(result));
+        }
+        return result;
     }
 
     public String waitForCommit(String oldHeadRevision, long maxWaitMillis) throws InterruptedException {
@@ -321,7 +345,7 @@ public class MemoryKernelImpl implements
 
     public String getJournal(String fromRevisionId, String toRevisionId) {
         if (DEBUG) {
-            System.out.println("getJournal " + fromRevisionId + " " + toRevisionId);
+            log("getJournal " + fromRevisionId + " " + toRevisionId);
         }
     	String revRange = fromRevisionId + "-" + toRevisionId;
     	synchronized (this) {
@@ -329,19 +353,19 @@ public class MemoryKernelImpl implements
     	        return lastJournal;
     	    }
     	}
-        long fromRevId = Revision.parseId(fromRevisionId);
-        long toRevId = Revision.parseId(toRevisionId);
+        long fromRev = Revision.parseId(fromRevisionId);
+        long toRev = Revision.parseId(toRevisionId);
         NodeImpl node = getRoot();
         ArrayList<Revision> revisions = new ArrayList<Revision>();
         Revision r = Revision.get(revisionCache, node.getNode("head"));
-        if (r.getId() >= fromRevId) {
+        if (r.getId() >= fromRev) {
             revisions.add(r);
         }
-        while (r.getId() > fromRevId && node.exists("old")) {
+        while (r.getId() > fromRev && node.exists("old")) {
             node = node.getNode("old");
-            for (Iterator<String> it = node.getChildNodeNames(); it.hasNext();) {
+            for (Iterator<String> it = node.getChildNodeNames(Integer.MAX_VALUE); it.hasNext();) {
                 r = Revision.get(revisionCache, node.getNode(it.next()));
-                if (r != null && r.getId() >= fromRevId && r.getId() <= toRevId) {
+                if (r != null && r.getId() >= fromRev && r.getId() <= toRev) {
                     revisions.add(r);
                 }
             }
@@ -349,7 +373,7 @@ public class MemoryKernelImpl implements
         Collections.sort(revisions);
         JsopBuilder buff = new JsopBuilder().array().newline();
         for (Revision rev : revisions) {
-            if (rev.getId() >= fromRevId && rev.getId() <= toRevId) {
+            if (rev.getId() >= fromRev && rev.getId() <= toRev) {
                 rev.appendJournal(buff);
             }
         }
@@ -357,23 +381,53 @@ public class MemoryKernelImpl implements
             lastJournalRevRange = revRange;
             lastJournal = buff.endArray().toString();
         }
+        if (DEBUG) {
+            log("getJournal returned " + getHead(lastJournal));
+        }
         return lastJournal;
     }
 
+    private String getHead(String s) {
+        return s.length() < 100 ? s : (s.substring(0, 100) + "...");
+    }
+
     public String getNodes(String path, String revisionId) {
-        return getNodes(path, revisionId, 1, 0, -1);
+        if (DEBUG) {
+            log("getNodes " + path + " revision:" + revisionId);
+        }
+        String result = doGetNodes(path, revisionId, 1, 0, -1);
+        if (DEBUG) {
+            log("getNodes returned " + getHead(result));
+        }
+        return result;
     }
 
     public String getNodes(String path, String revisionId, int depth, long offset, int count) {
         if (DEBUG) {
-            System.out.println("getNodes " + path + " " + revisionId + " " + depth + " " + offset + " " + count);
+            log("getNodes " + path + " revision:" + revisionId + " depth:" + depth + " offset:" + offset + " count:" + count);
+        }
+        String result = doGetNodes(path, revisionId, depth, offset, count);
+        if (DEBUG) {
+            log("getNodes returned " + getHead(result));
+        }
+        return result;
+    }
+
+    private String doGetNodes(String path, String revisionId, int depth, long offset, int count) {
+        if (count < 0) {
+            count = nodeMap.getMaxMemoryChildren();
         }
         if (!PathUtils.isAbsolute(path)) {
-            throw new IllegalArgumentException("Not an absolute path: " + path);
+            throw ExceptionFactory.get("Not an absolute path: " + path);
+        }
+        NodeImpl n;
+        if (path.startsWith("/:root")) {
+            n = getRoot().getNode(path.substring(7));
+        } else {
+            n = getRevision(revisionId).getNode(path.substring(1));
         }
-        NodeImpl n = getRevision(revisionId).getNode(path.substring(1));
         if (n == null) {
-            throw new RuntimeException("Path not found: " + path);
+            throw ExceptionFactory.get("Path not found: " + path);
         }
         JsopBuilder json = new JsopBuilder();
         n.append(json, depth, offset, count, true);
@@ -387,11 +441,11 @@ public class MemoryKernelImpl implements
             node = node.getNode("head");
         } else {
             if (DEBUG) {
-                System.out.println("getRevision " + revisionId);
+                log("getRevision " + revisionId);
             }
             while (true) {
                 if (!node.exists("old")) {
-                    throw new RuntimeException("Revision not found: " + revisionId);
+                    throw ExceptionFactory.get("Revision not found: " + revisionId);
                 }
                 node = node.getNode("old");
                 if (node.exists(revisionId)) {
@@ -405,55 +459,52 @@ public class MemoryKernelImpl implements
 
     public boolean nodeExists(String path, String revisionId) {
         if (DEBUG) {
-            System.out.println("nodeExists " + path + " " + revisionId);
+            log("nodeExists " + path + " revision:" + revisionId);
         }
-
-        // TODO possibly use a bloom filter
         if (!PathUtils.isAbsolute(path)) {
-            throw new IllegalArgumentException("Not an absolute path: " + path);
+            throw ExceptionFactory.get("Not an absolute path: " + path);
+        }
+        // TODO possibly use a cache / a bloom filter
+        boolean result = getRevision(revisionId).exists(path.substring(1));
+        if (DEBUG) {
+            log("nodeExists returned " + result);
         }
-        return getRevision(revisionId).exists(path.substring(1));
+        return result;
     }
 
     public long getLength(String blobId) {
         if (DEBUG) {
-            System.out.println("getLength " + blobId);
-        }
-        try {
-            return ds.getBlobLength(blobId);
-        } catch (Exception e) {
-            throw new MicroKernelException(e);
+            log("getLength " + blobId);
         }
+        return ds.getBlobLength(blobId);
     }
 
     public int read(String blobId, long pos, byte[] buff, int off, int length) {
         if (DEBUG) {
-            System.out.println("read " + blobId);
-        }
-        try {
-            return ds.readBlob(blobId, pos, buff, off, length);
-        } catch (Exception e) {
-            throw new MicroKernelException(e);
+            log("read " + blobId);
         }
+        return ds.readBlob(blobId, pos, buff, off, length);
     }
 
     public String write(InputStream in) {
         if (DEBUG) {
-            System.out.println("write " + in);
-        }
-        try {
-            return ds.writeBlob(in);
-        } catch (Exception e) {
-            throw new MicroKernelException(e);
+            log("write " + in);
         }
+        return ds.writeBlob(in);
     }
 
     public void dispose() {
         if (DEBUG) {
-            System.out.println("dispose");
+            log("dispose");
         }
         gate.commit("end");
         nodeMap.close();
     }
 
+    private static void log(String s) {
+        if (DEBUG) {
+            System.out.println(s);
+        }
+    }
+
 }

Modified: jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/mem/NodeImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/mem/NodeImpl.java?rev=1166067&r1=1166066&r2=1166067&view=diff
==============================================================================
--- jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/mem/NodeImpl.java (original)
+++ jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/mem/NodeImpl.java Wed Sep  7 08:54:47 2011
@@ -19,6 +19,7 @@ package org.apache.jackrabbit.mk.mem;
 import org.apache.jackrabbit.mk.Constants;
 import org.apache.jackrabbit.mk.json.JsopBuilder;
 import org.apache.jackrabbit.mk.json.JsopTokenizer;
+import org.apache.jackrabbit.mk.util.ExceptionFactory;
 import org.apache.jackrabbit.mk.util.PathUtils;
 
 import java.util.ArrayList;
@@ -45,7 +46,7 @@ public class NodeImpl {
         this.revId = revId;
     }
 
-    public long getId() {
+    long getId() {
         return id;
     }
 
@@ -62,12 +63,12 @@ public class NodeImpl {
             clone.properties = new HashMap<String, String>(properties);
         }
         if (childNodes != null) {
-            clone.childNodes = childNodes.createClone(map);
+            clone.childNodes = childNodes.createClone(map, revId);
         }
         return clone;
     }
 
-    public long getChildNodeCount() {
+    long getChildNodeCount() {
         return childNodes == null ? 0 : childNodes.size();
     }
 
@@ -126,11 +127,11 @@ public class NodeImpl {
         }
         String child = path.substring(0, index);
         if (childNodes == null) {
-            throw new RuntimeException("Node not found: " + path);
+            throw ExceptionFactory.get("Node not found: " + path);
         }
         NodeImpl n = getChildNode(child);
         if (n == null) {
-            throw new RuntimeException("Node not found: " + path);
+            throw ExceptionFactory.get("Node not found: " + path);
         }
         NodeImpl n2 = n.cloneAndAddChildNode(path.substring(index + 1), before, position, newNode, revId);
         NodeImpl c = createClone(revId);
@@ -139,7 +140,7 @@ public class NodeImpl {
         return c;
     }
 
-    public NodeImpl cloneAndRemoveChildNode(String path, long revId) {
+    NodeImpl cloneAndRemoveChildNode(String path, long revId) {
         int index = PathUtils.getNextSlash(path, 0);
         if (index < 0) {
             NodeImpl clone = createClone(revId);
@@ -149,7 +150,7 @@ public class NodeImpl {
         String child = path.substring(0, index);
         NodeImpl n = getChildNode(child);
         if (n == null) {
-            throw new RuntimeException("Node not found: " + path);
+            throw ExceptionFactory.get("Node not found: " + path);
         }
         NodeImpl n2 = n.cloneAndRemoveChildNode(path.substring(index + 1), revId);
         NodeImpl c = createClone(revId);
@@ -168,7 +169,7 @@ public class NodeImpl {
         String child = path.substring(0, index);
         NodeImpl n = getChildNode(child);
         if (n == null) {
-            throw new RuntimeException("Node not found: " + path);
+            throw ExceptionFactory.get("Node not found: " + path);
         }
         NodeImpl n2 = n.cloneAndSetProperty(path.substring(index + 1), value, revId);
         NodeImpl c = createClone(revId);
@@ -185,7 +186,7 @@ public class NodeImpl {
         return properties == null ? null : properties.get(propertyName);
     }
 
-    public void append(JsopBuilder json, int depth, long offset, int count, boolean childNodeCount) {
+    void append(JsopBuilder json, int depth, long offset, int count, boolean childNodeCount) {
         json.object();
         if (properties != null) {
             for (Entry<String, String> e : properties.entrySet()) {
@@ -201,10 +202,7 @@ public class NodeImpl {
                 json.key(":childNodeCount").value(childNodes.size());
             }
             if (count != 0) {
-                for (Iterator<String> it = childNodes.getNames(offset); it.hasNext() && count != 0;) {
-                    if (count > 0) {
-                        count--;
-                    }
+                for (Iterator<String> it = childNodes.getNames(offset, count); it.hasNext();) {
                     String s = it.next();
                     json.key(s);
                     if (depth == 0) {
@@ -226,7 +224,7 @@ public class NodeImpl {
         if (childNodes == null) {
             childNodes = new NodeListSmall();
         } else if (childNodes.containsKey(name)) {
-            throw new RuntimeException("Node already exists: " + name);
+            throw ExceptionFactory.get("Node already exists: " + name);
         }
         if (Constants.NODE_NAME_AS_PROPERTY) {
             node.setProperty(":name", JsopBuilder.encode(name));
@@ -235,7 +233,7 @@ public class NodeImpl {
         if (before || position != null) {
             boolean moveNext = false;
             ArrayList<String> move = new ArrayList<String>();
-            for (Iterator<String> it = childNodes.getNames(0); it.hasNext();) {
+            for (Iterator<String> it = childNodes.getNames(0, Integer.MAX_VALUE); it.hasNext();) {
                 String entry = it.next();
                 if (entry.equals(name)) {
                     // don't move new entry
@@ -257,9 +255,9 @@ public class NodeImpl {
         }
     }
 
-    void removeChildNode(String name) {
+    private void removeChildNode(String name) {
         if (childNodes == null) {
-            throw new RuntimeException("Node not found: " + name);
+            throw ExceptionFactory.get("Node not found: " + name);
         }
         childNodes.remove(name);
         if (childNodes.size() == 0) {
@@ -317,11 +315,11 @@ public class NodeImpl {
         return path;
     }
 
-    public Iterator<String> getChildNodeNames() {
+    public Iterator<String> getChildNodeNames(int maxCount) {
         if (childNodes == null || childNodes.size() == 0) {
             return new ArrayList<String>().iterator();
         }
-        return childNodes.getNames(0);
+        return childNodes.getNames(0, maxCount);
     }
 
     public Iterable<Entry<String, String>> getProperties() {
@@ -351,16 +349,7 @@ public class NodeImpl {
             }
         }
         if (childNodes != null && childNodes.size() > 0) {
-            for (Iterator<String> it = childNodes.getNames(0); it.hasNext();) {
-                String n = it.next();
-                json.key(n);
-                long x = childNodes.get(n);
-                long y = map.getId(x);
-                if (x != y) {
-                    childNodes.setId(n, y);
-                }
-                json.encodedValue(map.formatId(y));
-            }
+            childNodes.append(json, map);
         }
         return json.endObject().toString();
     }
@@ -376,7 +365,9 @@ public class NodeImpl {
                 String key = t.readString();
                 t.read(':');
                 String value = t.readRawValue();
-                if (map.isId(value)) {
+                if (key.equals(":children")) {
+                    node.childNodes = NodeListLarge.read(t, map, value);
+                } else if (map.isId(value)) {
                     if (node.childNodes == null) {
                         node.childNodes = new NodeListSmall();
                     }
@@ -391,9 +382,16 @@ public class NodeImpl {
     }
 
     NodeList getNodeList() {
+        if (childNodes == null) {
+            childNodes = new NodeListSmall();
+        }
         return childNodes;
     }
 
+    void setNodeList(NodeList childNodes) {
+        this.childNodes = childNodes;
+    }
+
     NodeImpl setChild(String name, NodeImpl child, long revId) {
         NodeImpl result = this;
         if (exists(name)) {

Modified: jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/mem/NodeList.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/mem/NodeList.java?rev=1166067&r1=1166066&r2=1166067&view=diff
==============================================================================
--- jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/mem/NodeList.java (original)
+++ jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/mem/NodeList.java Wed Sep  7 08:54:47 2011
@@ -1,8 +1,28 @@
+/*
+ * 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.mk.mem;
 
 import java.util.Iterator;
+import org.apache.jackrabbit.mk.json.JsopBuilder;
 import org.apache.jackrabbit.mk.mem.NodeImpl.ChildVisitor;
 
+/**
+ * A list of child nodes.
+ */
 interface NodeList {
 
     long size();
@@ -13,14 +33,16 @@ interface NodeList {
 
     void add(String name, long x);
 
-    void setId(String name, long x);
-
-    Iterator<String> getNames(long offset);
+    Iterator<String> getNames(long offset, int maxCount);
 
     long remove(String name);
 
-    NodeList createClone(NodeMap map);
+    NodeList createClone(NodeMap map, long revId);
 
     void visit(ChildVisitor v);
 
+    void append(JsopBuilder json, NodeMap map);
+
+    byte[] getNameFilter(NodeMap map);
+
 }

Modified: jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/mem/NodeListLarge.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/mem/NodeListLarge.java?rev=1166067&r1=1166066&r2=1166067&view=diff
==============================================================================
--- jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/mem/NodeListLarge.java (original)
+++ jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/mem/NodeListLarge.java Wed Sep  7 08:54:47 2011
@@ -17,97 +17,101 @@
 package org.apache.jackrabbit.mk.mem;
 
 import java.util.ArrayList;
-import java.util.BitSet;
 import java.util.Iterator;
-import java.util.LinkedHashMap;
+import org.apache.jackrabbit.mk.json.JsopBuilder;
+import org.apache.jackrabbit.mk.json.JsopTokenizer;
 import org.apache.jackrabbit.mk.mem.NodeImpl.ChildVisitor;
-
+import org.apache.jackrabbit.mk.util.ExceptionFactory;
+import org.apache.jackrabbit.mk.util.IOUtils;
+import org.h2.util.StringUtils;
+
+/**
+ * A large list of nodes.
+ */
 public class NodeListLarge implements NodeList {
 
-    private static final int BLOOM_FILTER_SIZE = 256;
-
     ArrayList<Child> children;
     private final NodeMap map;
+    private final long revId;
     private long size;
 
-    NodeListLarge(NodeMap map, ArrayList<Child> children) {
+    private NodeListLarge(NodeMap map, ArrayList<Child> children, long revId) {
         this.map = map;
-        children = new ArrayList<Child>();
+        this.children = children;
+        this.revId = revId;
+        for (Child c : children) {
+            size += getList(c, false).size();
+        }
     }
 
-    public NodeListLarge(NodeMap map, LinkedHashMap<String, Long> list) {
+    NodeListLarge(NodeMap map, NodeList list, long size, long revId) {
         this.map = map;
-        NodeImpl childNode = new NodeImpl(map, 0);
-        long id = map.addNode(childNode);
+        this.children = new ArrayList<Child>();
+        this.revId = revId;
         Child c = new Child();
-        c.id = id;
-        children = new ArrayList<Child>();
+        NodeImpl n = new NodeImpl(map, revId);
+        n.setNodeList(list);
+        c.id = map.addNode(n);
+        c.nameFilter = list.getNameFilter(map);
         children.add(c);
-        // TODO Auto-generated constructor stub
+        this.size = size;
     }
 
     public boolean containsKey(String name) {
         for (Child c : children) {
             if (c.possiblyContains(name)) {
-                return getList(c).containsKey(name);
-            }
-        }
-        return false;
-    }
-
-    public void setId(String name, long x) {
-        for (Child c : children) {
-            if (c.possiblyContains(name)) {
-                if (getList(c).containsKey(name)) {
-//                    getList(c).get
+                if (getList(c, false).containsKey(name)) {
+                    return true;
                 }
             }
         }
-        throw new RuntimeException("Node node found: " + name);
+        return false;
     }
 
-    NodeList getList(Child c) {
+    NodeList getList(Child c, boolean modify) {
         NodeImpl n = map.getNode(c.id);
+        if (modify) {
+            n = n.createClone(revId);
+            c.id = map.addNode(n);
+        }
         return n.getNodeList();
     }
 
     public long get(String name) {
         for (Child c : children) {
             if (c.possiblyContains(name)) {
-                NodeList child = getList(c);
+                NodeList child = getList(c, false);
                 if (child.containsKey(name)) {
                     return child.get(name);
                 }
             }
         }
-        throw new RuntimeException("Node node found: " + name);
+        throw ExceptionFactory.get("Node not found: " + name);
     }
 
-    public Iterator<String> getNames(long offset) {
+    public Iterator<String> getNames(long offset, final int maxCount) {
         int i = 0;
         for (; i < children.size(); i++) {
             Child c = children.get(i);
-            if (c.size < offset) {
-                offset -= c.size;
-                continue;
+            long size = getList(c, false).size();
+            if (size > offset) {
+                break;
             }
+            offset -= size;
         }
         final int start = i;
         final long off = offset;
         Iterator<String> it = new Iterator<String>() {
             int pos = start;
+            int remaining = maxCount;
             long offset = off;
             Iterator<String> it;
             public boolean hasNext() {
-                if (it == null) {
-                    return false;
-                }
-                if (it.hasNext()) {
+                if (it != null && it.hasNext()) {
                     return true;
                 }
-                it = null;
                 while (pos < children.size()) {
-                    it = getList(children.get(pos++)).getNames(offset);
+                    it = getList(children.get(pos++), false).getNames(offset, remaining);
                     offset = 0;
                     if (it.hasNext()) {
                         return true;
@@ -118,6 +122,7 @@ public class NodeListLarge implements No
 
             public String next() {
                 if (hasNext()) {
+                    remaining--;
                     return it.next();
                 } else {
                     return null;
@@ -133,26 +138,33 @@ public class NodeListLarge implements No
 
     public void add(String name, long x) {
         Child c = children.get(children.size() - 1);
-        NodeList child = getList(c);
+        NodeList child = getList(c, false);
+        if (child.size() >= map.getMaxMemoryChildren()) {
+            c = new Child();
+            c.id = map.addNode(new NodeImpl(map, revId));
+            children.add(c);
+        }
+        child = getList(c, true);
         child.add(name, x);
+        c.nameFilter = child.getNameFilter(map);
         size++;
     }
 
     public long remove(String name) {
         for (Child c : children) {
             if (c.possiblyContains(name)) {
-                NodeList child = getList(c);
+                NodeList child = getList(c, true);
                 if (child.containsKey(name)) {
                     Long x = child.remove(name);
                     if (x == null) {
-                        throw new RuntimeException("Could not remove " + name);
+                        throw ExceptionFactory.get("Could not remove " + name);
                     }
                     size--;
                     return x;
                 }
             }
         }
-        throw new RuntimeException("Node node found: " + name);
+        throw ExceptionFactory.get("Node node found: " + name);
     }
 
     public long size() {
@@ -160,30 +172,42 @@ public class NodeListLarge implements No
     }
 
     static class Child {
-        NodeMap map;
+
         long id;
+        byte[] nameFilter;
 
-        BitSet nameBloomFilter = new BitSet(BLOOM_FILTER_SIZE);
-        long size;
         boolean possiblyContains(String name) {
-            return nameBloomFilter.get(name.hashCode() & (BLOOM_FILTER_SIZE - 1));
-        }
-        void addName(String name) {
-            nameBloomFilter.set(name.hashCode() & (BLOOM_FILTER_SIZE - 1));
+            int h = name.hashCode();
+            int b = nameFilter[(h >> 3) & (nameFilter.length - 1)] & (h & 255);
+            return b != 0;
         }
+
     }
 
-    public NodeList createClone(NodeMap map) {
+    public NodeList createClone(NodeMap map, long revId) {
+        if (revId == this.revId) {
+            return this;
+        }
         if (size < map.getMaxMemoryChildren() / 2) {
             NodeListSmall s = new NodeListSmall();
-            for (Iterator<String> it = getNames(0); it.hasNext();) {
+            for (Iterator<String> it = getNames(0, Integer.MAX_VALUE); it.hasNext();) {
                 String n = it.next();
                 s.add(n, get(n));
             }
             return s;
         }
-        int todo;
-        return new NodeListLarge(map, children);
+        ArrayList<Child> newChildren = new ArrayList<Child>();
+        for (Child c : children) {
+            Child c2 = new Child();
+            c2.id = map.addNode(map.getNode(c.id));
+            c2.nameFilter = c.nameFilter;
+            newChildren.add(c2);
+        }
+        NodeListLarge result = new NodeListLarge(map, newChildren, revId);
+        if (children.size() > map.getMaxMemoryChildren()) {
+            return new NodeListLarge(map, result, size, revId);
+        }
+        return result;
     }
 
     public void visit(ChildVisitor v) {
@@ -192,4 +216,58 @@ public class NodeListLarge implements No
         }
     }
 
+    public void append(JsopBuilder json, NodeMap map) {
+        for (Child c : children) {
+            json.key(":children");
+            long x = c.id;
+            long y = map.getId(x);
+            if (x != y) {
+                c.id = y;
+            }
+            json.encodedValue(map.formatId(y));
+            json.key(":names").value(StringUtils.convertBytesToHex(c.nameFilter));
+        }
+        json.key(":childCount").value(size);
+    }
+
+    static NodeListLarge read(JsopTokenizer t, NodeMap map, String value) {
+        NodeListLarge list = new NodeListLarge(map, new ArrayList<Child>(), 0);
+        Child c = new Child();
+        c.id = map.parseId(value);
+        list.children.add(c);
+        while (t.matches(',')) {
+            String k = t.readString();
+            t.read(':');
+            if (k.endsWith(":childCount")) {
+                list.size = Long.parseLong(t.readRawValue());
+            } else if (k.equals(":children")) {
+                value = t.readRawValue();
+                c = new Child();
+                c.id = map.parseId(value);
+                list.children.add(c);
+            } else if (k.equals(":names")) {
+                c.nameFilter = StringUtils.convertHexToBytes(t.readString());
+            } else {
+                throw ExceptionFactory.get("Unexpected " + k);
+            }
+        }
+        return list;
+    }
+
+    public byte[] getNameFilter(NodeMap map) {
+        int len = IOUtils.nextPowerOf2(Math.min(64, map.getMaxMemoryChildren() / 4));
+        for (Child c : children) {
+            if (c.nameFilter.length < len) {
+                len = c.nameFilter.length;
+            }
+        }
+        byte[] data = new byte[len];
+        for (Child c : children) {
+            for (int i = 0; i < len; i++) {
+                data[i] |= c.nameFilter[i];
+            }
+        }
+        return data;
+    }
+
 }

Modified: jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/mem/NodeListSmall.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/mem/NodeListSmall.java?rev=1166067&r1=1166066&r2=1166067&view=diff
==============================================================================
--- jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/mem/NodeListSmall.java (original)
+++ jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/mem/NodeListSmall.java Wed Sep  7 08:54:47 2011
@@ -19,6 +19,8 @@ package org.apache.jackrabbit.mk.mem;
 import java.util.Iterator;
 import org.apache.jackrabbit.mk.json.JsopBuilder;
 import org.apache.jackrabbit.mk.mem.NodeImpl.ChildVisitor;
+import org.apache.jackrabbit.mk.util.ExceptionFactory;
+import org.apache.jackrabbit.mk.util.IOUtils;
 import org.apache.jackrabbit.mk.util.StringUtils;
 
 public class NodeListSmall implements NodeList {
@@ -77,7 +79,7 @@ public class NodeListSmall implements No
     public long get(String name) {
         int index = find(name);
         if (index < 0) {
-            throw new RuntimeException("Node node found: " + name);
+            throw ExceptionFactory.get("Node node found: " + name);
         }
         return children[sort[index]];
     }
@@ -85,7 +87,7 @@ public class NodeListSmall implements No
     public void add(String name, long x) {
         int index = find(name);
         if (index >= 0) {
-            throw new RuntimeException("Node already exists: " + name);
+            throw ExceptionFactory.get("Node already exists: " + name);
         }
         index = -index - 1;
         names = StringUtils.arrayInsert(names, size, name);
@@ -94,21 +96,15 @@ public class NodeListSmall implements No
         size++;
     }
 
-    public void setId(String name, long x) {
-        int index = find(name);
-        if (index < 0) {
-            throw new RuntimeException("Node node found: " + name);
-        }
-        children[sort[index]] = x;
-    }
-
-    public Iterator<String> getNames(final long offset) {
+    public Iterator<String> getNames(final long offset, final int maxCount) {
         return  new Iterator<String>() {
             int pos = (int) offset;
+            int remaining = maxCount;
             public boolean hasNext() {
-                return pos < size;
+                return pos < size && remaining > 0;
             }
             public String next() {
+                remaining--;
                 return names[pos++];
             }
             public void remove() {
@@ -120,7 +116,7 @@ public class NodeListSmall implements No
     public long remove(String name) {
         int index = find(name);
         if (index < 0) {
-            throw new RuntimeException("Node not found: " + name);
+            throw ExceptionFactory.get("Node not found: " + name);
         }
         int s = sort[index];
         long result = children[s];
@@ -148,11 +144,12 @@ public class NodeListSmall implements No
         return json.toString();
     }
 
-    public NodeList createClone(NodeMap map) {
-//        if (size > map.getMaxMemoryChildren()) {
-//            return new NodeListLarge(map, list);
-//        }
-        return new NodeListSmall(names, children, sort, size);
+    public NodeList createClone(NodeMap map, long revId) {
+        NodeList result = new NodeListSmall(names, children, sort, size);
+        if (size > map.getMaxMemoryChildren()) {
+            return new NodeListLarge(map, result, size, revId);
+        }
+        return result;
     }
 
     public void visit(ChildVisitor v) {
@@ -161,4 +158,26 @@ public class NodeListSmall implements No
         }
     }
 
+    public void append(JsopBuilder json, NodeMap map) {
+        for (int i = 0; i < size; i++) {
+            json.key(names[i]);
+            long x = children[i];
+            long y = map.getId(x);
+            if (x != y) {
+                children[i] = y;
+            }
+            json.encodedValue(map.formatId(y));
+        }
+    }
+
+    public byte[] getNameFilter(NodeMap map) {
+        int len = IOUtils.nextPowerOf2(Math.min(64, map.getMaxMemoryChildren() / 4));
+        byte[] data = new byte[len];
+        for (String n : names) {
+            int h = n.hashCode();
+            data[(h >> 3) & (data.length - 1)] |= h & 255;
+        }
+        return data;
+    }
+
 }

Modified: jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/mem/NodeMap.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/mem/NodeMap.java?rev=1166067&r1=1166066&r2=1166067&view=diff
==============================================================================
--- jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/mem/NodeMap.java (original)
+++ jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/mem/NodeMap.java Wed Sep  7 08:54:47 2011
@@ -17,15 +17,17 @@
 package org.apache.jackrabbit.mk.mem;
 
 import java.util.HashMap;
+import org.apache.jackrabbit.mk.util.ExceptionFactory;
 
 public class NodeMap {
 
-    private static final int MAX_MEMORY_CHILDREN = Integer.MAX_VALUE;
+    private static final String MAX_MEMORY_CHILDREN = "maxMemoryChildren";
+    private static final int DEFAULT_MAX_MEMORY_CHILDREN = Integer.MAX_VALUE;
 
     private HashMap<Long, NodeImpl> nodes = new HashMap<Long, NodeImpl>();
     private long nextId = 1;
     private long rootId;
-    private int maxMemoryChildren = MAX_MEMORY_CHILDREN;
+    private int maxMemoryChildren = DEFAULT_MAX_MEMORY_CHILDREN;
 
     public long addNode(NodeImpl node) {
         long x = node.getId();
@@ -46,6 +48,14 @@ public class NodeMap {
         nextId = 1;
     }
 
+    public void setSetting(String key, String value) {
+        if (key.equals(MAX_MEMORY_CHILDREN)) {
+            maxMemoryChildren = Integer.parseInt(value);
+        } else {
+            throw ExceptionFactory.get("Unknown setting: " + key);
+        }
+    }
+
     public void setMaxMemoryChildren(int max) {
         maxMemoryChildren = max;
     }
@@ -71,11 +81,11 @@ public class NodeMap {
     }
 
     public String formatId(long id) {
-        return "n" + id;
+        return "n" + Long.toHexString(id);
     }
 
     public long parseId(String id) {
-        return Long.parseLong(id.substring(1));
+        return Long.parseLong(id.substring(1), 16);
     }
 
     public boolean isId(String value) {

Modified: jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/mem/Revision.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/mem/Revision.java?rev=1166067&r1=1166066&r2=1166067&view=diff
==============================================================================
--- jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/mem/Revision.java (original)
+++ jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/mem/Revision.java Wed Sep  7 08:54:47 2011
@@ -31,7 +31,7 @@ public class Revision implements Compara
     private String diff;
     private String msg;
 
-    public Revision(long id, long time, String diff, String msg) {
+    Revision(long id, long time, String diff, String msg) {
         this.id = id;
         this.time = time;
         this.diff = diff;
@@ -58,22 +58,22 @@ public class Revision implements Compara
         return r;
     }
 
-    public long getId() {
+    long getId() {
         return id;
     }
 
-    public long getTime() {
+    long getTime() {
         return time;
     }
 
-    public String getDiff() {
+    private String getDiff() {
         if (diff == null) {
             diff = getCommitValue("diff");
         }
         return diff;
     }
 
-    public String getMsg() {
+    private String getMsg() {
         if (msg == null) {
             msg = getCommitValue("msg");
         }
@@ -119,7 +119,7 @@ public class Revision implements Compara
         return head.setChild("commit", commit, id);
     }
 
-    public void appendJournal(JsopBuilder buff) {
+    void appendJournal(JsopBuilder buff) {
         buff.object().
             key("id").value(Revision.formatId(id)).
             key("ts").value(time).

Modified: jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/util/IOUtils.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/util/IOUtils.java?rev=1166067&r1=1166066&r2=1166067&view=diff
==============================================================================
--- jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/util/IOUtils.java (original)
+++ jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/util/IOUtils.java Wed Sep  7 08:54:47 2011
@@ -222,4 +222,19 @@ public class IOUtils {
         }
     }
 
+    /**
+     * Get the value that is equal or higher than this value, and that is a
+     * power of two.
+     *
+     * @param x the original value
+     * @return the next power of two value
+     */
+    public static int nextPowerOf2(int x) {
+        long i = 1;
+        while (i < x && i < (Integer.MAX_VALUE / 2)) {
+            i += i;
+        }
+        return (int) i;
+    }
+
 }