Author: frm
Date: Mon Nov  6 16:45:25 2017
New Revision: 1814429

URL: http://svn.apache.org/viewvc?rev=1814429&view=rev
Log:
OAK-6883 - Let SizeDeltaGcEstimation take the compaction type into consideration

Added:
    
jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/GCEstimationResult.java
   (with props)
    
jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/file/SizeDeltaGCEstimationTest.java
   (with props)
Removed:
    
jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/file/CompactionEstimatorTest.java
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/GCEstimation.java
    
jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/SizeDeltaGcEstimation.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=1814429&r1=1814428&r2=1814429&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
 Mon Nov  6 16:45:25 2017
@@ -368,16 +368,6 @@ public class FileStore extends AbstractF
     }
 
     /**
-     * Run the compaction gain estimation process.
-     * @return
-     */
-    public GCEstimation estimateCompactionGain() {
-        try (ShutDownCloser ignored = shutDown.keepAlive()) {
-            return garbageCollector.estimateCompactionGain();
-        }
-    }
-
-    /**
      * Copy every referenced record in data (non-bulk) segments. Bulk segments
      * are fully kept (they are only removed in cleanup, if there is no
      * reference to them).
@@ -624,14 +614,14 @@ public class FileStore extends AbstractF
         }
 
         synchronized void runFull() throws IOException {
-            run(this::compactFull);
+            run(true, this::compactFull);
         }
 
         synchronized void runTail() throws IOException {
-            run(this::compactTail);
+            run(false, this::compactTail);
         }
 
-        private void run(Supplier<CompactionResult> compact) throws 
IOException {
+        private void run(boolean full, Supplier<CompactionResult> compact) 
throws IOException {
             try {
                 gcListener.info("TarMK GC #{}: started", 
GC_COUNT.incrementAndGet());
 
@@ -652,9 +642,9 @@ public class FileStore extends AbstractF
                     gcListener.updateStatus(ESTIMATION.message());
                     
                     Stopwatch watch = Stopwatch.createStarted();
-                    GCEstimation estimate = estimateCompactionGain();
-                    sufficientEstimatedGain = estimate.gcNeeded();
-                    String gcLog = estimate.gcLog();
+                    GCEstimationResult estimation = 
estimateCompactionGain(full);
+                    sufficientEstimatedGain = estimation.isGcNeeded();
+                    String gcLog = estimation.getGcLog();
                     if (sufficientEstimatedGain) {
                         gcListener.info(
                                 "TarMK GC #{}: estimation completed in {} ({} 
ms). {}",
@@ -696,9 +686,8 @@ public class FileStore extends AbstractF
          * the passed {@code stop} signal.
          * @return compaction gain estimate
          */
-        synchronized GCEstimation estimateCompactionGain() {
-            return new SizeDeltaGcEstimation(gcOptions, gcJournal,
-                    stats.getApproximateSize());
+        GCEstimationResult estimateCompactionGain(boolean full) {
+            return new 
SizeDeltaGcEstimation(gcOptions.getGcSizeDeltaEstimation(), gcJournal, 
stats.getApproximateSize(), full).estimate();
         }
 
         @Nonnull

Modified: 
jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/GCEstimation.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/GCEstimation.java?rev=1814429&r1=1814428&r2=1814429&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/GCEstimation.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/GCEstimation.java
 Mon Nov  6 16:45:25 2017
@@ -19,17 +19,8 @@
 
 package org.apache.jackrabbit.oak.segment.file;
 
-public interface GCEstimation {
+interface GCEstimation {
 
-    /**
-     * Determines if the Gc operation needs to run or not
-     */
-    boolean gcNeeded();
-
-    /**
-     * User friendly message explaining the value of the
-     * {@link GCEstimation#gcNeeded()} flag
-     */
-    String gcLog();
+    GCEstimationResult estimate();
 
 }

Added: 
jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/GCEstimationResult.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/GCEstimationResult.java?rev=1814429&view=auto
==============================================================================
--- 
jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/GCEstimationResult.java
 (added)
+++ 
jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/GCEstimationResult.java
 Mon Nov  6 16:45:25 2017
@@ -0,0 +1,39 @@
+/*
+ * 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;
+
+class GCEstimationResult {
+
+    private final boolean gcNeeded;
+
+    private final String gcLog;
+
+    GCEstimationResult(boolean gcNeeded, String gcLog) {
+        this.gcNeeded = gcNeeded;
+        this.gcLog = gcLog;
+    }
+
+    boolean isGcNeeded() {
+        return gcNeeded;
+    }
+
+    String getGcLog() {
+        return gcLog;
+    }
+
+}

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

Modified: 
jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/SizeDeltaGcEstimation.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/SizeDeltaGcEstimation.java?rev=1814429&r1=1814428&r2=1814429&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/SizeDeltaGcEstimation.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/SizeDeltaGcEstimation.java
 Mon Nov  6 16:45:25 2017
@@ -23,82 +23,94 @@ import static com.google.common.base.Pre
 import static java.lang.String.format;
 import static org.apache.jackrabbit.oak.commons.IOUtils.humanReadableByteCount;
 
+import java.util.ArrayList;
+import java.util.List;
+
 import javax.annotation.Nonnull;
 
-import org.apache.jackrabbit.oak.segment.compaction.SegmentGCOptions;
+import org.apache.jackrabbit.oak.segment.file.GCJournal.GCJournalEntry;
 
-public class SizeDeltaGcEstimation implements GCEstimation {
+class SizeDeltaGcEstimation implements GCEstimation {
 
     private final long delta;
 
     private final GCJournal gcJournal;
 
-    private final long totalSize;
-
-    private boolean gcNeeded;
-
-    private String gcInfo = "unknown";
+    private final long currentSize;
 
-    private boolean finished = false;
+    private final boolean full;
 
-    public SizeDeltaGcEstimation(@Nonnull SegmentGCOptions opts,
-            @Nonnull GCJournal gcJournal, long totalSize) {
-        this.delta = checkNotNull(opts).getGcSizeDeltaEstimation();
+    SizeDeltaGcEstimation(long delta, @Nonnull GCJournal gcJournal, long 
currentSize, boolean full) {
+        this.delta = delta;
         this.gcJournal = checkNotNull(gcJournal);
-        this.totalSize = totalSize;
+        this.currentSize = currentSize;
+        this.full = full;
     }
 
     @Override
-    public boolean gcNeeded() {
-        if (!finished) {
-            run();
+    public GCEstimationResult estimate() {
+        if (delta == 0) {
+            return new GCEstimationResult(true, "Estimation skipped because 
the size delta value equals 0");
+        }
+
+        long previousSize = readPreviousSize();
+
+        if (previousSize < 0) {
+            return new GCEstimationResult(true, "Estimation skipped because of 
missing gc journal data (expected on first run)");
+        }
+
+        long gain = currentSize - previousSize;
+        boolean gcNeeded = gain > delta;
+        String gcInfo = format(
+            "Segmentstore size has increased since the last %s garbage 
collection from %s (%s bytes) to %s (%s bytes), an increase of %s (%s bytes) or 
%s%%. ",
+            full ? "full" : "tail",
+            humanReadableByteCount(previousSize), previousSize,
+            humanReadableByteCount(currentSize), currentSize,
+            humanReadableByteCount(gain), gain, 100 * gain / previousSize
+        );
+        if (gcNeeded) {
+            gcInfo = gcInfo + format(
+                "This is greater than sizeDeltaEstimation=%s (%s bytes), so 
running garbage collection",
+                humanReadableByteCount(delta), delta
+            );
+        } else {
+            gcInfo = gcInfo + format(
+                "This is less than sizeDeltaEstimation=%s (%s bytes), so 
skipping garbage collection",
+                humanReadableByteCount(delta), delta
+            );
         }
-        return gcNeeded;
+        return new GCEstimationResult(gcNeeded, gcInfo);
     }
 
-    @Override
-    public String gcLog() {
-        if (!finished) {
-            run();
+    private long readPreviousSize() {
+        if (full) {
+            return readPreviousFullCleanupSize();
         }
-        return gcInfo;
+        return readPreviousTailCleanupSize();
     }
 
-    private void run() {
-        if (finished) {
-            return;
+    private long readPreviousFullCleanupSize() {
+        List<GCJournalEntry> entries = new ArrayList<>(gcJournal.readAll());
+
+        if (entries.isEmpty()) {
+            return -1;
         }
-        if (delta == 0) {
-            gcNeeded = true;
-            gcInfo = "Estimation skipped because the size delta value equals 
0";
-        } else if (getPreviousCleanupSize() < 0) {
-            gcNeeded = true;
-            gcInfo = "Estimation skipped because of missing gc journal data 
(expected on first run)";
-        } else {
-            long lastGc = getPreviousCleanupSize();
-            long gain = totalSize - lastGc;
-            long gainP = 100 * (totalSize - lastGc) / lastGc;
-            gcNeeded = gain > delta;
-            gcInfo = format(
-                    "Segmentstore size has increased since the last garbage 
collection from %s (%s bytes) to %s (%s bytes), " +
-                    "an increase of %s (%s bytes) or %s%%. ",
-                    humanReadableByteCount(lastGc), lastGc,
-                    humanReadableByteCount(totalSize), totalSize,
-                    humanReadableByteCount(gain), gain, gainP);
-            if (gcNeeded) {
-                gcInfo = gcInfo + format(
-                        "This is greater than sizeDeltaEstimation=%s (%s 
bytes), so running garbage collection",
-                        humanReadableByteCount(delta), delta);
-            } else {
-                gcInfo = gcInfo + format(
-                        "This is less than sizeDeltaEstimation=%s (%s bytes), 
so skipping garbage collection",
-                        humanReadableByteCount(delta), delta);
+
+        entries.sort((a, b) -> {
+            if (a.getGcGeneration().getFullGeneration() > 
b.getGcGeneration().getFullGeneration()) {
+                return -1;
             }
-        }
-        finished = true;
+            if (a.getGcGeneration().getFullGeneration() < 
b.getGcGeneration().getFullGeneration()) {
+                return 1;
+            }
+            return Integer.compare(a.getGcGeneration().getGeneration(), 
b.getGcGeneration().getGeneration());
+        });
+
+        return entries.iterator().next().getRepoSize();
     }
 
-    private long getPreviousCleanupSize() {
+    private long readPreviousTailCleanupSize() {
         return gcJournal.read().getRepoSize();
     }
+
 }

Added: 
jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/file/SizeDeltaGCEstimationTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/file/SizeDeltaGCEstimationTest.java?rev=1814429&view=auto
==============================================================================
--- 
jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/file/SizeDeltaGCEstimationTest.java
 (added)
+++ 
jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/file/SizeDeltaGCEstimationTest.java
 Mon Nov  6 16:45:25 2017
@@ -0,0 +1,101 @@
+/*
+ * 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.tar.GCGeneration.newGCGeneration;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+
+public class SizeDeltaGCEstimationTest {
+
+    @Rule
+    public TemporaryFolder folder = new TemporaryFolder(new File("target"));
+
+    private GCJournal journal;
+
+    @Before
+    public void setUpJournal() throws Exception {
+        journal = new GCJournal(folder.getRoot());
+    }
+
+    @Test
+    public void testFullSkippedEstimation() {
+        assertTrue(new SizeDeltaGcEstimation(0, journal, 1000, 
true).estimate().isGcNeeded());
+    }
+
+    @Test
+    public void testTailSkippedEstimation() {
+        assertTrue(new SizeDeltaGcEstimation(0, journal, 1000, 
false).estimate().isGcNeeded());
+    }
+
+    @Test
+    public void testFullEmptyJournal() {
+        assertTrue(new SizeDeltaGcEstimation(100, journal, 1000, 
true).estimate().isGcNeeded());
+    }
+
+    @Test
+    public void testTailEmptyJournal() {
+        assertTrue(new SizeDeltaGcEstimation(100, journal, 1000, 
false).estimate().isGcNeeded());
+    }
+
+    @Test
+    public void testTailGCNeeded() throws Exception {
+        journal.persist(100, 1000, newGCGeneration(1, 1, true), 1000, "id");
+        journal.persist(110, 1100, newGCGeneration(2, 1, true), 1000, "id");
+        journal.persist(120, 1200, newGCGeneration(3, 1, true), 1000, "id");
+        assertTrue(new SizeDeltaGcEstimation(50, journal, 1300, 
false).estimate().isGcNeeded());
+    }
+
+    @Test
+    public void testTailGCSkipped() throws Exception {
+        journal.persist(100, 1000, newGCGeneration(1, 1, true), 1000, "id");
+        journal.persist(110, 1100, newGCGeneration(2, 1, true), 1000, "id");
+        journal.persist(120, 1200, newGCGeneration(3, 1, true), 1000, "id");
+        assertFalse(new SizeDeltaGcEstimation(200, journal, 1300, 
false).estimate().isGcNeeded());
+    }
+
+    @Test
+    public void testFullGCNeeded() throws Exception {
+        journal.persist(100, 1000, newGCGeneration(1, 1, true), 1000, "id");
+        journal.persist(110, 1100, newGCGeneration(2, 1, true), 1000, "id");
+        journal.persist(120, 1200, newGCGeneration(3, 1, true), 1000, "id");
+        journal.persist(130, 1000, newGCGeneration(4, 2, true), 1000, "id");
+        journal.persist(100, 1010, newGCGeneration(5, 2, true), 1000, "id");
+        journal.persist(110, 1020, newGCGeneration(6, 2, true), 1000, "id");
+        assertTrue(new SizeDeltaGcEstimation(100, journal, 1300, 
true).estimate().isGcNeeded());
+    }
+
+    @Test
+    public void testFullGCSkipped() throws Exception {
+        journal.persist(100, 1000, newGCGeneration(1, 1, true), 1000, "id");
+        journal.persist(110, 1100, newGCGeneration(2, 1, true), 1000, "id");
+        journal.persist(120, 1200, newGCGeneration(3, 1, true), 1000, "id");
+        journal.persist(130, 1000, newGCGeneration(4, 2, true), 1000, "id");
+        journal.persist(100, 1010, newGCGeneration(5, 2, true), 1000, "id");
+        journal.persist(110, 1020, newGCGeneration(6, 2, true), 1000, "id");
+        assertFalse(new SizeDeltaGcEstimation(100, journal, 1030, 
true).estimate().isGcNeeded());
+    }
+
+}

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


Reply via email to