Author: chetanm
Date: Thu Mar 27 15:20:19 2014
New Revision: 1582348
URL: http://svn.apache.org/r1582348
Log:
OAK-1341 - DocumentNodeStore: Implement revision garbage collection (WIP)
Support for gc of deleted nodes
-- Mark docs once deleted with a flag
-- Created an index on _deletedOnce flag
-- Updated test fixture for easier use
Added:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/VersionGCSupport.java
(with props)
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoVersionGCSupport.java
(with props)
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/util/CloseableIterable.java
(with props)
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/NodeDocument.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/VersionGarbageCollector.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoDocumentStore.java
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentStoreFixture.java
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/VersionGarbageCollectorTest.java
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/NodeDocument.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/NodeDocument.java?rev=1582348&r1=1582347&r2=1582348&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/NodeDocument.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/NodeDocument.java
Thu Mar 27 15:20:19 2014
@@ -69,6 +69,18 @@ public final class NodeDocument extends
static final Logger LOG = LoggerFactory.getLogger(NodeDocument.class);
/**
+ * All NodeDocument ID value would be greater than this value
+ * It can be used as startKey in DocumentStore#query methods
+ */
+ public static final String MIN_ID_VALUE = "0000000";
+
+ /**
+ * All NodeDocument ID value would be less than this value
+ * It can be used as endKey in DocumentStore#query methods
+ */
+ public static final String MAX_ID_VALUE = ";";
+
+ /**
* A size threshold after which to consider a document a split candidate.
* TODO: check which value is the best one
*/
@@ -137,6 +149,16 @@ public final class NodeDocument extends
private static final String DELETED = "_deleted";
/**
+ * Flag indicating that whether this node was ever deleted.
+ * Its just used as a hint. If set to true then it indicates that
+ * node was once deleted.
+ *
+ * <p>Note that a true value does not mean that node should be considered
+ * deleted as it might have been resurrected in later revision</p>
+ */
+ public static final String DELETED_ONCE = "_deletedOnce";
+
+ /**
* The list of recent revisions for this node, where this node is the
* root of the commit.
* <p>
@@ -177,7 +199,7 @@ public final class NodeDocument extends
*/
private static final Set<String> IGNORE_ON_SPLIT = ImmutableSet.of(
ID, MOD_COUNT, MODIFIED, PREVIOUS, LAST_REV, CHILDREN_FLAG,
- HAS_BINARY_FLAG, PATH);
+ HAS_BINARY_FLAG, PATH, DELETED_ONCE);
public static final long HAS_BINARY_VAL = 1;
@@ -238,7 +260,9 @@ public final class NodeDocument extends
}
/**
- * @return the approximate number of children for this node.
+ * Returns <tt>true</tt> if this node possibly has children
+ *
+ * @return <tt>true</tt> if this node has children
*/
public boolean hasChildren() {
Boolean childrenFlag = (Boolean) get(CHILDREN_FLAG);
@@ -246,6 +270,26 @@ public final class NodeDocument extends
}
/**
+ * Returns <tt>true</tt> if this document was ever deleted in past.
+ */
+ public boolean wasDeletedOnce() {
+ Boolean deletedOnceFlag = (Boolean) get(DELETED_ONCE);
+ return deletedOnceFlag != null && deletedOnceFlag;
+ }
+
+ /**
+ * Checks if this document has been modified after the given
lastModifiedTime
+ *
+ * @param lastModifiedTime time to compare against
+ * @return <tt>true</tt> if this document was modified after the given
+ * lastModifiedTime
+ */
+ public boolean hasBeenModifiedSince(long lastModifiedTime){
+ Long modified = (Long) get(MODIFIED);
+ return modified != null && modified > lastModifiedTime;
+ }
+
+ /**
* Mark this instance as up-to-date (matches the state in persistence
* store).
*
@@ -912,6 +956,8 @@ public final class NodeDocument extends
Revision r = input.getKey();
int h = input.getValue().height;
String prevId = Utils.getPreviousIdFor(mainPath, r, h);
+ //TODO Use the maxAge variant such that in case of
Mongo call for
+ //previous doc are directed towards replicas first
NodeDocument prev = store.find(Collection.NODES,
prevId);
if (prev != null) {
return prev;
@@ -930,6 +976,38 @@ public final class NodeDocument extends
}
}
+ @Nonnull
+ Iterable<NodeDocument> getAllPreviousDocs() {
+ if (getPreviousRanges().isEmpty()) {
+ return Collections.emptyList();
+ }
+ final String mainPath = getMainPath();
+ return filter(transform(getPreviousRanges().entrySet(),
+ new Function<Map.Entry<Revision, Range>, NodeDocument>() {
+ @Override
+ public NodeDocument apply(Map.Entry<Revision, Range>
input) {
+ Revision r = input.getKey();
+ int h = input.getValue().height;
+ String prevId = Utils.getPreviousIdFor(mainPath, r, h);
+ //TODO Use the maxAge variant such that in case of
Mongo call for
+ //previous doc are directed towards replicas first
+ NodeDocument prev = store.find(Collection.NODES,
prevId);
+ if (prev != null) {
+ return prev;
+ } else {
+ LOG.warn("Document with previous revisions not
found: " + prevId);
+ }
+ return null;
+ }
+ }
+ ), new Predicate<NodeDocument>() {
+ @Override
+ public boolean apply(@Nullable NodeDocument input) {
+ return input != null;
+ }
+ });
+ }
+
/**
* Returns the local value map for the given key.
*
@@ -1034,6 +1112,11 @@ public final class NodeDocument extends
public static void setDeleted(@Nonnull UpdateOp op,
@Nonnull Revision revision,
boolean deleted) {
+ if(deleted) {
+ //DELETED_ONCE would be set upon every delete.
+ //possibly we can avoid that
+ checkNotNull(op).set(DELETED_ONCE, Boolean.TRUE);
+ }
checkNotNull(op).setMapEntry(DELETED, checkNotNull(revision),
String.valueOf(deleted));
}
Added:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/VersionGCSupport.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/VersionGCSupport.java?rev=1582348&view=auto
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/VersionGCSupport.java
(added)
+++
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/VersionGCSupport.java
Thu Mar 27 15:20:19 2014
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.jackrabbit.oak.plugins.document;
+
+import java.util.List;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterables;
+
+public class VersionGCSupport {
+ private final DocumentStore store;
+
+ public VersionGCSupport(DocumentStore store) {
+ this.store = store;
+ }
+
+ public Iterable<NodeDocument> getPossiblyDeletedDocs(final long
lastModifiedTime) {
+ //Fetch all documents.
+ List<NodeDocument> nodes =
store.query(Collection.NODES,NodeDocument.MIN_ID_VALUE,
+ NodeDocument.MAX_ID_VALUE, Integer.MAX_VALUE);
+ return Iterables.filter(nodes, new Predicate<NodeDocument>() {
+ @Override
+ public boolean apply(NodeDocument input) {
+ return input.wasDeletedOnce() &&
!input.hasBeenModifiedSince(lastModifiedTime);
+ }
+ });
+ }
+}
Propchange:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/VersionGCSupport.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/VersionGarbageCollector.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/VersionGarbageCollector.java?rev=1582348&r1=1582347&r2=1582348&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/VersionGarbageCollector.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/VersionGarbageCollector.java
Thu Mar 27 15:20:19 2014
@@ -19,13 +19,20 @@
package org.apache.jackrabbit.oak.plugins.document;
+import java.io.Closeable;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
import java.util.concurrent.TimeUnit;
+import org.apache.jackrabbit.oak.plugins.document.mongo.MongoDocumentStore;
+import org.apache.jackrabbit.oak.plugins.document.mongo.MongoVersionGCSupport;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
class VersionGarbageCollector {
private final DocumentNodeStore nodeStore;
+ private final VersionGCSupport versionStore;
private final Logger log = LoggerFactory.getLogger(getClass());
@@ -33,31 +40,76 @@ class VersionGarbageCollector {
VersionGarbageCollector(DocumentNodeStore nodeStore) {
this.nodeStore = nodeStore;
+
+ if(nodeStore.getDocumentStore() instanceof MongoDocumentStore){
+ this.versionStore =
+ new MongoVersionGCSupport((MongoDocumentStore)
nodeStore.getDocumentStore());
+ }else {
+ this.versionStore = new
VersionGCSupport(nodeStore.getDocumentStore());
+ }
}
public VersionGCStats gc() {
VersionGCStats stats = new VersionGCStats();
- long oldestRevTimeStamp = nodeStore.getClock().getTime() -
maxRevisionAge;
+ final long oldestRevTimeStamp = nodeStore.getClock().getTime() -
maxRevisionAge;
+ final Revision headRevision = nodeStore.getHeadRevision();
//Check for any registered checkpoint which prevent the GC from running
Revision checkpoint =
nodeStore.getCheckpoints().getOldestRevisionToKeep();
if (checkpoint != null && checkpoint.getTimestamp() <
oldestRevTimeStamp) {
log.info("Ignoring version gc as valid checkpoint [{}] found while
" +
"need to collect versions older than [{}]",
checkpoint.toReadableString(),
- oldestRevTimeStamp
+ Revision.timestampToString(oldestRevTimeStamp)
);
stats.ignoredGCDueToCheckPoint = true;
return stats;
}
+ collectDeletedDocuments(stats, headRevision, oldestRevTimeStamp);
+
return stats;
}
+ private void collectDeletedDocuments(VersionGCStats stats, Revision
headRevision, long oldestRevTimeStamp) {
+ List<String> docIdsToDelete = new ArrayList<String>();
+ Iterable<NodeDocument> itr =
versionStore.getPossiblyDeletedDocs(oldestRevTimeStamp);
+ try {
+ for (NodeDocument doc : itr) {
+ //Check if node is actually deleted at current revision
+ //As node is not modified since oldestRevTimeStamp then
+ //this node has not be revived again in past maxRevisionAge
+ //So deleting it is safe
+ if (doc.getNodeAtRevision(nodeStore, headRevision, null) ==
null) {
+ docIdsToDelete.add(doc.getId());
+ //Collect id of all previous docs also
+ for (NodeDocument prevDoc : doc.getAllPreviousDocs()) {
+ docIdsToDelete.add(prevDoc.getId());
+ }
+ }
+ }
+ } finally {
+ close(itr);
+ }
+ nodeStore.getDocumentStore().remove(Collection.NODES, docIdsToDelete);
+ stats.deletedDocCount += docIdsToDelete.size();
+ }
+
public void setMaxRevisionAge(long maxRevisionAge) {
this.maxRevisionAge = maxRevisionAge;
}
public static class VersionGCStats {
boolean ignoredGCDueToCheckPoint;
+ int deletedDocCount;
+ }
+
+ private void close(Object obj){
+ if(obj instanceof Closeable){
+ try{
+ ((Closeable) obj).close();
+ } catch (IOException e) {
+ log.warn("Error occurred while closing", e);
+ }
+ }
}
}
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoDocumentStore.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoDocumentStore.java?rev=1582348&r1=1582347&r2=1582348&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoDocumentStore.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoDocumentStore.java
Thu Mar 27 15:20:19 2014
@@ -139,6 +139,14 @@ public class MongoDocumentStore implemen
options.put("sparse", Boolean.TRUE);
this.nodes.ensureIndex(index, options);
+ index = new BasicDBObject();
+ index.put(NodeDocument.DELETED_ONCE, 1);
+ options = new BasicDBObject();
+ options.put("unique", Boolean.FALSE);
+ options.put("sparse", Boolean.TRUE);
+ this.nodes.ensureIndex(index, options);
+
+
// TODO expire entries if the parent was changed
if (builder.useOffHeapCache()) {
nodesCache = createOffHeapCache(builder);
Added:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoVersionGCSupport.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoVersionGCSupport.java?rev=1582348&view=auto
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoVersionGCSupport.java
(added)
+++
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoVersionGCSupport.java
Thu Mar 27 15:20:19 2014
@@ -0,0 +1,61 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.jackrabbit.oak.plugins.document.mongo;
+
+import com.google.common.base.Function;
+import com.mongodb.DBCollection;
+import com.mongodb.DBCursor;
+import com.mongodb.DBObject;
+import com.mongodb.QueryBuilder;
+import org.apache.jackrabbit.oak.plugins.document.Collection;
+import org.apache.jackrabbit.oak.plugins.document.NodeDocument;
+import org.apache.jackrabbit.oak.plugins.document.VersionGCSupport;
+import org.apache.jackrabbit.oak.plugins.document.util.CloseableIterable;
+
+import static com.google.common.collect.Iterables.transform;
+
+public class MongoVersionGCSupport extends VersionGCSupport {
+ private final MongoDocumentStore store;
+
+ public MongoVersionGCSupport(MongoDocumentStore store) {
+ super(store);
+ this.store = store;
+ }
+
+ @Override
+ public CloseableIterable<NodeDocument> getPossiblyDeletedDocs(final long
lastModifiedTime) {
+ //_deletedOnce == true && _modified < lastModifiedTime
+ DBObject query = QueryBuilder
+
.start(NodeDocument.DELETED_ONCE).is(Boolean.TRUE)
+
.put(NodeDocument.MODIFIED).lessThan(lastModifiedTime)
+ .get();
+ DBCursor cursor = getNodeCollection().find(query);
+ return CloseableIterable.wrap(transform(cursor, new Function<DBObject,
NodeDocument>() {
+ @Override
+ public NodeDocument apply(DBObject input) {
+ return store.convertFromDBObject(Collection.NODES, input);
+ }
+ }), cursor);
+ }
+
+ private DBCollection getNodeCollection(){
+ return store.getDBCollection(Collection.NODES);
+ }
+}
Propchange:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoVersionGCSupport.java
------------------------------------------------------------------------------
svn:eol-style = native
Added:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/util/CloseableIterable.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/util/CloseableIterable.java?rev=1582348&view=auto
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/util/CloseableIterable.java
(added)
+++
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/util/CloseableIterable.java
Thu Mar 27 15:20:19 2014
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.jackrabbit.oak.plugins.document.util;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.util.Iterator;
+
+public class CloseableIterable<T> implements Iterable<T>, Closeable {
+ private final Iterable<T> iterable;
+ private final Closeable closeable;
+
+ public static <T> CloseableIterable<T> wrap(Iterable<T> iterable,
Closeable closeable){
+ return new CloseableIterable<T>(iterable, closeable);
+ }
+
+ public CloseableIterable(Iterable<T> iterable, Closeable closeable) {
+ this.iterable = iterable;
+ this.closeable = closeable;
+ }
+
+ @Override
+ public void close() throws IOException {
+ closeable.close();
+ }
+
+ @Override
+ public Iterator<T> iterator() {
+ return iterable.iterator();
+ }
+}
Propchange:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/util/CloseableIterable.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified:
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentStoreFixture.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentStoreFixture.java?rev=1582348&r1=1582347&r2=1582348&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentStoreFixture.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentStoreFixture.java
Thu Mar 27 15:20:19 2014
@@ -46,7 +46,9 @@ public abstract class DocumentStoreFixtu
return true;
}
- private static class MemoryFixture extends DocumentStoreFixture {
+ public void dispose() throws Exception {}
+
+ public static class MemoryFixture extends DocumentStoreFixture {
DocumentStore ds = new MemoryDocumentStore();
@@ -61,7 +63,7 @@ public abstract class DocumentStoreFixtu
}
}
- private static class RDBFixture extends DocumentStoreFixture {
+ public static class RDBFixture extends DocumentStoreFixture {
DocumentStore ds;
String name;
@@ -92,17 +94,22 @@ public abstract class DocumentStoreFixtu
}
}
- private static class MongoFixture extends DocumentStoreFixture {
+ public static class MongoFixture extends DocumentStoreFixture {
+ public static final String DEFAULT_URI =
"mongodb://localhost:27017/oak-test";
+ private DocumentStore ds;
+ private DB mongoDB;
- DocumentStore ds;
+ public MongoFixture(){
+ this(DEFAULT_URI);
+ }
- public MongoFixture(String db) {
+ public MongoFixture(String dbUri) {
try {
- MongoConnection connection = new MongoConnection(db);
- DB mongoDB = connection.getDB();
+ MongoConnection connection = new MongoConnection(dbUri);
+ this.mongoDB = connection.getDB();
this.ds = new MongoDocumentStore(mongoDB, new
DocumentMK.Builder());
} catch (Exception e) {
- LOG.info("Mongo instance not available at " + db + ", skipping
tests...");
+ LOG.trace("Mongo instance not available at " + dbUri + ",
skipping tests...");
}
}
@@ -120,5 +127,10 @@ public abstract class DocumentStoreFixtu
public boolean isAvailable() {
return this.ds != null;
}
+
+ @Override
+ public void dispose() throws Exception {
+ mongoDB.dropDatabase();
+ }
}
}
Modified:
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/VersionGarbageCollectorTest.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/VersionGarbageCollectorTest.java?rev=1582348&r1=1582347&r2=1582348&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/VersionGarbageCollectorTest.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/VersionGarbageCollectorTest.java
Thu Mar 27 15:20:19 2014
@@ -19,31 +19,71 @@
package org.apache.jackrabbit.oak.plugins.document;
+import java.io.IOException;
+import java.util.*;
+import java.util.Collection;
+
import static
org.apache.jackrabbit.oak.plugins.document.VersionGarbageCollector.VersionGCStats;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import com.google.common.collect.Lists;
+import org.apache.jackrabbit.oak.spi.commit.CommitInfo;
+import org.apache.jackrabbit.oak.spi.commit.EmptyHook;
+import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
import org.apache.jackrabbit.oak.stats.Clock;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+@RunWith(Parameterized.class)
public class VersionGarbageCollectorTest {
+
+ private DocumentStoreFixture fixture;
+
private Clock clock;
private DocumentNodeStore store;
private VersionGarbageCollector gc;
+ public VersionGarbageCollectorTest(DocumentStoreFixture fixture) {
+ this.fixture = fixture;
+ }
+
+ @Parameterized.Parameters
+ public static Collection<Object[]> fixtures() throws IOException {
+ List<Object[]> fixtures = Lists.newArrayList();
+ fixtures.add(new Object[] {new DocumentStoreFixture.MemoryFixture()});
+
+ DocumentStoreFixture mongo = new DocumentStoreFixture.MongoFixture();
+ if(mongo.isAvailable()){
+ fixtures.add(new Object[] {mongo});
+ }
+ return fixtures;
+ }
+
@Before
public void setUp() throws InterruptedException {
clock = new Clock.Virtual();
- store = new DocumentMK.Builder().clock(clock).getNodeStore();
+ store = new DocumentMK.Builder()
+ .clock(clock)
+ .setDocumentStore(fixture.getDocumentStore())
+ .getNodeStore();
gc = store.getVersionGarbageCollector();
//Baseline the clock
clock.waitUntil(Revision.getCurrentTimestamp());
}
+ @After
+ public void tearDown() throws Exception {
+ fixture.dispose();
+ }
+
@Test
public void gcIgnoredForCheckpoint() throws Exception {
long expiryTime = 100, maxAge = 20;
@@ -61,4 +101,37 @@ public class VersionGarbageCollectorTest
stats = gc.gc();
assertFalse("GC should be performed", stats.ignoredGCDueToCheckPoint);
}
+
+ @Test
+ public void testGCDeletedDocument() throws Exception{
+ //1. Create nodes
+ NodeBuilder b1 = store.getRoot().builder();
+ b1.child("x").child("y");
+ b1.child("z");
+ store.merge(b1, EmptyHook.INSTANCE, CommitInfo.EMPTY);
+
+ int maxAge = 10000, delta = maxAge;
+ gc.setMaxRevisionAge(maxAge);
+ //Go past GC age and check no GC done as nothing deleted
+ clock.waitUntil(Revision.getCurrentTimestamp() + maxAge);
+ VersionGCStats stats = gc.gc();
+ assertEquals(0, stats.deletedDocCount);
+
+ //Remove x/y
+ NodeBuilder b2 = store.getRoot().builder();
+ b2.child("x").child("y").remove();
+ store.merge(b2, EmptyHook.INSTANCE, CommitInfo.EMPTY);
+ clock.waitUntil(Revision.getCurrentTimestamp() + maxAge + delta);
+
+ stats = gc.gc();
+ assertEquals(1, stats.deletedDocCount);
+
+ //TODO Add test scenario for deletion along with previous docs
+ }
+
+
+ @Test
+ public void sample() throws Exception{
+
+ }
}
\ No newline at end of file