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 {

Reply via email to