use of org.apache.jackrabbit.oak.plugins.document.VersionGarbageCollector.VersionGCStats in project jackrabbit-oak by apache.
the class VersionGCDeletionTest method gcForPreviousDocs.
@Test
public void gcForPreviousDocs() throws Exception {
DocumentStore ts = new MemoryDocumentStore();
store = new DocumentMK.Builder().clock(clock).setDocumentStore(ts).setAsyncDelay(0).getNodeStore();
NodeBuilder b1;
NodeBuilder xb;
// Create/remove "/x/split" sufficient times to split it
boolean create = true;
for (int i = 0; create || i < NodeDocument.NUM_REVS_THRESHOLD; i++) {
b1 = store.getRoot().builder();
xb = b1.child("x").child("split");
if (!create) {
xb.remove();
}
store.merge(b1, EmptyHook.INSTANCE, CommitInfo.EMPTY);
create = !create;
}
store.runBackgroundOperations();
// Count split docs
NodeDocument doc = ts.find(Collection.NODES, "2:/x/split");
int splitDocCount = Iterators.size(doc.getAllPreviousDocs());
// hours
long maxAge = 1;
long delta = TimeUnit.MINUTES.toMillis(10);
// Remove "/x"
NodeBuilder b2 = store.getRoot().builder();
b2.child("x").remove();
store.merge(b2, EmptyHook.INSTANCE, CommitInfo.EMPTY);
store.runBackgroundOperations();
// Pass some time and run GC
clock.waitUntil(clock.getTime() + HOURS.toMillis(maxAge * 2) + delta);
VersionGarbageCollector gc = store.getVersionGarbageCollector();
VersionGCStats stats = gc.gc(maxAge * 2, HOURS);
// Asset GC stats
assertEquals(2, stats.deletedDocGCCount);
assertEquals(splitDocCount, stats.splitDocGCCount);
// check if the deleted docs are really gone after GC
assertNull(ts.find(Collection.NODES, "1:/x"));
assertNull(ts.find(Collection.NODES, "2:/x/split"));
}
use of org.apache.jackrabbit.oak.plugins.document.VersionGarbageCollector.VersionGCStats in project jackrabbit-oak by apache.
the class VersionGCDeletionTest method queryWhileDocsAreRemoved.
// OAK-2420
@Test
public void queryWhileDocsAreRemoved() throws Exception {
final Thread currentThread = Thread.currentThread();
final Semaphore queries = new Semaphore(0);
final CountDownLatch ready = new CountDownLatch(1);
MemoryDocumentStore ms = new MemoryDocumentStore() {
@Nonnull
@Override
public <T extends Document> List<T> query(Collection<T> collection, String fromKey, String toKey, int limit) {
if (collection == Collection.NODES && Thread.currentThread() != currentThread) {
ready.countDown();
queries.acquireUninterruptibly();
}
return super.query(collection, fromKey, toKey, limit);
}
};
store = new DocumentMK.Builder().clock(clock).setDocumentStore(ms).setAsyncDelay(0).getNodeStore();
// create nodes
NodeBuilder builder = store.getRoot().builder();
NodeBuilder node = builder.child("node");
for (int i = 0; i < 200; i++) {
node.child("c-" + i);
}
merge(store, builder);
clock.waitUntil(clock.getTime() + HOURS.toMillis(1));
// remove nodes
builder = store.getRoot().builder();
node = builder.child("node");
for (int i = 0; i < 90; i++) {
node.getChildNode("c-" + i).remove();
}
merge(store, builder);
store.runBackgroundOperations();
clock.waitUntil(clock.getTime() + HOURS.toMillis(1));
List<String> expected = Lists.newArrayList();
// fill caches
NodeState n = store.getRoot().getChildNode("node");
for (ChildNodeEntry entry : n.getChildNodeEntries()) {
expected.add(entry.getName());
}
assertEquals(110, expected.size());
// invalidate the nodeChildren cache only
store.invalidateNodeChildrenCache();
Future<List<String>> f = newSingleThreadExecutor().submit(new Callable<List<String>>() {
@Override
public List<String> call() throws Exception {
List<String> names = Lists.newArrayList();
NodeState n = store.getRoot().getChildNode("node");
for (ChildNodeEntry entry : n.getChildNodeEntries()) {
names.add(entry.getName());
}
return names;
}
});
// run GC once the reader thread is collecting documents
ready.await();
VersionGarbageCollector gc = store.getVersionGarbageCollector();
VersionGCStats stats = gc.gc(30, MINUTES);
assertEquals(90, stats.deletedDocGCCount);
assertEquals(90, stats.deletedLeafDocGCCount);
queries.release(2);
List<String> names = f.get();
assertEquals(expected, names);
}
use of org.apache.jackrabbit.oak.plugins.document.VersionGarbageCollector.VersionGCStats in project jackrabbit-oak by apache.
the class VersionGarbageCollectorIT method malformedId.
// OAK-4819
@Test
public void malformedId() throws Exception {
// hrs
long maxAge = 1;
long delta = TimeUnit.MINUTES.toMillis(10);
NodeBuilder builder = store.getRoot().builder();
builder.child("foo");
store.merge(builder, EmptyHook.INSTANCE, CommitInfo.EMPTY);
// remove again
builder = store.getRoot().builder();
builder.child("foo").remove();
store.merge(builder, EmptyHook.INSTANCE, CommitInfo.EMPTY);
store.runBackgroundOperations();
// add a document with a malformed id
String id = "42";
UpdateOp op = new UpdateOp(id, true);
NodeDocument.setDeletedOnce(op);
NodeDocument.setModified(op, store.newRevision());
store.getDocumentStore().create(NODES, Lists.newArrayList(op));
clock.waitUntil(clock.getTime() + HOURS.toMillis(maxAge) + delta);
// gc must not fail
VersionGCStats stats = gc.gc(maxAge, HOURS);
assertEquals(1, stats.deletedDocGCCount);
assertEquals(1, stats.deletedLeafDocGCCount);
}
use of org.apache.jackrabbit.oak.plugins.document.VersionGarbageCollector.VersionGCStats in project jackrabbit-oak by apache.
the class VersionGarbageCollectorIT method gcWithConcurrentModification.
// OAK-2778
@Test
public void gcWithConcurrentModification() throws Exception {
Revision.setClock(clock);
DocumentStore ds = store.getDocumentStore();
// create test content
createTestNode("foo");
createTestNode("bar");
// remove again
NodeBuilder builder = store.getRoot().builder();
builder.getChildNode("foo").remove();
builder.getChildNode("bar").remove();
merge(store, builder);
// wait one hour
clock.waitUntil(clock.getTime() + HOURS.toMillis(1));
final BlockingQueue<NodeDocument> docs = Queues.newSynchronousQueue();
VersionGCSupport gcSupport = new VersionGCSupport(store.getDocumentStore()) {
@Override
public Iterable<NodeDocument> getPossiblyDeletedDocs(long fromModified, long toModified) {
return filter(super.getPossiblyDeletedDocs(fromModified, toModified), new Predicate<NodeDocument>() {
@Override
public boolean apply(NodeDocument input) {
try {
docs.put(input);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return true;
}
});
}
};
final VersionGarbageCollector gc = new VersionGarbageCollector(store, gcSupport);
// start GC -> will try to remove /foo and /bar
Future<VersionGCStats> f = execService.submit(new Callable<VersionGCStats>() {
@Override
public VersionGCStats call() throws Exception {
return gc.gc(30, MINUTES);
}
});
NodeDocument doc = docs.take();
String name = PathUtils.getName(doc.getPath());
// recreate node, which hasn't been removed yet
name = name.equals("foo") ? "bar" : "foo";
builder = store.getRoot().builder();
builder.child(name);
merge(store, builder);
// loop over child node entries -> will populate nodeChildrenCache
for (ChildNodeEntry cne : store.getRoot().getChildNodeEntries()) {
cne.getName();
}
// invalidate cached DocumentNodeState
DocumentNodeState state = (DocumentNodeState) store.getRoot().getChildNode(name);
store.invalidateNodeCache(state.getPath(), store.getRoot().getLastRevision());
while (!f.isDone()) {
docs.poll();
}
// read children again after GC finished
List<String> names = Lists.newArrayList();
for (ChildNodeEntry cne : store.getRoot().getChildNodeEntries()) {
names.add(cne.getName());
}
assertEquals(1, names.size());
doc = ds.find(NODES, Utils.getIdFromPath("/" + names.get(0)));
assertNotNull(doc);
assertEquals(0, Iterators.size(doc.getAllPreviousDocs()));
VersionGCStats stats = f.get();
assertEquals(1, stats.deletedDocGCCount);
assertEquals(2, stats.splitDocGCCount);
assertEquals(0, stats.deletedLeafDocGCCount);
}
use of org.apache.jackrabbit.oak.plugins.document.VersionGarbageCollector.VersionGCStats in project jackrabbit-oak by apache.
the class VersionGarbageCollectorIT method gcWithOldSweepRev.
@Test
public void gcWithOldSweepRev() throws Exception {
// hrs
long maxAge = 1;
long delta = TimeUnit.MINUTES.toMillis(10);
NodeBuilder builder = store.getRoot().builder();
builder.child("foo").child("bar");
merge(store, builder);
String value = "";
for (int i = 0; i < NUM_REVS_THRESHOLD; i++) {
builder = store.getRoot().builder();
value = "v" + i;
builder.child("foo").setProperty("prop", value);
merge(store, builder);
}
// trigger split of /foo
store.runBackgroundUpdateOperations();
// now /foo must have previous docs
NodeDocument doc = getDoc("/foo");
List<NodeDocument> prevDocs = ImmutableList.copyOf(doc.getAllPreviousDocs());
assertEquals(1, prevDocs.size());
assertEquals(SplitDocType.DEFAULT_NO_BRANCH, prevDocs.get(0).getSplitDocType());
clock.waitUntil(clock.getTime() + HOURS.toMillis(maxAge) + delta);
// revision gc must not collect previous doc because sweep did not run
VersionGCStats stats = gc.gc(maxAge, HOURS);
assertEquals(0, stats.splitDocGCCount);
// write something to make sure sweep rev is after the split revs
// otherwise GC won't collect the split doc
builder = store.getRoot().builder();
builder.child("qux");
merge(store, builder);
// run full background operations with sweep
clock.waitUntil(clock.getTime() + TimeUnit.SECONDS.toMillis(NodeDocument.MODIFIED_IN_SECS_RESOLUTION * 2));
store.runBackgroundOperations();
// now sweep rev must be updated and revision GC can collect prev doc
stats = gc.gc(maxAge, HOURS);
assertEquals(1, stats.splitDocGCCount);
doc = getDoc("/foo");
assertNotNull(doc);
prevDocs = ImmutableList.copyOf(doc.getAllPreviousDocs());
assertEquals(0, prevDocs.size());
// check value
assertEquals(value, store.getRoot().getChildNode("foo").getString("prop"));
}
Aggregations