Author: frm
Date: Wed Aug  2 13:42:24 2017
New Revision: 1803818

URL: http://svn.apache.org/viewvc?rev=1803818&view=rev
Log:
OAK-6507 - Prevent full head states in use from being removed during cleanup

Added:
    
jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/Reclaimers.java
   (with props)
    
jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/file/ReclaimersTest.java
   (with props)
Modified:
    
jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/FileStore.java
    
jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/tar/GCGeneration.java
    
jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/CompactionAndCleanupIT.java

Modified: 
jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/FileStore.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/FileStore.java?rev=1803818&r1=1803817&r2=1803818&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/FileStore.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/FileStore.java
 Wed Aug  2 13:42:24 2017
@@ -1067,7 +1067,7 @@ public class FileStore extends AbstractF
         synchronized void collectBlobReferences(Consumer<String> collector) 
throws IOException {
             segmentWriter.flush();
             tarFiles.collectBlobReferences(collector,
-                    CompactionResult.newOldReclaimer(getGcGeneration(), 
gcOptions.getRetainedGenerations()));
+                    Reclaimers.newOldReclaimer(getGcGeneration(), 
gcOptions.getRetainedGenerations()));
         }
 
         void cancel() {
@@ -1162,7 +1162,7 @@ public class FileStore extends AbstractF
             return new CompactionResult(newGeneration) {
                 @Override
                 Predicate<GCGeneration> reclaimer() {
-                    return CompactionResult.newOldReclaimer(newGeneration, 
gcOptions.getRetainedGenerations());
+                    return Reclaimers.newOldReclaimer(newGeneration, 
gcOptions.getRetainedGenerations());
                 }
 
                 @Override
@@ -1188,7 +1188,7 @@ public class FileStore extends AbstractF
             return new CompactionResult(currentGeneration) {
                 @Override
                 Predicate<GCGeneration> reclaimer() {
-                    return 
CompactionResult.newFailedReclaimer(failedGeneration);
+                    return Reclaimers.newExactReclaimer(failedGeneration);
                 }
 
                 @Override
@@ -1209,7 +1209,7 @@ public class FileStore extends AbstractF
             return new CompactionResult(currentGeneration) {
                 @Override
                 Predicate<GCGeneration> reclaimer() {
-                    return CompactionResult.newOldReclaimer(currentGeneration, 
gcOptions.getRetainedGenerations());
+                    return Reclaimers.newOldReclaimer(currentGeneration, 
gcOptions.getRetainedGenerations());
                 }
 
                 @Override
@@ -1250,33 +1250,6 @@ public class FileStore extends AbstractF
                     ",reclaim-predicate=" + reclaimer();
         }
 
-        private static Predicate<GCGeneration> newFailedReclaimer(@Nonnull 
final GCGeneration failedGeneration) {
-            return new Predicate<GCGeneration>() {
-                @Override
-                public boolean apply(GCGeneration generation) {
-                    return generation.equals(failedGeneration);
-                }
-                @Override
-                public String toString() {
-                    return "(generation==" + failedGeneration + ")";
-                }
-            };
-        }
-
-        private static Predicate<GCGeneration> newOldReclaimer(@Nonnull final 
GCGeneration reference, int retainedGenerations) {
-            return new Predicate<GCGeneration>() {
-                @Override
-                public boolean apply(GCGeneration generation) {
-                    return reference.compareFull(generation) >= 
retainedGenerations
-                            || (reference.compareTail(generation) >= 
retainedGenerations && !generation.isTail());
-                }
-                @Override
-                public String toString() {
-                    // FIXME OAK-3349 align string representation with above 
predicate
-                    return "(" + reference + " - generation >= " + 
retainedGenerations + ")";
-                }
-            };
-        }
     }
 
 }

Added: 
jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/Reclaimers.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/Reclaimers.java?rev=1803818&view=auto
==============================================================================
--- 
jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/Reclaimers.java
 (added)
+++ 
jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/Reclaimers.java
 Wed Aug  2 13:42:24 2017
@@ -0,0 +1,85 @@
+/*
+ * 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.segment.file;
+
+import javax.annotation.Nonnull;
+
+import com.google.common.base.Predicate;
+import org.apache.jackrabbit.oak.segment.file.tar.GCGeneration;
+
+class Reclaimers {
+
+    private Reclaimers() {
+        // Prevent instantiation.
+    }
+
+    static Predicate<GCGeneration> newOldReclaimer(@Nonnull final GCGeneration 
reference, int retainedGenerations) {
+        return new Predicate<GCGeneration>() {
+
+            @Override
+            public boolean apply(GCGeneration generation) {
+                int deltaFull = reference.compareFull(generation);
+
+                if (deltaFull == 0) {
+                    if (generation.getTail() == 0) {
+                        return false;
+                    }
+
+                    int deltaTail = reference.compareTail(generation);
+
+                    if (deltaTail == 0) {
+                        return false;
+                    }
+
+                    if (deltaTail >= retainedGenerations) {
+                        return !generation.isTail();
+                    }
+
+                    return false;
+                }
+
+                if (deltaFull >= retainedGenerations) {
+                    return true;
+                }
+
+                return generation.getTail() != 0;
+            }
+
+            @Override
+            public String toString() {
+                // FIXME OAK-3349 align string representation with above 
predicate
+                return "(" + reference + " - generation >= " + 
retainedGenerations + ")";
+            }
+
+        };
+    }
+
+    static Predicate<GCGeneration> newExactReclaimer(@Nonnull final 
GCGeneration failedGeneration) {
+        return new Predicate<GCGeneration>() {
+            @Override
+            public boolean apply(GCGeneration generation) {
+                return generation.equals(failedGeneration);
+            }
+            @Override
+            public String toString() {
+                return "(generation==" + failedGeneration + ")";
+            }
+        };
+    }
+
+}

Propchange: 
jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/Reclaimers.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: 
jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/tar/GCGeneration.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/tar/GCGeneration.java?rev=1803818&r1=1803817&r2=1803818&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/tar/GCGeneration.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/tar/GCGeneration.java
 Wed Aug  2 13:42:24 2017
@@ -74,7 +74,7 @@ public final class GCGeneration {
      */
     @Nonnull
     public GCGeneration nextFull() {
-        return new GCGeneration(full + 1, tail, false);
+        return new GCGeneration(full + 1, 0, false);
     }
 
     /**

Modified: 
jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/CompactionAndCleanupIT.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/CompactionAndCleanupIT.java?rev=1803818&r1=1803817&r2=1803818&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/CompactionAndCleanupIT.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/CompactionAndCleanupIT.java
 Wed Aug  2 13:42:24 2017
@@ -1458,11 +1458,12 @@ public class CompactionAndCleanupIT {
     }
 
     @Test
-    @Ignore("OAK-6507")
     public void latestFullCompactedStateShouldNotBeDeleted() throws Exception {
-        try (FileStore fileStore = fileStoreBuilder(getFileStoreFolder())
-                .withGCOptions(defaultGCOptions().setEstimationDisabled(true))
-                .build()) {
+        SegmentGCOptions gcOptions = defaultGCOptions()
+                .setEstimationDisabled(true)
+                .setRetainedGenerations(2);
+
+        try (FileStore fileStore = 
fileStoreBuilder(getFileStoreFolder()).withGCOptions(gcOptions).build()) {
 
             // Create a full, self consistent head state. This state will be 
the
             // base for the following tail compactions. This increments the
@@ -1480,10 +1481,10 @@ public class CompactionAndCleanupIT {
 
             // Create a tail state on top of the previous tail state. This
             // increments the tail generation, but leaves the full generation
-            // untouched. The increment in tail generation will make the 
cleanup
-            // algorithm delete the segments from the full head state. This
-            // results in an inconsistent repository and
-            // SegmentNotFoundException.
+            // untouched. This brings this generations two generations away 
from
+            // the latest full head state. Still, the full head state will not
+            // be deleted because doing so would geenrated an invalid 
repository
+            // at risk of SegmentNotFoundException.
 
             fileStore.tailGC();
             traverse(fileStore.getHead());

Added: 
jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/file/ReclaimersTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/file/ReclaimersTest.java?rev=1803818&view=auto
==============================================================================
--- 
jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/file/ReclaimersTest.java
 (added)
+++ 
jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/file/ReclaimersTest.java
 Wed Aug  2 13:42:24 2017
@@ -0,0 +1,79 @@
+/*
+ * 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.segment.file;
+
+import static 
org.apache.jackrabbit.oak.segment.file.Reclaimers.newOldReclaimer;
+import static 
org.apache.jackrabbit.oak.segment.file.tar.GCGeneration.newGCGeneration;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import com.google.common.base.Predicate;
+import org.apache.jackrabbit.oak.segment.file.tar.GCGeneration;
+import org.junit.Test;
+
+public class ReclaimersTest {
+
+    @Test
+    public void testOldReclaimer() throws Exception {
+        Predicate<GCGeneration> p = newOldReclaimer(newGCGeneration(3, 3, 
false), 2);
+
+        // Segments from the same full and tail generation should not be
+        // removed.
+
+        assertFalse(p.apply(newGCGeneration(3, 3, false)));
+        assertFalse(p.apply(newGCGeneration(3, 3, true)));
+
+        // Recent segments, tail or not-tail ones, can't be removed.
+
+        assertFalse(p.apply(newGCGeneration(3, 2, false)));
+        assertFalse(p.apply(newGCGeneration(3, 2, true)));
+
+        // Old segments from the same full generation can be removed as long
+        // as they are not tail segments.
+
+        assertTrue(p.apply(newGCGeneration(3, 1, false)));
+        assertFalse(p.apply(newGCGeneration(3, 1, true)));
+
+        // A full head state from the same full generation can't be removed.
+
+        assertFalse(p.apply(newGCGeneration(3, 0, false)));
+
+        // Some of these generations can be reclaimed, some may not. Since 
there
+        // is a new full head state with full generation 3, every tail and
+        // non-tail segment with a tail generation greater than zero can be
+        // removed. The full head state with full generation 2 can't be 
removed,
+        // otherwise the condition about the number of retained generations
+        // would be violated.
+
+        assertTrue(p.apply(newGCGeneration(2, 2, false)));
+        assertTrue(p.apply(newGCGeneration(2, 2, true)));
+        assertTrue(p.apply(newGCGeneration(2, 1, false)));
+        assertTrue(p.apply(newGCGeneration(2, 1, true)));
+        assertFalse(p.apply(newGCGeneration(2, 0, false)));
+
+        // These generations can be reclaimed because their full generation is
+        // too old when compared to the number of retained generations.
+
+        assertTrue(p.apply(newGCGeneration(1, 2, false)));
+        assertTrue(p.apply(newGCGeneration(1, 2, true)));
+        assertTrue(p.apply(newGCGeneration(1, 1, false)));
+        assertTrue(p.apply(newGCGeneration(1, 1, true)));
+        assertTrue(p.apply(newGCGeneration(1, 0, false)));
+    }
+
+}

Propchange: 
jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/file/ReclaimersTest.java
------------------------------------------------------------------------------
    svn:eol-style = native


Reply via email to