You are viewing a plain text version of this content. The canonical link for it is here.
Posted to oak-commits@jackrabbit.apache.org by dp...@apache.org on 2012/04/17 14:54:05 UTC

svn commit: r1327074 - in /jackrabbit/oak/trunk/oak-mk/src: main/java/org/apache/jackrabbit/mk/core/ main/java/org/apache/jackrabbit/mk/persistence/ main/java/org/apache/jackrabbit/mk/store/ test/java/org/apache/jackrabbit/mk/persistence/ test/java/org...

Author: dpfister
Date: Tue Apr 17 12:54:04 2012
New Revision: 1327074

URL: http://svn.apache.org/viewvc?rev=1327074&view=rev
Log:
GC for revisions (wip)
- restore initialize() method in Persistence
- derive Persistence from Closeable

Added:
    jackrabbit/oak/trunk/oak-mk/src/main/java/org/apache/jackrabbit/mk/persistence/GCPersistence.java   (with props)
    jackrabbit/oak/trunk/oak-mk/src/test/java/org/apache/jackrabbit/mk/persistence/
    jackrabbit/oak/trunk/oak-mk/src/test/java/org/apache/jackrabbit/mk/persistence/GCPersistenceTest.java   (with props)
Modified:
    jackrabbit/oak/trunk/oak-mk/src/main/java/org/apache/jackrabbit/mk/core/Repository.java
    jackrabbit/oak/trunk/oak-mk/src/main/java/org/apache/jackrabbit/mk/persistence/BDbPersistence.java
    jackrabbit/oak/trunk/oak-mk/src/main/java/org/apache/jackrabbit/mk/persistence/FSPersistence.java
    jackrabbit/oak/trunk/oak-mk/src/main/java/org/apache/jackrabbit/mk/persistence/H2Persistence.java
    jackrabbit/oak/trunk/oak-mk/src/main/java/org/apache/jackrabbit/mk/persistence/InMemPersistence.java
    jackrabbit/oak/trunk/oak-mk/src/main/java/org/apache/jackrabbit/mk/persistence/MongoPersistence.java
    jackrabbit/oak/trunk/oak-mk/src/main/java/org/apache/jackrabbit/mk/persistence/Persistence.java
    jackrabbit/oak/trunk/oak-mk/src/main/java/org/apache/jackrabbit/mk/store/DefaultRevisionStore.java
    jackrabbit/oak/trunk/oak-mk/src/test/java/org/apache/jackrabbit/mk/store/CopyingGCTest.java

Modified: jackrabbit/oak/trunk/oak-mk/src/main/java/org/apache/jackrabbit/mk/core/Repository.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-mk/src/main/java/org/apache/jackrabbit/mk/core/Repository.java?rev=1327074&r1=1327073&r2=1327074&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-mk/src/main/java/org/apache/jackrabbit/mk/core/Repository.java (original)
+++ jackrabbit/oak/trunk/oak-mk/src/main/java/org/apache/jackrabbit/mk/core/Repository.java Tue Apr 17 12:54:04 2012
@@ -89,9 +89,9 @@ public class Repository {
             return;
         }
 
-        H2Persistence pm = new H2Persistence(homeDir);
+        H2Persistence pm = new H2Persistence();
         //org.apache.jackrabbit.mk.persistence.MongoPersistence pm = new org.apache.jackrabbit.mk.persistence.MongoPersistence();
-        pm.initialize();
+        pm.initialize(homeDir);
         
         DefaultRevisionStore rs = new DefaultRevisionStore(pm);
         rs.initialize();

Modified: jackrabbit/oak/trunk/oak-mk/src/main/java/org/apache/jackrabbit/mk/persistence/BDbPersistence.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-mk/src/main/java/org/apache/jackrabbit/mk/persistence/BDbPersistence.java?rev=1327074&r1=1327073&r2=1327074&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-mk/src/main/java/org/apache/jackrabbit/mk/persistence/BDbPersistence.java (original)
+++ jackrabbit/oak/trunk/oak-mk/src/main/java/org/apache/jackrabbit/mk/persistence/BDbPersistence.java Tue Apr 17 12:54:04 2012
@@ -47,7 +47,6 @@ import com.sleepycat.je.OperationStatus;
 public class BDbPersistence implements Persistence, Closeable {
 
     private final static byte[] HEAD_ID = new byte[]{0};
-    private final File homeDir;
     private Environment dbEnv;
     private Database db;
     private Database head;
@@ -55,11 +54,7 @@ public class BDbPersistence implements P
     // TODO: make this configurable
     private IdFactory idFactory = IdFactory.getDigestFactory();
     
-    public BDbPersistence(File homeDir) {
-        this.homeDir = homeDir;
-    }
-    
-    public void initialize() throws Exception {
+    public void initialize(File homeDir) throws Exception {
         File dbDir = new File(homeDir, "db");
         if (!dbDir.exists()) {
             dbDir.mkdirs();

Modified: jackrabbit/oak/trunk/oak-mk/src/main/java/org/apache/jackrabbit/mk/persistence/FSPersistence.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-mk/src/main/java/org/apache/jackrabbit/mk/persistence/FSPersistence.java?rev=1327074&r1=1327073&r2=1327074&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-mk/src/main/java/org/apache/jackrabbit/mk/persistence/FSPersistence.java (original)
+++ jackrabbit/oak/trunk/oak-mk/src/main/java/org/apache/jackrabbit/mk/persistence/FSPersistence.java Tue Apr 17 12:54:04 2012
@@ -38,19 +38,13 @@ import org.apache.jackrabbit.mk.util.IOU
  */
 public class FSPersistence implements Persistence {
 
-    private final File homeDir;
     private File dataDir;
     private File head;
 
     // TODO: make this configurable
     private IdFactory idFactory = IdFactory.getDigestFactory();
     
-    
-    public FSPersistence(File homeDir) {
-        this.homeDir = homeDir;
-    }
-    
-    public void initialize() throws Exception {
+    public void initialize(File homeDir) throws Exception {
         dataDir = new File(homeDir, "data");
         if (!dataDir.exists()) {
             dataDir.mkdirs();
@@ -192,4 +186,9 @@ public class FSPersistence implements Pe
             tmp.delete();
         }
     }
+    
+    @Override
+    public void close() {
+        // nothing to do here
+    }
 }

Added: jackrabbit/oak/trunk/oak-mk/src/main/java/org/apache/jackrabbit/mk/persistence/GCPersistence.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-mk/src/main/java/org/apache/jackrabbit/mk/persistence/GCPersistence.java?rev=1327074&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-mk/src/main/java/org/apache/jackrabbit/mk/persistence/GCPersistence.java (added)
+++ jackrabbit/oak/trunk/oak-mk/src/main/java/org/apache/jackrabbit/mk/persistence/GCPersistence.java Tue Apr 17 12:54:04 2012
@@ -0,0 +1,77 @@
+/*
+ * 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.persistence;
+
+import org.apache.jackrabbit.mk.model.Id;
+
+/**
+ * Advanced persistence implementation offering GC support.
+ * <p>
+ * The persistence implementation must ensure that objects written after {@link #start()}
+ * was invoked are not swept.
+ */
+public interface GCPersistence extends Persistence {
+
+    /**
+     * Start a GC cycle. All objects written to the persistence in subsequent calls are
+     * marked implicitely, i.e. they must be retained on {@link #sweep()}.
+     */
+    void start();
+    
+    /**
+     * Mark a commit.
+     * 
+     * @param id
+     *            commit id
+     * @return <code>true</code> if the commit was not marked before;
+     *         <code>false</code> otherwise
+     * 
+     * @throws Exception if an error occurs
+     */
+    boolean markCommit(Id id) throws Exception;
+    
+    /**
+     * Mark a node.
+     * 
+     * @param id
+     *            node id
+     * @return <code>true</code> if the node was not marked before;
+     *         <code>false</code> otherwise
+     * 
+     * @throws Exception if an error occurs
+     */
+    boolean markNode(Id id) throws Exception;
+
+    /**
+     * Mark a child node entry map.
+     * 
+     * @param id
+     *            child node entry map id
+     * @return <code>true</code> if the child node entry map was not marked before;
+     *         <code>false</code> otherwise
+     * 
+     * @throws Exception if an error occurs
+     */
+    boolean markCNEMap(Id id) throws Exception;
+    
+    /**
+     * Sweep all objects that are not marked and were written before the GC started.
+     * 
+     * @throws Exception if an error occurs
+     */
+    void sweep() throws Exception;
+}

Propchange: jackrabbit/oak/trunk/oak-mk/src/main/java/org/apache/jackrabbit/mk/persistence/GCPersistence.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/oak/trunk/oak-mk/src/main/java/org/apache/jackrabbit/mk/persistence/GCPersistence.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision Rev Url

Modified: jackrabbit/oak/trunk/oak-mk/src/main/java/org/apache/jackrabbit/mk/persistence/H2Persistence.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-mk/src/main/java/org/apache/jackrabbit/mk/persistence/H2Persistence.java?rev=1327074&r1=1327073&r2=1327074&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-mk/src/main/java/org/apache/jackrabbit/mk/persistence/H2Persistence.java (original)
+++ jackrabbit/oak/trunk/oak-mk/src/main/java/org/apache/jackrabbit/mk/persistence/H2Persistence.java Tue Apr 17 12:54:04 2012
@@ -18,12 +18,12 @@ package org.apache.jackrabbit.mk.persist
 
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
-import java.io.Closeable;
 import java.io.File;
 import java.sql.Connection;
 import java.sql.PreparedStatement;
 import java.sql.ResultSet;
 import java.sql.Statement;
+import java.sql.Timestamp;
 
 import org.apache.jackrabbit.mk.model.ChildNodeEntriesMap;
 import org.apache.jackrabbit.mk.model.Commit;
@@ -39,23 +39,19 @@ import org.h2.jdbcx.JdbcConnectionPool;
 /**
  *
  */
-public class H2Persistence implements Persistence, Closeable {
+public class H2Persistence implements GCPersistence {
 
     private static final boolean FAST = Boolean.getBoolean("mk.fastDb");
 
-    private final File homeDir;
     private JdbcConnectionPool cp;
+    private long gcStart;
     
     // TODO: make this configurable
     private IdFactory idFactory = IdFactory.getDigestFactory();
 
-    public H2Persistence(File homeDir) throws Exception {
-        this.homeDir = homeDir;
-    }
-    
     //---------------------------------------------------< Persistence >
 
-    public void initialize() throws Exception {
+    public void initialize(File homeDir) throws Exception {
         File dbDir = new File(homeDir, "db");
         if (!dbDir.exists()) {
             dbDir.mkdirs();
@@ -71,7 +67,7 @@ public class H2Persistence implements Pe
         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 REVS(ID binary primary key, DATA binary, TIME timestamp)");
             stmt.execute("create table if not exists HEAD(ID binary) as select null");
             stmt.execute("create sequence if not exists DATASTORE_ID");
 /*
@@ -149,7 +145,7 @@ public class H2Persistence implements Pe
         try {
             PreparedStatement stmt = con
                     .prepareStatement(
-                            "insert into REVS (ID, DATA) select ?, ? where not exists (select 1 from REVS where ID = ?)");
+                            "insert into REVS (ID, DATA, TIME) select ?, ?, CURRENT_TIMESTAMP() where not exists (select 1 from REVS where ID = ?)");
             try {
                 stmt.setBytes(1, rawId);
                 stmt.setBytes(2, bytes);
@@ -194,7 +190,7 @@ public class H2Persistence implements Pe
         try {
             PreparedStatement stmt = con
                     .prepareStatement(
-                            "insert into REVS (ID, DATA) select ?, ? where not exists (select 1 from REVS where ID = ?)");
+                            "insert into REVS (ID, DATA, TIME) select ?, ?, CURRENT_TIMESTAMP() where not exists (select 1 from REVS where ID = ?)");
             try {
                 stmt.setBytes(1, id.getBytes());
                 stmt.setBytes(2, bytes);
@@ -239,7 +235,7 @@ public class H2Persistence implements Pe
         try {
             PreparedStatement stmt = con
                     .prepareStatement(
-                            "insert into REVS (ID, DATA) select ?, ? where not exists (select 1 from REVS where ID = ?)");
+                            "insert into REVS (ID, DATA, TIME) select ?, ?, CURRENT_TIMESTAMP() where not exists (select 1 from REVS where ID = ?)");
             try {
                 stmt.setBytes(1, rawId);
                 stmt.setBytes(2, bytes);
@@ -253,4 +249,65 @@ public class H2Persistence implements Pe
         }
         return new Id(rawId);
     }
+
+    @Override
+    public void start() {
+        gcStart = System.currentTimeMillis();
+    }
+    
+    @Override
+    public boolean markCommit(Id id) throws Exception {
+        return touch(id, gcStart);
+    }
+
+    @Override
+    public boolean markNode(Id id) throws Exception {
+        return touch(id, gcStart);
+    }
+
+    @Override
+    public boolean markCNEMap(Id id) throws Exception {
+        return touch(id, gcStart);
+    }
+    
+    private boolean touch(Id id, long timeMillis) throws Exception {
+        Timestamp ts = new Timestamp(timeMillis);
+
+        Connection con = cp.getConnection();
+        try {
+            PreparedStatement stmt = con
+                    .prepareStatement(
+                            "update REVS set TIME = ? where ID = ? and TIME < ?");
+            try {
+                stmt.setTimestamp(1, ts);
+                stmt.setBytes(2, id.getBytes());
+                stmt.setTimestamp(3, ts);
+                return stmt.executeUpdate() == 1;
+            } finally {
+                stmt.close();
+            }
+        } finally {
+            con.close();
+        }
+    }
+    
+    @Override
+    public void sweep() throws Exception {
+        Timestamp ts = new Timestamp(gcStart);
+
+        Connection con = cp.getConnection();
+        try {
+            PreparedStatement stmt = con
+                    .prepareStatement(
+                            "delete REVS where TIME < ?");
+            try {
+                stmt.setTimestamp(1, ts);
+                stmt.executeUpdate();
+            } finally {
+                stmt.close();
+            }
+        } finally {
+            con.close();
+        }
+     }
 }
\ No newline at end of file

Modified: jackrabbit/oak/trunk/oak-mk/src/main/java/org/apache/jackrabbit/mk/persistence/InMemPersistence.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-mk/src/main/java/org/apache/jackrabbit/mk/persistence/InMemPersistence.java?rev=1327074&r1=1327073&r2=1327074&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-mk/src/main/java/org/apache/jackrabbit/mk/persistence/InMemPersistence.java (original)
+++ jackrabbit/oak/trunk/oak-mk/src/main/java/org/apache/jackrabbit/mk/persistence/InMemPersistence.java Tue Apr 17 12:54:04 2012
@@ -18,6 +18,7 @@ package org.apache.jackrabbit.mk.persist
 
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
+import java.io.File;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
@@ -35,17 +36,22 @@ import org.apache.jackrabbit.mk.store.No
 /**
  *
  */
-public class InMemPersistence implements Persistence {
+public class InMemPersistence implements GCPersistence {
 
-    private final Map<Id, byte[]> nodes = Collections.synchronizedMap(new HashMap<Id, byte[]>());
-    private final Map<Id, StoredCommit> commits = Collections.synchronizedMap(new HashMap<Id, StoredCommit>());
-    private final Map<Id, ChildNodeEntriesMap> cneMaps = Collections.synchronizedMap(new HashMap<Id, ChildNodeEntriesMap>());
+    private final Map<Id, byte[]> objects = Collections.synchronizedMap(new HashMap<Id, byte[]>());
+    private final Map<Id, byte[]> marked = Collections.synchronizedMap(new HashMap<Id, byte[]>());
 
     private Id head;
+    private long gcStart;
 
     // TODO: make this configurable
     private IdFactory idFactory = IdFactory.getDigestFactory();
     
+    @Override
+    public void initialize(File homeDir) {
+        // nothing to initialize
+    }
+    
     public Id readHead() {
         return head;
     }
@@ -56,12 +62,12 @@ public class InMemPersistence implements
 
     public void readNode(StoredNode node) throws NotFoundException, Exception {
         Id id = node.getId();
-        byte[] bytes = nodes.get(id);
+        byte[] bytes = objects.get(id);
         if (bytes != null) {
             node.deserialize(new BinaryBinding(new ByteArrayInputStream(bytes)));
-        } else {
-            throw new NotFoundException(id.toString());
+            return;
         }
+        throw new NotFoundException(id.toString());
     }
 
     public Id writeNode(Node node) throws Exception {
@@ -70,20 +76,21 @@ public class InMemPersistence implements
         byte[] bytes = out.toByteArray();
         Id id = new Id(idFactory.createContentId(bytes));
 
-        if (!nodes.containsKey(id)) {
-            nodes.put(id, bytes);
+        if (!objects.containsKey(id)) {
+            objects.put(id, bytes);
+        }
+        if (gcStart != 0) {
+            marked.put(id, bytes);
         }
-
         return id;
     }
 
-    public StoredCommit readCommit(Id id) throws NotFoundException {
-        StoredCommit commit = commits.get(id);
-        if (commit != null) {
-            return commit;
-        } else {
-            throw new NotFoundException(id.toString());
+    public StoredCommit readCommit(Id id) throws NotFoundException, Exception {
+        byte[] bytes = objects.get(id);
+        if (bytes != null) {
+            return StoredCommit.deserialize(id, new BinaryBinding(new ByteArrayInputStream(bytes)));
         }
+        throw new NotFoundException(id.toString());
     }
 
     public void writeCommit(Id id, Commit commit) throws Exception {
@@ -91,18 +98,20 @@ public class InMemPersistence implements
         commit.serialize(new BinaryBinding(out));
         byte[] bytes = out.toByteArray();
 
-        if (!commits.containsKey(id)) {
-            commits.put(id, StoredCommit.deserialize(id, new BinaryBinding(new ByteArrayInputStream(bytes))));
+        if (!objects.containsKey(id)) {
+            objects.put(id, bytes);
+        }
+        if (gcStart != 0) {
+            marked.put(id, bytes);
         }
     }
 
-    public ChildNodeEntriesMap readCNEMap(Id id) throws NotFoundException {
-        ChildNodeEntriesMap map = cneMaps.get(id);
-        if (map != null) {
-            return map;
-        } else {
-            throw new NotFoundException(id.toString());
+    public ChildNodeEntriesMap readCNEMap(Id id) throws NotFoundException, Exception {
+        byte[] bytes = objects.get(id);
+        if (bytes != null) {
+            return ChildNodeEntriesMap.deserialize(new BinaryBinding(new ByteArrayInputStream(bytes)));
         }
+        throw new NotFoundException(id.toString());
     }
 
     public Id writeCNEMap(ChildNodeEntriesMap map) throws Exception {
@@ -111,10 +120,54 @@ public class InMemPersistence implements
         byte[] bytes = out.toByteArray();
         Id id = new Id(idFactory.createContentId(bytes));
 
-        if (!cneMaps.containsKey(id)) {
-            cneMaps.put(id, ChildNodeEntriesMap.deserialize(new BinaryBinding(new ByteArrayInputStream(bytes))));
+        if (!objects.containsKey(id)) {
+            objects.put(id, bytes);
+        }
+        if (gcStart != 0) {
+            marked.put(id, bytes);
         }
-
         return id;
     }
+
+    @Override
+    public void close() {
+        // nothing to do here
+    }
+    
+    @Override
+    public void start() {
+        gcStart = System.currentTimeMillis();
+        marked.clear();
+    }
+
+    @Override
+    public boolean markCommit(Id id) throws NotFoundException {
+        return markObject(id);
+    }
+
+    @Override
+    public boolean markNode(Id id) throws NotFoundException {
+        return markObject(id);
+    }
+
+    @Override
+    public boolean markCNEMap(Id id) throws NotFoundException {
+        return markObject(id);
+    }
+    
+    private boolean markObject(Id id) throws NotFoundException {
+        byte[] data = objects.get(id);
+        if (data != null) {
+            return marked.put(id, data) == null;
+        }
+        throw new NotFoundException(id.toString());
+    }
+
+    @Override
+    public void sweep() {
+        objects.clear();
+        objects.putAll(marked);
+        
+        gcStart = 0;
+    }
 }

Modified: jackrabbit/oak/trunk/oak-mk/src/main/java/org/apache/jackrabbit/mk/persistence/MongoPersistence.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-mk/src/main/java/org/apache/jackrabbit/mk/persistence/MongoPersistence.java?rev=1327074&r1=1327073&r2=1327074&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-mk/src/main/java/org/apache/jackrabbit/mk/persistence/MongoPersistence.java (original)
+++ jackrabbit/oak/trunk/oak-mk/src/main/java/org/apache/jackrabbit/mk/persistence/MongoPersistence.java Tue Apr 17 12:54:04 2012
@@ -19,7 +19,6 @@ package org.apache.jackrabbit.mk.persist
 import java.io.BufferedInputStream;
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
-import java.io.Closeable;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.InputStream;
@@ -55,7 +54,7 @@ import com.mongodb.gridfs.GridFSInputFil
 /**
  * 
  */
-public class MongoPersistence implements Persistence, Closeable, BlobStore {
+public class MongoPersistence implements Persistence, BlobStore {
 
     private static final boolean BINARY_FORMAT = false;
 
@@ -76,7 +75,7 @@ public class MongoPersistence implements
     // TODO: make this configurable
     private IdFactory idFactory = IdFactory.getDigestFactory();
     
-    public void initialize() throws Exception {
+    public void initialize(File homeDir) throws Exception {
         con = new Mongo();
         //con = new Mongo("localhost", 27017);
 

Modified: jackrabbit/oak/trunk/oak-mk/src/main/java/org/apache/jackrabbit/mk/persistence/Persistence.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-mk/src/main/java/org/apache/jackrabbit/mk/persistence/Persistence.java?rev=1327074&r1=1327073&r2=1327074&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-mk/src/main/java/org/apache/jackrabbit/mk/persistence/Persistence.java (original)
+++ jackrabbit/oak/trunk/oak-mk/src/main/java/org/apache/jackrabbit/mk/persistence/Persistence.java Tue Apr 17 12:54:04 2012
@@ -16,6 +16,9 @@
  */
 package org.apache.jackrabbit.mk.persistence;
 
+import java.io.Closeable;
+import java.io.File;
+
 import org.apache.jackrabbit.mk.model.ChildNodeEntriesMap;
 import org.apache.jackrabbit.mk.model.Commit;
 import org.apache.jackrabbit.mk.model.Id;
@@ -28,8 +31,10 @@ import org.apache.jackrabbit.mk.store.No
  * Defines the methods exposed by a persistence manager, that stores head
  * revision id, nodes, child node entries and blobs.
  */
-public interface Persistence {
+public interface Persistence extends Closeable {
 
+    public void initialize(File homeDir) throws Exception;
+    
     Id readHead() throws Exception;
 
     void writeHead(Id id) throws Exception;

Modified: jackrabbit/oak/trunk/oak-mk/src/main/java/org/apache/jackrabbit/mk/store/DefaultRevisionStore.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-mk/src/main/java/org/apache/jackrabbit/mk/store/DefaultRevisionStore.java?rev=1327074&r1=1327073&r2=1327074&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-mk/src/main/java/org/apache/jackrabbit/mk/store/DefaultRevisionStore.java (original)
+++ jackrabbit/oak/trunk/oak-mk/src/main/java/org/apache/jackrabbit/mk/store/DefaultRevisionStore.java Tue Apr 17 12:54:04 2012
@@ -89,9 +89,9 @@ public class DefaultRevisionStore extend
         verifyInitialized();
 
         cache.clear();
-        if (pm instanceof Closeable) {
-            IOUtils.closeQuietly((Closeable) pm);
-        }
+
+        IOUtils.closeQuietly((Closeable) pm);
+
         initialized = false;
     }
 

Added: jackrabbit/oak/trunk/oak-mk/src/test/java/org/apache/jackrabbit/mk/persistence/GCPersistenceTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-mk/src/test/java/org/apache/jackrabbit/mk/persistence/GCPersistenceTest.java?rev=1327074&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-mk/src/test/java/org/apache/jackrabbit/mk/persistence/GCPersistenceTest.java (added)
+++ jackrabbit/oak/trunk/oak-mk/src/test/java/org/apache/jackrabbit/mk/persistence/GCPersistenceTest.java Tue Apr 17 12:54:04 2012
@@ -0,0 +1,138 @@
+/*
+ * 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.persistence;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.File;
+import java.util.Arrays;
+import java.util.Collection;
+
+import org.apache.jackrabbit.mk.model.Id;
+import org.apache.jackrabbit.mk.model.MutableNode;
+import org.apache.jackrabbit.mk.model.StoredNode;
+import org.apache.jackrabbit.mk.store.NotFoundException;
+import org.apache.jackrabbit.mk.util.IOUtils;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+/**
+ * Tests verifying the contract provided by {@link GCPersistence}.
+ */
+@RunWith(value = Parameterized.class)
+public class GCPersistenceTest {
+
+    private Class<GCPersistence> pmClass;
+    private GCPersistence pm;
+    
+    public GCPersistenceTest(Class<GCPersistence> pmClass) {
+        this.pmClass = pmClass;
+    }
+    
+    @Before
+    public void setup() throws Exception {
+        pm = pmClass.newInstance();
+        pm.initialize(new File("target/mk"));
+        
+        // start with empty repository
+        pm.start();
+        pm.sweep();
+    }
+    
+    @SuppressWarnings("rawtypes")
+    @Parameters
+    public static Collection classes() {
+        Class[][] pmClasses = new Class[][] {
+                { H2Persistence.class },
+                { InMemPersistence.class }
+        };
+        return Arrays.asList(pmClasses);
+    }
+    
+    @After
+    public void tearDown() throws Exception {
+        IOUtils.closeQuietly(pm);
+    }
+
+    @Test
+    public void testOldNodeIsSwept() throws Exception {
+        MutableNode node = new MutableNode(null, "/");
+        Id id = pm.writeNode(node);
+
+        pm.start();
+        pm.sweep();
+        
+        try {
+            pm.readNode(new StoredNode(id, null));
+            fail();
+        } catch (NotFoundException e) {
+            /* expected */
+        }
+    }
+
+    @Test
+    public void testMarkedNodeIsNotSwept() throws Exception {
+        MutableNode node = new MutableNode(null, "/");
+        Id id = pm.writeNode(node);
+
+        pm.start();
+        pm.markNode(id);
+        pm.sweep();
+        
+        pm.readNode(new StoredNode(id, null));
+    }
+
+    @Test
+    public void testOldNodeIsUnmarked() throws Exception {
+        MutableNode node = new MutableNode(null, "/");
+        Id id = pm.writeNode(node);
+        
+        // small delay needed
+        Thread.sleep(100);
+        
+        pm.start();
+        assertTrue(pm.markNode(id));
+    }
+    
+    @Test
+    public void testNewNodeIsMarked() throws Exception {
+        pm.start();
+        
+        MutableNode node = new MutableNode(null, "/");
+        Id id = pm.writeNode(node);
+        
+        assertFalse(pm.markNode(id));
+    }
+
+    @Test
+    public void testNewNodeIsNotSwept() throws Exception {
+        pm.start();
+        
+        MutableNode node = new MutableNode(null, "/");
+        Id id = pm.writeNode(node);
+        
+        pm.sweep();
+        pm.readNode(new StoredNode(id, null));
+    }
+}
+

Propchange: jackrabbit/oak/trunk/oak-mk/src/test/java/org/apache/jackrabbit/mk/persistence/GCPersistenceTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/oak/trunk/oak-mk/src/test/java/org/apache/jackrabbit/mk/persistence/GCPersistenceTest.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision Rev Url

Modified: jackrabbit/oak/trunk/oak-mk/src/test/java/org/apache/jackrabbit/mk/store/CopyingGCTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-mk/src/test/java/org/apache/jackrabbit/mk/store/CopyingGCTest.java?rev=1327074&r1=1327073&r2=1327074&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-mk/src/test/java/org/apache/jackrabbit/mk/store/CopyingGCTest.java (original)
+++ jackrabbit/oak/trunk/oak-mk/src/test/java/org/apache/jackrabbit/mk/store/CopyingGCTest.java Tue Apr 17 12:54:04 2012
@@ -33,9 +33,6 @@ import org.junit.Before;
 import org.junit.Ignore;
 import org.junit.Test;
 
-import java.io.File;
-import java.io.IOException;
-
 /**
  * Use-case: start off a new revision store that contains just the head revision
  * and its nodes.