This is an automated email from the ASF dual-hosted git repository. daim pushed a commit to branch DetailedGC/OAK-10199 in repository https://gitbox.apache.org/repos/asf/jackrabbit-oak.git
commit 4984eea7d0149dcc5b94d4758eb96c74dd747b0c Author: Rishabh Kumar <d...@adobe.com> AuthorDate: Mon Jun 26 19:55:41 2023 +0530 OAK-10199 : handled escaped properties while deleting them --- .../plugins/document/VersionGarbageCollector.java | 2 + .../document/VersionGarbageCollectorIT.java | 57 +++++++++++++++++++++- 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/VersionGarbageCollector.java b/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/VersionGarbageCollector.java index 9d918ee9a4..307315d5a8 100644 --- a/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/VersionGarbageCollector.java +++ b/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/VersionGarbageCollector.java @@ -62,6 +62,7 @@ import static java.util.Objects.requireNonNull; import static java.util.Optional.ofNullable; import static java.util.concurrent.TimeUnit.MILLISECONDS; import static java.util.stream.Collectors.joining; +import static java.util.stream.Collectors.toSet; import static org.apache.jackrabbit.guava.common.base.StandardSystemProperty.LINE_SEPARATOR; import static org.apache.jackrabbit.guava.common.collect.Iterables.all; import static org.apache.jackrabbit.guava.common.collect.Iterators.partition; @@ -834,6 +835,7 @@ public class VersionGarbageCollector { final Set<String> retainPropSet = ofNullable(doc.getNodeAtRevision(nodeStore, headRevision, null)) .map(DocumentNodeState::getPropertyNames) + .map(p -> p.stream().map(Utils::escapePropertyName).collect(toSet())) .orElse(emptySet()); final int deletedPropsGCCount = properties.stream() .filter(p -> !retainPropSet.contains(p)) 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 031176ca33..ca00648244 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 @@ -454,7 +454,7 @@ public class VersionGarbageCollectorIT { assertEquals(10, stats.deletedPropsGCCount); } - // Test when properties are not collected in one GC cycle + // Test properties are collected after system crash had happened @Test public void testGCDeletedProps_4() throws Exception { final FailingDocumentStore fds = new FailingDocumentStore(fixture.createDocumentStore(), 42) { @@ -522,6 +522,61 @@ public class VersionGarbageCollectorIT { } + // Test when escaped properties are collected + @Test + public void testGCDeletedProps_5() throws Exception { + //1. Create nodes with properties + NodeBuilder b1 = store.getRoot().builder(); + + // Add property to node & save + for (int i = 0; i < 10; i++) { + b1.child("x").setProperty("test."+i, "t", STRING); + } + store.merge(b1, EmptyHook.INSTANCE, CommitInfo.EMPTY); + + // enable the detailed gc flag + writeField(gc, "detailedGCEnabled", true, true); + long maxAge = 1; //hours + long delta = TimeUnit.MINUTES.toMillis(10); + //1. Go past GC age and check no GC done as nothing deleted + clock.waitUntil(Revision.getCurrentTimestamp() + maxAge); + VersionGCStats stats = gc.gc(maxAge, HOURS); + assertEquals(0, stats.deletedPropsGCCount); + + //Remove property + NodeBuilder b2 = store.getRoot().builder(); + for (int i = 0; i < 10; i++) { + b2.getChildNode("x").removeProperty("test."+i); + } + store.merge(b2, EmptyHook.INSTANCE, CommitInfo.EMPTY); + + store.runBackgroundOperations(); + + //2. Check that a deleted property is not collected before maxAge + //Clock cannot move back (it moved forward in #1) so double the maxAge + clock.waitUntil(clock.getTime() + delta); + stats = gc.gc(maxAge*2, HOURS); + assertEquals(0, stats.deletedPropsGCCount); + + //3. Check that deleted property does get collected post maxAge + clock.waitUntil(clock.getTime() + HOURS.toMillis(maxAge*2) + delta); + + stats = gc.gc(maxAge*2, HOURS); + assertEquals(10, stats.deletedPropsGCCount); + + //4. Check that a revived property (deleted and created again) does not get gc + NodeBuilder b4 = store.getRoot().builder(); + for (int i = 0; i < 10; i++) { + b4.child("x").setProperty("test."+i, "t", STRING); + } + store.merge(b4, EmptyHook.INSTANCE, CommitInfo.EMPTY); + + clock.waitUntil(clock.getTime() + HOURS.toMillis(maxAge*2) + delta); + stats = gc.gc(maxAge*2, HOURS); + assertEquals(0, stats.deletedPropsGCCount); + + } + // OAK-10199 END private void gcSplitDocsInternal(String subNodeName) throws Exception {