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 st...@apache.org on 2024/04/02 14:09:29 UTC
(jackrabbit-oak) 01/01: OAK-10535 : unignored lateWriteRemoveChildGC_noSweep
This is an automated email from the ASF dual-hosted git repository.
stefanegli pushed a commit to branch OAK-10535-unignore
in repository https://gitbox.apache.org/repos/asf/jackrabbit-oak.git
commit 253a3bbcb77ff390397464c618af9e5a17c50401
Author: Stefan Egli <st...@apache.org>
AuthorDate: Tue Apr 2 16:09:15 2024 +0200
OAK-10535 : unignored lateWriteRemoveChildGC_noSweep
---
.../document/VersionGarbageCollectorIT.java | 94 +++++++++++++++++++---
1 file changed, 85 insertions(+), 9 deletions(-)
diff --git a/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/VersionGarbageCollectorIT.java b/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/VersionGarbageCollectorIT.java
index f249d111b9..b4aa7fc3fc 100644
--- a/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/VersionGarbageCollectorIT.java
+++ b/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/VersionGarbageCollectorIT.java
@@ -46,6 +46,7 @@ import static java.util.Objects.requireNonNull;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.stream.Collectors.toList;
import static java.util.stream.StreamSupport.stream;
+import static org.apache.commons.lang3.reflect.FieldUtils.readField;
import static org.apache.commons.lang3.reflect.FieldUtils.writeField;
import static org.apache.commons.lang3.reflect.FieldUtils.writeStaticField;
import static org.apache.jackrabbit.guava.common.base.Strings.repeat;
@@ -96,6 +97,7 @@ import static org.junit.Assume.assumeTrue;
import org.apache.jackrabbit.guava.common.base.Function;
import org.apache.jackrabbit.guava.common.base.Predicate;
+import org.apache.jackrabbit.guava.common.cache.Cache;
import org.apache.jackrabbit.guava.common.collect.AbstractIterator;
import org.apache.jackrabbit.guava.common.collect.ImmutableList;
import org.apache.jackrabbit.guava.common.collect.Iterators;
@@ -559,7 +561,7 @@ public class VersionGarbageCollectorIT {
stats = gc(gc, maxAge*2, HOURS);
assertStatsCountsEqual(stats,
noOldPropGc(0, 0, 0, 0, 0, 0, 0),
- keepOneFull(0, 0, 0, 2, 1, 0, 1),
+ keepOneFull(0, 0, 0, 2, 0, 0, 1),
keepOneUser(0, 0, 0, 2, 0, 0, 1),
betweenChkp(0, 0, 0, 0, 0, 0, 0));
assertEquals(MIN_ID_VALUE, stats.oldestModifiedDocId);
@@ -1263,6 +1265,77 @@ public class VersionGarbageCollectorIT {
// OAK-10199 END
+ @SuppressWarnings("unchecked")
+ /**
+ * Test when a revision on a parent is becoming garbage on a property
+ * but not on "_revision" as it is (potentially but in this case indeed)
+ * still required by a child (2:/parent/child "ck").
+ * Note that this is not involving and branch commits.
+ */
+ @Test
+ public void parentWithGarbageGCChildIndependent() throws Exception { // rename me
+ assumeTrue(fixture.hasSinglePersistence());
+ NodeBuilder nb = store1.getRoot().builder();
+ NodeBuilder parent = nb.child("parent");
+ parent.setProperty("pk", "pv");
+ parent.child("child").setProperty("ck", "cv");
+ store1.merge(nb, EmptyHook.INSTANCE, CommitInfo.EMPTY);
+ store1.runBackgroundOperations();
+ nb = store1.getRoot().builder();
+ nb.child("parent").setProperty("pk", "pv2");
+ nb.child("parent").child("child").setProperty("ck", "cv2");
+ store1.merge(nb, EmptyHook.INSTANCE, CommitInfo.EMPTY);
+ nb = store1.getRoot().builder();
+ nb.child("parent").setProperty("pk", "pv3");
+ store1.merge(nb, EmptyHook.INSTANCE, CommitInfo.EMPTY);
+ // not doing a bgops == sweep here to cause "cv2" revision
+ // not being considered as commited by sweep
+ // (the test goal is to cause that resolution to fail in case
+ // we would delete the parent's _revisions entry)
+
+ // enable the detailed gc flag
+ writeField(gc, "detailedGCEnabled", true, true);
+
+ // wait two hours
+ clock.waitUntil(clock.getTime() + HOURS.toMillis(2));
+
+ // now make a child change so that only parent (and root) gets GCed
+ nb = store1.getRoot().builder();
+ nb.child("parent").child("child").setProperty("ck", "cv2");
+ store1.merge(nb, EmptyHook.INSTANCE, CommitInfo.EMPTY);
+ // now unlike usually, DONT do a store1.runBackgroundOperations() here
+ // this will leave the parent GC-able
+
+ // check state of 2:/parent/child.ck before GC
+ // invalidate a bunch of caches, in particular nodecache and commitvaluecache
+ store1.getNodeCache().invalidateAll();
+ store1.getNodeChildrenCache().invalidateAll();
+ CachingCommitValueResolver cvr = (CachingCommitValueResolver) readField(store1, "commitValueResolver", true);
+ Cache<Revision, String> commitValueCache = (Cache<Revision, String>) readField( cvr, "commitValueCache", true);
+ commitValueCache.invalidateAll();
+ PropertyState ckBefore = store1.getRoot().getChildNode("parent").getChildNode("child").getProperty("ck");
+ assertNotNull(ckBefore);
+
+ // now the GC
+ VersionGCStats stats = gc(gc, 1, HOURS);
+
+ // check state of 2:/parent/child.ck after GC - should match before GC state
+ // invalidate a bunch of caches, in particular nodecache and commitvaluecache
+ store1.getNodeCache().invalidateAll();
+ store1.getNodeChildrenCache().invalidateAll();
+ cvr = (CachingCommitValueResolver) readField(store1, "commitValueResolver", true);
+ commitValueCache = (Cache<Revision, String>) readField( cvr, "commitValueCache", true);
+ commitValueCache.invalidateAll();
+ PropertyState ckAfter = store1.getRoot().getChildNode("parent").getChildNode("child").getProperty("ck");
+ assertNotNull(ckAfter);
+ assertEquals(ckBefore.getValue(Type.STRING), ckAfter.getValue(Type.STRING));
+ assertStatsCountsEqual(stats,
+ noOldPropGc(0, 0, 0, 0, 0, 0, 0),
+ keepOneFull(0, 0, 0, 3, 0, 0, 2),
+ keepOneUser(0, 0, 0, 3, 0, 0, 2),
+ betweenChkp(0, 0, 0, 0, 0, 0, 0));
+ }
+
@Test
public void parentGCChildIndependent() throws Exception {
assumeTrue(fixture.hasSinglePersistence());
@@ -1410,7 +1483,7 @@ public class VersionGarbageCollectorIT {
// deletedPropRevsCount=1 : (nothing on /node1[a, _commitRoot), /[_revisions]
assertStatsCountsEqual(stats,
noOldPropGc(0, 0, 0, 0, 0, 0, 0),
- keepOneFull(0, 0, 0, 0, 0, 0, 0),
+ keepOneFull(0, 0, 1, 0, 1, 0, 1),
keepOneUser(0, 0, 0, 0, 0, 0, 0),
betweenChkp(0, 0, 1, 0, 2, 1, 1));
// checking for br1 revisino to have disappeared doesn't really make much sense,
@@ -1452,7 +1525,7 @@ public class VersionGarbageCollectorIT {
assertStatsCountsEqual(stats,
noOldPropGc(0, 3, 0, 0, 0, 0, 2),
- keepOneFull(0, 3, 2, 1, 9, 0, 3),
+ keepOneFull(0, 3, 1, 1, 9, 0, 3),
keepOneUser(0, 3, 0, 1, 0, 0, 2),
betweenChkp(0, 3, 1, 1, 8, 2, 3));
assertBranchRevisionRemovedFromAllDocuments(store1, br1);
@@ -1493,7 +1566,7 @@ public class VersionGarbageCollectorIT {
VersionGCStats stats = gc(gc, 1, HOURS);
assertStatsCountsEqual(stats,
noOldPropGc(0, 3, 0, 0, 0, 0, 2),
- keepOneFull(0, 3, 3, 1, 17, 0, 3),
+ keepOneFull(0, 3, 2, 1, 17, 0, 3),
keepOneUser(0, 3, 0, 1, 0, 0, 2),
betweenChkp(0, 3, 2, 1, 18, 4, 3));
assertBranchRevisionRemovedFromAllDocuments(store1, br1);
@@ -1551,7 +1624,6 @@ public class VersionGarbageCollectorIT {
}
@Test
- @Ignore(value = "OAK-10535 : fails currently as uncommitted revisions aren't yet removed")
public void lateWriteRemoveChildGC_noSweep() throws Exception {
assumeTrue(fixture.hasSinglePersistence());
enableDetailGC(store1.getVersionGarbageCollector());
@@ -1570,7 +1642,11 @@ public class VersionGarbageCollectorIT {
assertNotNull(store1.getDocumentStore().find(NODES, "4:/a/b/c/d"));
assertTrue(getChildeNodeState(store1, "/a/b/c/d", true).exists());
// should be 3 as it should clean up the _deleted from /a/b, /a/b/c and /a/b/c/d
- assertEquals(3, stats.updatedDetailedGCDocsCount);
+ assertStatsCountsEqual(stats,
+ noOldPropGc(0, 0, 0, 0, 0, 0, 0),
+ keepOneFull(0, 0, 0, 3, 3, 0, 3),
+ keepOneUser(0, 0, 0, 3, 0, 0, 3),
+ betweenChkp(0, 0, 0, 0, 0, 0, 0));
}
/**
@@ -2044,7 +2120,7 @@ public class VersionGarbageCollectorIT {
// removeProperty(prop) plus 1 _commitRoot entry
assertStatsCountsEqual(stats,
noOldPropGc(0, 0, 0, 0, 0, 0, 0),
- keepOneFull(0, 0, 0, 2, 1, 0, 1),
+ keepOneFull(0, 0, 0, 2, 0, 0, 1),
keepOneUser(0, 0, 0, 2, 0, 0, 1),
betweenChkp(0, 0, 0, 0, 0, 0, 0));
assertDocumentsExist(of("/bar"));
@@ -2076,7 +2152,7 @@ public class VersionGarbageCollectorIT {
// 1 prop-rev removal : the late-write null
assertStatsCountsEqual(stats,
noOldPropGc(0, 0, 0, 0, 0, 0, 0),
- keepOneFull(0, 0, 1, 1, 0, 0, 1),
+ keepOneFull(0, 0, 0, 1, 0, 0, 1),
keepOneUser(0, 0, 0, 1, 0, 0, 1),
betweenChkp(0, 0, 0, 0, 0, 0, 0));
assertDocumentsExist(of("/bar"));
@@ -2110,7 +2186,7 @@ public class VersionGarbageCollectorIT {
// removes 1 prop-rev : the late-write null
assertStatsCountsEqual(stats,
noOldPropGc(0, 0, 0, 0, 0, 0, 0),
- keepOneFull(0, 0, 1, 1, 0, 0, 1),
+ keepOneFull(0, 0, 0, 1, 0, 0, 1),
keepOneUser(0, 0, 0, 1, 0, 0, 1),
betweenChkp(0, 0, 0, 0, 0, 0, 0));
assertDocumentsExist(of("/foo/bar/baz"));