You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by st...@apache.org on 2012/03/01 13:41:22 UTC

svn commit: r1295539 - in /jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/store: ./ pm/

Author: stefan
Date: Thu Mar  1 12:41:21 2012
New Revision: 1295539

URL: http://svn.apache.org/viewvc?rev=1295539&view=rev
Log:
some minor refactoring

Added:
    jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/store/pm/
    jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/store/pm/BDbPersistenceManager.java
    jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/store/pm/FSPersistenceManager.java
    jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/store/pm/H2PersistenceManager.java
    jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/store/pm/InMemPersistenceManager.java
    jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/store/pm/MongoPersistenceManager.java
    jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/store/pm/PersistenceManager.java
Removed:
    jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/store/BDbPersistenceManager.java
    jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/store/FSPersistenceManager.java
    jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/store/H2PersistenceManager.java
    jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/store/InMemPersistenceManager.java
    jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/store/MongoPersistenceManager.java
    jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/store/PersistenceManager.java
Modified:
    jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/store/DefaultRevisionStore.java
    jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/store/IdFactory.java

Modified: jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/store/DefaultRevisionStore.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/store/DefaultRevisionStore.java?rev=1295539&r1=1295538&r2=1295539&view=diff
==============================================================================
--- jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/store/DefaultRevisionStore.java (original)
+++ jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/store/DefaultRevisionStore.java Thu Mar  1 12:41:21 2012
@@ -25,6 +25,8 @@ import org.apache.jackrabbit.mk.model.No
 import org.apache.jackrabbit.mk.model.MutableNode;
 import org.apache.jackrabbit.mk.model.StoredCommit;
 import org.apache.jackrabbit.mk.model.StoredNode;
+import org.apache.jackrabbit.mk.store.pm.H2PersistenceManager;
+import org.apache.jackrabbit.mk.store.pm.PersistenceManager;
 import org.apache.jackrabbit.mk.util.SimpleLRUCache;
 
 import java.io.File;

Modified: jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/store/IdFactory.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/store/IdFactory.java?rev=1295539&r1=1295538&r2=1295539&view=diff
==============================================================================
--- jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/store/IdFactory.java (original)
+++ jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/store/IdFactory.java Thu Mar  1 12:41:21 2012
@@ -23,7 +23,7 @@ import org.apache.jackrabbit.mk.util.Asc
 /**
  * Create new commit and internal content object ids based on serialized data.
  */
-abstract class IdFactory {
+public abstract class IdFactory {
 
     /**
      * Creates a new id based on the specified serialized data.

Added: jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/store/pm/BDbPersistenceManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/store/pm/BDbPersistenceManager.java?rev=1295539&view=auto
==============================================================================
--- jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/store/pm/BDbPersistenceManager.java (added)
+++ jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/store/pm/BDbPersistenceManager.java Thu Mar  1 12:41:21 2012
@@ -0,0 +1,194 @@
+/*
+ * 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.store.pm;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+
+import org.apache.jackrabbit.mk.model.ChildNodeEntriesMap;
+import org.apache.jackrabbit.mk.model.Commit;
+import org.apache.jackrabbit.mk.model.Node;
+import org.apache.jackrabbit.mk.model.StoredCommit;
+import org.apache.jackrabbit.mk.store.BinaryBinding;
+import org.apache.jackrabbit.mk.store.Binding;
+import org.apache.jackrabbit.mk.store.IdFactory;
+import org.apache.jackrabbit.mk.store.NotFoundException;
+import org.apache.jackrabbit.mk.util.StringUtils;
+
+import com.sleepycat.je.Database;
+import com.sleepycat.je.DatabaseConfig;
+import com.sleepycat.je.DatabaseEntry;
+import com.sleepycat.je.Durability;
+import com.sleepycat.je.Environment;
+import com.sleepycat.je.EnvironmentConfig;
+import com.sleepycat.je.EnvironmentMutableConfig;
+import com.sleepycat.je.LockMode;
+import com.sleepycat.je.OperationStatus;
+
+/**
+ *
+ */
+public class BDbPersistenceManager implements PersistenceManager {
+
+    private final static byte[] HEAD_ID = new byte[]{0};
+    private Environment dbEnv;
+    private Database db;
+    private Database head;
+
+    // TODO: make this configurable
+    private IdFactory idFactory = IdFactory.getDigestFactory();
+    
+    public void initialize(File homeDir) throws Exception {
+        File dbDir = new File(homeDir, "db");
+        if (!dbDir.exists()) {
+            dbDir.mkdir();
+        }
+
+        EnvironmentConfig envConfig = new EnvironmentConfig();
+        //envConfig.setTransactional(true);
+        envConfig.setAllowCreate(true);
+        dbEnv = new Environment(dbDir, envConfig);
+
+        EnvironmentMutableConfig envMutableConfig = new EnvironmentMutableConfig();
+        //envMutableConfig.setDurability(Durability.COMMIT_SYNC);
+        //envMutableConfig.setDurability(Durability.COMMIT_NO_SYNC);
+        envMutableConfig.setDurability(Durability.COMMIT_WRITE_NO_SYNC);
+        dbEnv.setMutableConfig(envMutableConfig);
+
+        DatabaseConfig dbConfig = new DatabaseConfig();
+        dbConfig.setAllowCreate(true);
+        //dbConfig.setDeferredWrite(true);
+        db = dbEnv.openDatabase(null, "revs", dbConfig);
+
+        head = dbEnv.openDatabase(null, "head", dbConfig);
+
+        // TODO FIXME workaround in case we're not closed properly
+        Runtime.getRuntime().addShutdownHook(new Thread() {
+            public void run() {
+                try { close(); } catch (Throwable ignore) {}
+            }
+        });
+    }
+
+    public void close() {
+        try {
+            if (db.getConfig().getDeferredWrite()) {
+                db.sync();
+            }
+            db.close();
+            head.close();
+            dbEnv.close();
+
+            db = null;
+            dbEnv = null;
+        } catch (Throwable t) {
+            t.printStackTrace();
+        }
+    }
+
+    public String readHead() throws Exception {
+        DatabaseEntry key = new DatabaseEntry(HEAD_ID);
+        DatabaseEntry data = new DatabaseEntry();
+
+        if (head.get(null, key, data, LockMode.DEFAULT) == OperationStatus.SUCCESS) {
+            return StringUtils.convertBytesToHex(data.getData());
+        } else {
+            return null;
+        }
+    }
+
+    public void writeHead(String id) throws Exception {
+        DatabaseEntry key = new DatabaseEntry(HEAD_ID);
+        DatabaseEntry data = new DatabaseEntry(StringUtils.convertHexToBytes(id));
+
+        head.put(null, key, data);
+    }
+
+    public Binding readNodeBinding(String id) throws NotFoundException, Exception {
+        DatabaseEntry key = new DatabaseEntry(StringUtils.convertHexToBytes(id));
+        DatabaseEntry data = new DatabaseEntry();
+
+        if (db.get(null, key, data, LockMode.DEFAULT) == OperationStatus.SUCCESS) {
+            ByteArrayInputStream in = new ByteArrayInputStream(data.getData());
+            return new BinaryBinding(in);
+        } else {
+            throw new NotFoundException(id);
+        }
+    }
+
+    public String writeNode(Node node) throws Exception {
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        node.serialize(new BinaryBinding(out));
+        byte[] bytes = out.toByteArray();
+        byte[] rawId = idFactory.createContentId(bytes);
+        return persist(bytes, rawId);
+    }
+
+    public StoredCommit readCommit(String id) throws NotFoundException, Exception {
+        DatabaseEntry key = new DatabaseEntry(StringUtils.convertHexToBytes(id));
+        DatabaseEntry data = new DatabaseEntry();
+
+        if (db.get(null, key, data, LockMode.DEFAULT) == OperationStatus.SUCCESS) {
+            ByteArrayInputStream in = new ByteArrayInputStream(data.getData());
+            return StoredCommit.deserialize(id, new BinaryBinding(in));
+        } else {
+            throw new NotFoundException(id);
+        }
+    }
+
+    public String writeCommit(Commit commit) throws Exception {
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        commit.serialize(new BinaryBinding(out));
+        byte[] bytes = out.toByteArray();
+        byte[] rawId = idFactory.createCommitId(bytes);
+        return persist(bytes, rawId);
+    }
+
+    public ChildNodeEntriesMap readCNEMap(String id) throws NotFoundException, Exception {
+        DatabaseEntry key = new DatabaseEntry(StringUtils.convertHexToBytes(id));
+        DatabaseEntry data = new DatabaseEntry();
+
+        if (db.get(null, key, data, LockMode.DEFAULT) == OperationStatus.SUCCESS) {
+            ByteArrayInputStream in = new ByteArrayInputStream(data.getData());
+            return ChildNodeEntriesMap.deserialize(new BinaryBinding(in));
+        } else {
+            throw new NotFoundException(id);
+        }
+    }
+
+    public String writeCNEMap(ChildNodeEntriesMap map) throws Exception {
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        map.serialize(new BinaryBinding(out));
+        byte[] bytes = out.toByteArray();
+        byte[] rawId = idFactory.createContentId(bytes);
+        return persist(bytes, rawId);
+    }
+
+    //-------------------------------------------------------< implementation >
+
+    protected String persist(byte[] bytes, byte[] rawId) throws Exception {
+        String id = StringUtils.convertBytesToHex(rawId);
+
+        DatabaseEntry key = new DatabaseEntry(rawId);
+        DatabaseEntry data = new DatabaseEntry(bytes);
+
+        db.put(null, key, data);
+
+        return id;
+    }
+}

Added: jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/store/pm/FSPersistenceManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/store/pm/FSPersistenceManager.java?rev=1295539&view=auto
==============================================================================
--- jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/store/pm/FSPersistenceManager.java (added)
+++ jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/store/pm/FSPersistenceManager.java Thu Mar  1 12:41:21 2012
@@ -0,0 +1,188 @@
+/*
+ * 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.store.pm;
+
+import java.io.BufferedInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+
+import org.apache.jackrabbit.mk.model.ChildNodeEntriesMap;
+import org.apache.jackrabbit.mk.model.Commit;
+import org.apache.jackrabbit.mk.model.Node;
+import org.apache.jackrabbit.mk.model.StoredCommit;
+import org.apache.jackrabbit.mk.store.BinaryBinding;
+import org.apache.jackrabbit.mk.store.Binding;
+import org.apache.jackrabbit.mk.store.IdFactory;
+import org.apache.jackrabbit.mk.store.NotFoundException;
+import org.apache.jackrabbit.mk.util.IOUtils;
+import org.apache.jackrabbit.mk.util.StringUtils;
+
+/**
+ *
+ */
+public class FSPersistenceManager implements PersistenceManager {
+
+    private File dataDir;
+    private File head;
+
+    // TODO: make this configurable
+    private IdFactory idFactory = IdFactory.getDigestFactory();
+    
+    public void initialize(File homeDir) throws Exception {
+        dataDir = new File(homeDir, "data");
+        if (!dataDir.exists()) {
+            dataDir.mkdir();
+        }
+        head = new File(homeDir, "HEAD");
+        if (!head.exists()) {
+            writeHead("");
+        }
+    }
+
+    public void close() {
+    }
+
+    public String readHead() throws Exception {
+        FileInputStream in = new FileInputStream(head);
+        try {
+            return IOUtils.readString(in);
+        } finally {
+            in.close();
+        }
+    }
+
+    public void writeHead(String id) throws Exception {
+        FileOutputStream out = new FileOutputStream(head);
+        try {
+            IOUtils.writeString(out, id);
+        } finally {
+            out.close();
+        }
+    }
+
+    public Binding readNodeBinding(String id) throws NotFoundException, Exception {
+        File f = getFile(id);
+        if (f.exists()) {
+            BufferedInputStream in = new BufferedInputStream(new FileInputStream(f));
+            try {
+                return new BinaryBinding(in);
+            } finally {
+                in.close();
+            }
+        } else {
+            throw new NotFoundException(id);
+        }
+    }
+
+    public String writeNode(Node node) throws Exception {
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        node.serialize(new BinaryBinding(out));
+        byte[] bytes = out.toByteArray();
+        byte[] rawId = idFactory.createContentId(bytes);
+        return writeFile(bytes, rawId);
+    }
+
+    public StoredCommit readCommit(String id) throws NotFoundException, Exception {
+        File f = getFile(id);
+        if (f.exists()) {
+            BufferedInputStream in = new BufferedInputStream(new FileInputStream(f));
+            try {
+                return StoredCommit.deserialize(id, new BinaryBinding(in));
+            } finally {
+                in.close();
+            }
+        } else {
+            throw new NotFoundException(id);
+        }
+    }
+
+    public String writeCommit(Commit commit) throws Exception {
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        commit.serialize(new BinaryBinding(out));
+        byte[] bytes = out.toByteArray();
+        byte[] rawId = idFactory.createCommitId(bytes);
+        return writeFile(bytes, rawId);
+    }
+
+    public ChildNodeEntriesMap readCNEMap(String id) throws NotFoundException, Exception {
+        File f = getFile(id);
+        if (f.exists()) {
+            BufferedInputStream in = new BufferedInputStream(new FileInputStream(f));
+            try {
+                return ChildNodeEntriesMap.deserialize(new BinaryBinding(in));
+            } finally {
+                in.close();
+            }
+        } else {
+            throw new NotFoundException(id);
+        }
+    }
+
+    public String writeCNEMap(ChildNodeEntriesMap map) throws Exception {
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        map.serialize(new BinaryBinding(out));
+        byte[] bytes = out.toByteArray();
+        byte[] rawId = idFactory.createContentId(bytes);
+        return writeFile(bytes, rawId);
+    }
+
+    //-------------------------------------------------------< implementation >
+
+    private File getFile(String id) {
+        StringBuilder buf = new StringBuilder(id.substring(0, 2));
+        buf.append('/');
+        buf.append(id.substring(2));
+        return new File(dataDir, buf.toString());
+    }
+
+    private String writeFile(byte[] data, byte[] rawId) throws Exception {
+        File tmp = File.createTempFile("tmp", null, dataDir);
+
+        try {
+            FileOutputStream fos = new FileOutputStream(tmp);
+
+            try {
+                fos.write(data);
+            } finally {
+                //fos.getChannel().force(true);
+                fos.close();
+            }
+
+            String id = StringUtils.convertBytesToHex(rawId);
+            File dst = getFile(id);
+            if (dst.exists()) {
+                // already exists
+                return id;
+            }
+            // move tmp file
+            tmp.setReadOnly();
+            if (tmp.renameTo(dst)) {
+                return id;
+            }
+            // make sure parent dir exists and try again
+            dst.getParentFile().mkdir();
+            if (tmp.renameTo(dst)) {
+                return id;
+            }
+            throw new Exception("failed to create " + dst);
+        } finally {
+            tmp.delete();
+        }
+    }
+}

Added: jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/store/pm/H2PersistenceManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/store/pm/H2PersistenceManager.java?rev=1295539&view=auto
==============================================================================
--- jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/store/pm/H2PersistenceManager.java (added)
+++ jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/store/pm/H2PersistenceManager.java Thu Mar  1 12:41:21 2012
@@ -0,0 +1,253 @@
+/*
+ * 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.store.pm;
+
+import org.apache.jackrabbit.mk.model.ChildNodeEntriesMap;
+import org.apache.jackrabbit.mk.model.Commit;
+import org.apache.jackrabbit.mk.model.Node;
+import org.apache.jackrabbit.mk.model.StoredCommit;
+import org.apache.jackrabbit.mk.store.BinaryBinding;
+import org.apache.jackrabbit.mk.store.Binding;
+import org.apache.jackrabbit.mk.store.IdFactory;
+import org.apache.jackrabbit.mk.store.NotFoundException;
+import org.apache.jackrabbit.mk.util.StringUtils;
+import org.h2.jdbcx.JdbcConnectionPool;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.Statement;
+
+/**
+ *
+ */
+public class H2PersistenceManager implements PersistenceManager {
+
+    private static final boolean FAST = Boolean.getBoolean("mk.fastDb");
+
+    private JdbcConnectionPool cp;
+    
+    // TODO: make this configurable
+    private IdFactory idFactory = IdFactory.getDigestFactory();
+
+    //---------------------------------------------------< PersistenceManager >
+
+    public void initialize(File homeDir) throws Exception {
+        File dbDir = new File(homeDir, "db");
+        if (!dbDir.exists()) {
+            dbDir.mkdir();
+        }
+
+        Class.forName("org.h2.Driver");
+        String url = "jdbc:h2:" + dbDir.getCanonicalPath() + "/revs";
+        if (FAST) {
+            url += ";log=0;undo_log=0";
+        }
+        cp = JdbcConnectionPool.create(url, "sa", "");
+        cp.setMaxConnections(40);
+        Connection con = cp.getConnection();
+        try {
+            Statement stmt = con.createStatement();
+            stmt.execute("create table if not exists REVS (ID binary primary key, DATA binary)");
+            stmt.execute("create table if not exists head(id varchar) as select ''");
+            stmt.execute("create sequence if not exists datastore_id");
+/*
+            DbBlobStore store = new DbBlobStore();
+            store.setConnectionPool(cp);
+            blobStore = store;
+*/
+        } finally {
+            con.close();
+        }
+    }
+
+    public void close() {
+        cp.dispose();
+    }
+
+    public String readHead() throws Exception {
+        Connection con = cp.getConnection();
+        try {
+            PreparedStatement stmt = con.prepareStatement("select * from head");
+            ResultSet rs = stmt.executeQuery();
+            String headId = null;
+            if (rs.next()) {
+                headId = rs.getString(1);
+            }
+            stmt.close();
+            return headId;
+        } finally {
+            con.close();
+        }
+    }
+
+    public void writeHead(String id) throws Exception {
+        Connection con = cp.getConnection();
+        try {
+            PreparedStatement stmt = con.prepareStatement("update head set id=?");
+            stmt.setString(1, id);
+            stmt.execute();
+            stmt.close();
+        } finally {
+            con.close();
+        }
+    }
+
+    public Binding readNodeBinding(String id) throws NotFoundException, Exception {
+        Connection con = cp.getConnection();
+        try {
+            PreparedStatement stmt = con.prepareStatement("select DATA from REVS where ID = ?");
+            try {
+                stmt.setBytes(1, StringUtils.convertHexToBytes(id));
+                ResultSet rs = stmt.executeQuery();
+                if (rs.next()) {
+                    ByteArrayInputStream in = new ByteArrayInputStream(rs.getBytes(1));
+                    return new BinaryBinding(in);
+                } else {
+                    throw new NotFoundException(id);
+                }
+            } finally {
+                stmt.close();
+            }
+        } finally {
+            con.close();
+        }
+    }
+
+    public String writeNode(Node node) throws Exception {
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        node.serialize(new BinaryBinding(out));
+        byte[] bytes = out.toByteArray();
+        byte[] rawId = idFactory.createContentId(bytes);
+        String id = StringUtils.convertBytesToHex(rawId);
+
+        Connection con = cp.getConnection();
+        try {
+            PreparedStatement stmt = con
+                    .prepareStatement(
+                            "insert into REVS (ID, DATA) select ?, ? where not exists (select 1 from revs where ID = ?)");
+            try {
+                stmt.setBytes(1, rawId);
+                stmt.setBytes(2, bytes);
+                stmt.setBytes(3, rawId);
+                stmt.executeUpdate();
+            } finally {
+                stmt.close();
+            }
+        } finally {
+            con.close();
+        }
+        return id;
+    }
+
+    public StoredCommit readCommit(String id) throws NotFoundException, Exception {
+        Connection con = cp.getConnection();
+        try {
+            PreparedStatement stmt = con.prepareStatement("select DATA from REVS where ID = ?");
+            try {
+                stmt.setBytes(1, StringUtils.convertHexToBytes(id));
+                ResultSet rs = stmt.executeQuery();
+                if (rs.next()) {
+                    ByteArrayInputStream in = new ByteArrayInputStream(rs.getBytes(1));
+                    return StoredCommit.deserialize(id, new BinaryBinding(in));
+                } else {
+                    throw new NotFoundException(id);
+                }
+            } finally {
+                stmt.close();
+            }
+        } finally {
+            con.close();
+        }
+    }
+    
+    public String writeCommit(Commit commit) throws Exception {
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        commit.serialize(new BinaryBinding(out));
+        byte[] bytes = out.toByteArray();
+        byte[] rawId = idFactory.createCommitId(bytes);
+        String id = StringUtils.convertBytesToHex(rawId);
+
+        Connection con = cp.getConnection();
+        try {
+            PreparedStatement stmt = con
+                    .prepareStatement(
+                            "insert into REVS (ID, DATA) select ?, ? where not exists (select 1 from revs where ID = ?)");
+            try {
+                stmt.setBytes(1, rawId);
+                stmt.setBytes(2, bytes);
+                stmt.setBytes(3, rawId);
+                stmt.executeUpdate();
+            } finally {
+                stmt.close();
+            }
+        } finally {
+            con.close();
+        }
+        return id;
+    }
+
+    public ChildNodeEntriesMap readCNEMap(String id) throws NotFoundException, Exception {
+        Connection con = cp.getConnection();
+        try {
+            PreparedStatement stmt = con.prepareStatement("select DATA from REVS where ID = ?");
+            try {
+                stmt.setBytes(1, StringUtils.convertHexToBytes(id));
+                ResultSet rs = stmt.executeQuery();
+                if (rs.next()) {
+                    ByteArrayInputStream in = new ByteArrayInputStream(rs.getBytes(1));
+                    return ChildNodeEntriesMap.deserialize(new BinaryBinding(in));
+                } else {
+                    throw new NotFoundException(id);
+                }
+            } finally {
+                stmt.close();
+            }
+        } finally {
+            con.close();
+        }
+    }
+
+    public String writeCNEMap(ChildNodeEntriesMap map) throws Exception {
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        map.serialize(new BinaryBinding(out));
+        byte[] bytes = out.toByteArray();
+        byte[] rawId = idFactory.createContentId(bytes);
+        String id = StringUtils.convertBytesToHex(rawId);
+
+        Connection con = cp.getConnection();
+        try {
+            PreparedStatement stmt = con
+                    .prepareStatement(
+                            "insert into REVS (ID, DATA) select ?, ? where not exists (select 1 from revs where ID = ?)");
+            try {
+                stmt.setBytes(1, rawId);
+                stmt.setBytes(2, bytes);
+                stmt.setBytes(3, rawId);
+                stmt.executeUpdate();
+            } finally {
+                stmt.close();
+            }
+        } finally {
+            con.close();
+        }
+        return id;
+    }
+}
\ No newline at end of file

Added: jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/store/pm/InMemPersistenceManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/store/pm/InMemPersistenceManager.java?rev=1295539&view=auto
==============================================================================
--- jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/store/pm/InMemPersistenceManager.java (added)
+++ jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/store/pm/InMemPersistenceManager.java Thu Mar  1 12:41:21 2012
@@ -0,0 +1,152 @@
+/*
+ * 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.store.pm;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.InputStream;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.jackrabbit.mk.blobs.BlobStore;
+import org.apache.jackrabbit.mk.blobs.MemoryBlobStore;
+import org.apache.jackrabbit.mk.model.ChildNodeEntriesMap;
+import org.apache.jackrabbit.mk.model.Commit;
+import org.apache.jackrabbit.mk.model.Node;
+import org.apache.jackrabbit.mk.model.StoredCommit;
+import org.apache.jackrabbit.mk.store.BinaryBinding;
+import org.apache.jackrabbit.mk.store.Binding;
+import org.apache.jackrabbit.mk.store.IdFactory;
+import org.apache.jackrabbit.mk.store.NotFoundException;
+import org.apache.jackrabbit.mk.util.StringUtils;
+
+/**
+ *
+ */
+public class InMemPersistenceManager implements PersistenceManager, BlobStore {
+
+    private final Map<String, byte[]> nodes = Collections.synchronizedMap(new HashMap<String, byte[]>());
+    private final Map<String, StoredCommit> commits = Collections.synchronizedMap(new HashMap<String, StoredCommit>());
+    private final Map<String, ChildNodeEntriesMap> cneMaps = Collections.synchronizedMap(new HashMap<String, ChildNodeEntriesMap>());
+    private final BlobStore blobs = new MemoryBlobStore();
+
+    private String head;
+
+    // TODO: make this configurable
+    private IdFactory idFactory = IdFactory.getDigestFactory();
+    
+    public void initialize(File homeDir) throws Exception {
+        head = null;
+    }
+
+    public void close() {
+    }
+
+    public String readHead() throws Exception {
+        return head;
+    }
+
+    public void writeHead(String id) throws Exception {
+        head = id;
+    }
+
+    public Binding readNodeBinding(String id) throws NotFoundException, Exception {
+        byte[] bytes = nodes.get(id);
+        if (bytes != null) {
+            return new BinaryBinding(new ByteArrayInputStream(bytes));
+        } else {
+            throw new NotFoundException(id);
+        }
+    }
+
+    public String writeNode(Node node) throws Exception {
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        node.serialize(new BinaryBinding(out));
+        byte[] bytes = out.toByteArray();
+        String id = StringUtils.convertBytesToHex(idFactory.createContentId(bytes));
+
+        if (!nodes.containsKey(id)) {
+            nodes.put(id, bytes);
+        }
+
+        return id;
+    }
+
+    public StoredCommit readCommit(String id) throws NotFoundException, Exception {
+        StoredCommit commit = commits.get(id);
+        if (commit != null) {
+            return commit;
+        } else {
+            throw new NotFoundException(id);
+        }
+    }
+
+    public String writeCommit(Commit commit) throws Exception {
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        commit.serialize(new BinaryBinding(out));
+        byte[] bytes = out.toByteArray();
+        String id = StringUtils.convertBytesToHex(idFactory.createCommitId(bytes));
+
+        if (!commits.containsKey(id)) {
+            commits.put(id, StoredCommit.deserialize(id, new BinaryBinding(new ByteArrayInputStream(bytes))));
+        }
+
+        return id;
+    }
+
+    public ChildNodeEntriesMap readCNEMap(String id) throws NotFoundException, Exception {
+        ChildNodeEntriesMap map = cneMaps.get(id);
+        if (map != null) {
+            return map;
+        } else {
+            throw new NotFoundException(id);
+        }
+    }
+
+    public String writeCNEMap(ChildNodeEntriesMap map) throws Exception {
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        map.serialize(new BinaryBinding(out));
+        byte[] bytes = out.toByteArray();
+        String id = StringUtils.convertBytesToHex(idFactory.createContentId(bytes));
+
+        if (!cneMaps.containsKey(id)) {
+            cneMaps.put(id, ChildNodeEntriesMap.deserialize(new BinaryBinding(new ByteArrayInputStream(bytes))));
+        }
+
+        return id;
+    }
+    
+    //------------------------------------------------------------< BlobStore >
+
+    public String addBlob(String tempFilePath) throws Exception {
+        return blobs.addBlob(tempFilePath);
+    }
+
+    public String writeBlob(InputStream in) throws Exception {
+        return blobs.writeBlob(in);
+    }
+
+    public int readBlob(String blobId, long pos, byte[] buff, int off, int length) throws NotFoundException, Exception {
+        return blobs.readBlob(blobId, pos, buff, off, length);
+    }
+
+    public long getBlobLength(String blobId) throws Exception {
+        return blobs.getBlobLength(blobId);
+    }
+}

Added: jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/store/pm/MongoPersistenceManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/store/pm/MongoPersistenceManager.java?rev=1295539&view=auto
==============================================================================
--- jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/store/pm/MongoPersistenceManager.java (added)
+++ jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/store/pm/MongoPersistenceManager.java Thu Mar  1 12:41:21 2012
@@ -0,0 +1,484 @@
+/*
+ * 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.store.pm;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.InputStream;
+import java.util.Iterator;
+
+import org.apache.jackrabbit.mk.blobs.BlobStore;
+import org.apache.jackrabbit.mk.fs.FilePath;
+import org.apache.jackrabbit.mk.model.ChildNodeEntriesMap;
+import org.apache.jackrabbit.mk.model.Commit;
+import org.apache.jackrabbit.mk.model.Node;
+import org.apache.jackrabbit.mk.model.StoredCommit;
+import org.apache.jackrabbit.mk.store.BinaryBinding;
+import org.apache.jackrabbit.mk.store.Binding;
+import org.apache.jackrabbit.mk.store.IdFactory;
+import org.apache.jackrabbit.mk.store.NotFoundException;
+import org.apache.jackrabbit.mk.util.ExceptionFactory;
+import org.apache.jackrabbit.mk.util.IOUtils;
+import org.apache.jackrabbit.mk.util.StringUtils;
+import org.bson.types.ObjectId;
+
+import com.mongodb.BasicDBObject;
+import com.mongodb.DB;
+import com.mongodb.DBCollection;
+import com.mongodb.DBObject;
+import com.mongodb.Mongo;
+import com.mongodb.MongoException;
+import com.mongodb.WriteConcern;
+import com.mongodb.gridfs.GridFS;
+import com.mongodb.gridfs.GridFSDBFile;
+import com.mongodb.gridfs.GridFSInputFile;
+
+/**
+ *
+ */
+public class MongoPersistenceManager implements PersistenceManager, BlobStore {
+
+    private static final boolean BINARY_FORMAT = false;
+
+    private static final String HEAD_COLLECTION = "head";
+    private static final String NODES_COLLECTION = "nodes";
+    private static final String COMMITS_COLLECTION = "commits";
+    private static final String CNEMAPS_COLLECTION = "cneMaps";
+    private static final String ID_FIELD = ":id";
+    private static final String DATA_FIELD = ":data";
+
+    private Mongo con;
+    private DB db;
+    private DBCollection nodes;
+    private DBCollection commits;
+    private DBCollection cneMaps;
+    private GridFS fs;
+
+    // TODO: make this configurable
+    private IdFactory idFactory = IdFactory.getDigestFactory();
+    
+    public void initialize(File homeDir) throws Exception {
+        con = new Mongo();
+        //con = new Mongo("localhost", 27017);
+
+        db = con.getDB("mk");
+        db.setWriteConcern(WriteConcern.SAFE);
+
+        if (!db.collectionExists(HEAD_COLLECTION)) {
+            // capped collection of size 1
+            db.createCollection(HEAD_COLLECTION, new BasicDBObject("capped", true).append("size", 256).append("max", 1));
+        }
+
+        nodes = db.getCollection(NODES_COLLECTION);
+        nodes.ensureIndex(
+                new BasicDBObject(ID_FIELD, 1),
+                new BasicDBObject("unique", true));
+
+        commits = db.getCollection(COMMITS_COLLECTION);
+        commits.ensureIndex(
+                new BasicDBObject(ID_FIELD, 1),
+                new BasicDBObject("unique", true));
+
+        cneMaps = db.getCollection(CNEMAPS_COLLECTION);
+        cneMaps.ensureIndex(
+                new BasicDBObject(ID_FIELD, 1),
+                new BasicDBObject("unique", true));
+
+        fs = new GridFS(db);
+    }
+
+    public void close() {
+        con.close();
+        con = null;
+        db = null;
+    }
+
+    public String readHead() throws Exception {
+        DBObject entry = db.getCollection(HEAD_COLLECTION).findOne();
+        if (entry == null) {
+            return null;
+        }
+        return (String) entry.get(ID_FIELD);
+    }
+
+    public void writeHead(String id) throws Exception {
+        // capped collection of size 1
+        db.getCollection(HEAD_COLLECTION).insert(new BasicDBObject(ID_FIELD, id));
+    }
+
+    public Binding readNodeBinding(String id) throws NotFoundException, Exception {
+        BasicDBObject key = new BasicDBObject();
+        if (BINARY_FORMAT) {
+            key.put(ID_FIELD, StringUtils.convertHexToBytes(id));
+        } else {
+            key.put(ID_FIELD, id);
+        }
+        final BasicDBObject nodeObject = (BasicDBObject) nodes.findOne(key);
+        if (nodeObject != null) {
+            // todo support partitioned child node lists
+            if (BINARY_FORMAT) {
+                byte[] bytes = (byte[]) nodeObject.get(DATA_FIELD);
+                return new BinaryBinding(new ByteArrayInputStream(bytes));
+            } else {
+                return new DBObjectBinding(nodeObject);
+            }
+        } else {
+            throw new NotFoundException(id);
+        }
+    }
+    
+    public String writeNode(Node node) throws Exception {
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        node.serialize(new BinaryBinding(out));
+        byte[] bytes = out.toByteArray();
+        byte[] key = idFactory.createContentId(bytes);
+        String id = StringUtils.convertBytesToHex(key);
+
+        // todo support partitioned child node lists
+        BasicDBObject nodeObject;
+        if (BINARY_FORMAT) {
+            nodeObject = new BasicDBObject(ID_FIELD, key).append(DATA_FIELD, bytes);
+        } else {
+            nodeObject = new BasicDBObject(ID_FIELD, id);
+            node.serialize(new DBObjectBinding(nodeObject));
+        }
+        try {
+            nodes.insert(nodeObject);
+        } catch (MongoException.DuplicateKey ignore) {
+            // fall through
+        }
+
+        return id;
+    }
+
+    public StoredCommit readCommit(String id) throws NotFoundException, Exception {
+        BasicDBObject key = new BasicDBObject();
+        if (BINARY_FORMAT) {
+            key.put(ID_FIELD, StringUtils.convertHexToBytes(id));
+        } else {
+            key.put(ID_FIELD, id);
+        }
+        BasicDBObject commitObject = (BasicDBObject) commits.findOne(key);
+        if (commitObject != null) {
+            if (BINARY_FORMAT) {
+                byte[] bytes = (byte[]) commitObject.get(DATA_FIELD);
+                return StoredCommit.deserialize(id, new BinaryBinding(new ByteArrayInputStream(bytes)));
+            } else {
+                return StoredCommit.deserialize(id, new DBObjectBinding(commitObject));
+            }
+        } else {
+            throw new NotFoundException(id);
+        }
+    }
+
+    public String writeCommit(Commit commit) throws Exception {
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        commit.serialize(new BinaryBinding(out));
+        byte[] bytes = out.toByteArray();
+        byte[] key = idFactory.createCommitId(bytes);
+        String id = StringUtils.convertBytesToHex(key);
+
+        BasicDBObject commitObject;
+        if (BINARY_FORMAT) {
+            commitObject = new BasicDBObject(ID_FIELD, key).append(DATA_FIELD, bytes);
+        } else {
+            commitObject = new BasicDBObject(ID_FIELD, id);
+            commit.serialize(new DBObjectBinding(commitObject));
+        }
+        try {
+            commits.insert(commitObject);
+        } catch (MongoException.DuplicateKey ignore) {
+            // fall through
+        }
+
+        return id;
+    }
+
+    public ChildNodeEntriesMap readCNEMap(String id) throws NotFoundException, Exception {
+        BasicDBObject key = new BasicDBObject();
+        if (BINARY_FORMAT) {
+            key.put(ID_FIELD, StringUtils.convertHexToBytes(id));
+        } else {
+            key.put(ID_FIELD, id);
+        }
+        BasicDBObject mapObject = (BasicDBObject) cneMaps.findOne(key);
+        if (mapObject != null) {
+            if (BINARY_FORMAT) {
+                byte[] bytes = (byte[]) mapObject.get(DATA_FIELD);
+                return ChildNodeEntriesMap.deserialize(new BinaryBinding(new ByteArrayInputStream(bytes)));
+            } else {
+                return ChildNodeEntriesMap.deserialize(new DBObjectBinding(mapObject));
+            }
+        } else {
+            throw new NotFoundException(id);
+        }
+    }
+
+    public String writeCNEMap(ChildNodeEntriesMap map) throws Exception {
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        map.serialize(new BinaryBinding(out));
+        byte[] bytes = out.toByteArray();
+        byte[] key = idFactory.createContentId(bytes);
+        String id = StringUtils.convertBytesToHex(key);
+
+        BasicDBObject mapObject;
+        if (BINARY_FORMAT) {
+            mapObject = new BasicDBObject(ID_FIELD, key).append(DATA_FIELD, bytes);
+        } else {
+            mapObject = new BasicDBObject(ID_FIELD, id);
+            map.serialize(new DBObjectBinding(mapObject));
+        }
+        try {
+            cneMaps.insert(mapObject);
+        } catch (MongoException.DuplicateKey ignore) {
+            // fall through
+        }
+
+        return id;
+    }
+
+    //------------------------------------------------------------< BlobStore >
+
+    public String addBlob(String tempFilePath) throws Exception {
+        try {
+            FilePath file = FilePath.get(tempFilePath);
+            try {
+                InputStream in = file.newInputStream();
+                return writeBlob(in);
+            } finally {
+                file.delete();
+            }
+        } catch (Exception e) {
+            throw ExceptionFactory.convert(e);
+        }
+    }
+
+    public String writeBlob(InputStream in) throws Exception {
+        GridFSInputFile f = fs.createFile(in, true);
+        //f.save(0x20000);   // save in 128k chunks
+        f.save();
+
+        return f.getId().toString();
+    }
+
+    public int readBlob(String blobId, long pos, byte[] buff, int off,
+            int length) throws Exception {
+
+        GridFSDBFile f = fs.findOne(new ObjectId(blobId));
+        if (f == null) {
+            throw new NotFoundException(blobId);
+        }
+        // todo provide a more efficient implementation
+        InputStream in = f.getInputStream();
+        try {
+            in.skip(pos);
+            return in.read(buff, off, length);
+        } finally {
+            IOUtils.closeQuietly(in);
+        }
+    }
+
+    public long getBlobLength(String blobId) throws Exception {
+        GridFSDBFile f = fs.findOne(new ObjectId(blobId));
+        if (f == null) {
+            throw new NotFoundException(blobId);
+        }
+
+        return f.getLength();
+    }
+    
+    //-------------------------------------------------------< implementation >
+
+    protected final static String ENCODED_DOT = "_x46_";
+    protected final static String ENCODED_DOLLAR_SIGN = "_x36_";
+
+    /**
+     * see http://www.mongodb.org/display/DOCS/Legal+Key+Names
+     *
+     * @param name
+     * @return
+     */
+    protected static String encodeName(String name) {
+        StringBuilder buf = null;
+        for (int i = 0; i < name.length(); i++) {
+            if (i == 0 && name.charAt(i) == '$') {
+                // mongodb field names must not start with '$'
+                buf = new StringBuilder();
+                buf.append(ENCODED_DOLLAR_SIGN);
+            } else if (name.charAt(i) == '.') {
+                // . is a reserved char for mongodb field names
+                if (buf == null) {
+                    buf = new StringBuilder(name.substring(0, i));
+                }
+                buf.append(ENCODED_DOT);
+            } else {
+                if (buf != null) {
+                    buf.append(name.charAt(i));
+                }
+            }
+        }
+
+        return buf == null ? name : buf.toString();
+    }
+
+    protected static String decodeName(String name) {
+        StringBuilder buf = null;
+
+        int lastPos = 0;
+        if (name.startsWith(ENCODED_DOLLAR_SIGN)) {
+            buf = new StringBuilder("$");
+            lastPos = ENCODED_DOLLAR_SIGN.length();
+        }
+
+        int pos;
+        while ((pos = name.indexOf(ENCODED_DOT, lastPos)) != -1) {
+            if (buf == null) {
+                buf = new StringBuilder();
+            }
+            buf.append(name.substring(lastPos, pos));
+            buf.append('.');
+            lastPos = pos + ENCODED_DOT.length();
+        }
+
+        if (buf != null) {
+            buf.append(name.substring(lastPos));
+            return buf.toString();
+        } else {
+            return name;
+        }
+    }
+
+    //--------------------------------------------------------< inner classes >
+
+    protected class DBObjectBinding implements Binding {
+
+        BasicDBObject obj;
+
+        protected DBObjectBinding(BasicDBObject obj) {
+            this.obj = obj;
+        }
+
+        @Override
+        public void write(String key, String value) throws Exception {
+            obj.append(encodeName(key), value);
+        }
+
+        @Override
+        public void write(String key, byte[] value) throws Exception {
+            obj.append(encodeName(key), StringUtils.convertBytesToHex(value));
+        }
+
+        @Override
+        public void write(String key, long value) throws Exception {
+            obj.append(encodeName(key), value);
+        }
+
+        @Override
+        public void write(String key, int value) throws Exception {
+            obj.append(encodeName(key), value);
+        }
+
+        @Override
+        public void writeMap(String key, int count, StringEntryIterator iterator) throws Exception {
+            BasicDBObject childObj = new BasicDBObject();
+            while (iterator.hasNext()) {
+                StringEntry entry = iterator.next();
+                childObj.append(encodeName(entry.getKey()), entry.getValue());
+            }
+            obj.append(encodeName(key), childObj);
+        }
+
+        @Override
+        public void writeMap(String key, int count, BytesEntryIterator iterator) throws Exception {
+            BasicDBObject childObj = new BasicDBObject();
+            while (iterator.hasNext()) {
+                BytesEntry entry = iterator.next();
+                childObj.append(encodeName(entry.getKey()), StringUtils.convertBytesToHex(entry.getValue()));
+            }
+            obj.append(encodeName(key), childObj);
+        }
+
+        @Override
+        public String readStringValue(String key) throws Exception {
+            return obj.getString(encodeName(key));
+        }
+
+        @Override
+        public byte[] readBytesValue(String key) throws Exception {
+            return StringUtils.convertHexToBytes(obj.getString(encodeName(key)));
+        }
+
+        @Override
+        public long readLongValue(String key) throws Exception {
+            return obj.getLong(encodeName(key));
+        }
+
+        @Override
+        public int readIntValue(String key) throws Exception {
+            return obj.getInt(encodeName(key));
+        }
+
+        @Override
+        public StringEntryIterator readStringMap(String key) throws Exception {
+            final BasicDBObject childObj = (BasicDBObject) obj.get(encodeName(key));
+            final Iterator<String> it = childObj.keySet().iterator();
+            return new StringEntryIterator() {
+                @Override
+                public boolean hasNext() {
+                    return it.hasNext();
+                }
+
+                @Override
+                public StringEntry next() {
+                    String key = it.next();
+                    return new StringEntry(decodeName(key), childObj.getString(key));
+                }
+
+                @Override
+                public void remove() {
+                    throw new UnsupportedOperationException();
+                }
+            };
+        }
+
+        @Override
+        public BytesEntryIterator readBytesMap(String key) throws Exception {
+            final BasicDBObject childObj = (BasicDBObject) obj.get(encodeName(key));
+            final Iterator<String> it = childObj.keySet().iterator();
+            return new BytesEntryIterator() {
+                @Override
+                public boolean hasNext() {
+                    return it.hasNext();
+                }
+
+                @Override
+                public BytesEntry next() {
+                    String key = it.next();
+                    return new BytesEntry(
+                            decodeName(key),
+                            StringUtils.convertHexToBytes(childObj.getString(key)));
+                }
+
+                @Override
+                public void remove() {
+                    throw new UnsupportedOperationException();
+                }
+            };
+        }
+    }
+}

Added: jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/store/pm/PersistenceManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/store/pm/PersistenceManager.java?rev=1295539&view=auto
==============================================================================
--- jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/store/pm/PersistenceManager.java (added)
+++ jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/store/pm/PersistenceManager.java Thu Mar  1 12:41:21 2012
@@ -0,0 +1,56 @@
+/*
+ * 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.store.pm;
+
+import java.io.File;
+
+import org.apache.jackrabbit.mk.model.ChildNodeEntriesMap;
+import org.apache.jackrabbit.mk.model.Commit;
+import org.apache.jackrabbit.mk.model.Node;
+import org.apache.jackrabbit.mk.model.StoredCommit;
+import org.apache.jackrabbit.mk.store.Binding;
+import org.apache.jackrabbit.mk.store.NotFoundException;
+
+/**
+ * Defines the methods exposed by a persistence manager, that stores head
+ * revision id, nodes, child node entries and blobs.
+ * 
+ * TODO: instead of deserializing objects on their own, return Binding
+ *       instances, such as in #readNodeBinding.
+ */
+public interface PersistenceManager {
+
+    void initialize(File homeDir) throws Exception;
+
+    void close();
+
+    String readHead() throws Exception;
+
+    void writeHead(String id) throws Exception;
+
+    Binding readNodeBinding(String id) throws NotFoundException, Exception;
+
+    String writeNode(Node node) throws Exception;
+
+    ChildNodeEntriesMap readCNEMap(String id) throws NotFoundException, Exception;
+
+    String writeCNEMap(ChildNodeEntriesMap map) throws Exception;
+
+    StoredCommit readCommit(String id) throws NotFoundException, Exception;
+
+    String writeCommit(Commit commit) throws Exception;
+}