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 re...@apache.org on 2019/08/17 05:09:02 UTC

svn commit: r1865335 - in /jackrabbit/oak/branches/1.8: ./ oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/ oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/

Author: reschke
Date: Sat Aug 17 05:09:02 2019
New Revision: 1865335

URL: http://svn.apache.org/viewvc?rev=1865335&view=rev
Log:
OAK-8453: Refactor VersionGarbageCollector to extract Recommendations class (merged r1862465, r1862499 and r1862536 into 1.8)

Added:
    jackrabbit/oak/branches/1.8/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/VersionGCRecommendations.java
      - copied, changed from r1862465, jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/VersionGCRecommendations.java
Modified:
    jackrabbit/oak/branches/1.8/   (props changed)
    jackrabbit/oak/branches/1.8/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/VersionGarbageCollector.java
    jackrabbit/oak/branches/1.8/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/VersionGCTest.java

Propchange: jackrabbit/oak/branches/1.8/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Sat Aug 17 05:09:02 2019
@@ -1,4 +1,4 @@
 /jackrabbit/oak/branches/1.0:1665962
 /jackrabbit/oak/branches/1.10:1854524
-/jackrabbit/oak/trunk:1820660-1820661,1820729,1820734,1820859,1820861,1820878,1820888,1820947,1821027,1821130,1821140-1821141,1821178,1821237,1821240,1821249,1821258,1821325,1821358,1821361-1821362,1821370,1821375,1821393,1821477,1821487,1821516,1821617,1821663,1821665,1821668,1821681,1821847,1821975-1821983,1822121,1822182,1822201,1822207,1822496,1822527,1822638,1822642,1822645,1822723,1822802,1822808,1822850,1822934,1823135,1823163,1823169,1823172,1823655,1823669,1823671,1824196,1824198,1824253,1824255,1824896,1824962,1825065,1825362,1825381,1825442,1825448,1825466,1825470-1825471,1825475,1825523,1825525,1825561,1825619-1825621,1825651,1825654,1825992,1826079,1826089-1826090,1826096,1826216,1826237,1826338,1826516,1826532,1826551,1826560,1826638,1826640,1826730,1826833,1826932,1826957,1827423,1827472,1827486,1827816,1827977,1828349,1828439,1828502,1828529,1828827,1828868,1828948,1829527,1829534,1829546,1829569,1829587,1829665,1829854,1829864,1829978,1829985,1829987,1829998,1830019
 ,1830048,1830160,1830171,1830197,1830209,1830239,1830347,1830748,1830911,1830923,1831157-1831158,1831163,1831190,1831374,1831560,1831689,1832258,1832376,1832379,1832535,1833308,1833347,1833702,1833833,1834109,1834112,1834117,1834287,1834291,1834302,1834312,1834326,1834328,1834336,1834428,1834468,1834483,1834610,1834648-1834649,1834681,1834823,1834857-1834858,1835056,1835060,1835062,1835518,1835521,1835635,1835642,1835780,1835819,1836082,1836121,1836167-1836168,1836170-1836187,1836189-1836196,1836206,1836487,1836493,1836548,1837057,1837274,1837296,1837326,1837475,1837503,1837547,1837569,1837596,1837600,1837657,1837718,1837998,1838076,1838637,1839549,1839570,1839637,1839746,1840019,1840024,1840031,1840226,1840455,1840462,1840574,1840769,1841314,1841352,1841909,1842089,1842240,1842677,1843175,1843222,1843231,1843398,1843618,1843621,1843637,1843652,1843669,1843905,1843911,1843994,1844070,1844110,1844325,1844549,1844625,1844627,1844642,1844728,1844775,1844932,1845135,1845336,1845405,1845
 415,1845730-1845731,1845863,1845865,1846057,1846162,1846396,1846429,1846486,1846581,1846617,1847088,1847096,1848073,1848181-1848182,1848191,1848217,1848729,1848769,1848822-1848823,1850221,1850319,1850343,1850837,1850874,1851533-1851535,1851619,1852120,1852135,1852451,1852492-1852493,1852528,1852582,1852584,1852601,1853083,1853141,1853229,1853393,1853429,1853433,1853435,1853866,1853868,1853870,1853893,1853969,1853997,1854034,1854044,1854055,1854113,1854373,1854377,1854380,1854385,1854401,1854403,1854455,1854461-1854462,1854466,1854468,1854515,1854539,1854701,1854773-1854774,1854827,1854848,1854859,1854930,1855032,1855522,1855776,1855905,1855993,1856049,1856056,1856538,1856545,1856818,1857000,1857010,1857221,1857242,1857247,1857253,1857294,1857314,1857332,1857463,1857480,1857634,1857638,1857936,1858032,1858139,1858385,1858424,1858571,1858578,1858810,1858926,1859020,1859231,1859292,1859294,1859533,1859609,1859612,1859711,1859716,1859772,1859776,1859780,1859843,1859881,1860120,1860131,1
 860137,1860202,1860328,1860548,1860564-1860565,1861114,1861626,1861743,1861757,1862044,1862370,1862422,1862448,1862728,1862881,1863540,1864349,1864353
+/jackrabbit/oak/trunk:1820660-1820661,1820729,1820734,1820859,1820861,1820878,1820888,1820947,1821027,1821130,1821140-1821141,1821178,1821237,1821240,1821249,1821258,1821325,1821358,1821361-1821362,1821370,1821375,1821393,1821477,1821487,1821516,1821617,1821663,1821665,1821668,1821681,1821847,1821975-1821983,1822121,1822182,1822201,1822207,1822496,1822527,1822638,1822642,1822645,1822723,1822802,1822808,1822850,1822934,1823135,1823163,1823169,1823172,1823655,1823669,1823671,1824196,1824198,1824253,1824255,1824896,1824962,1825065,1825362,1825381,1825442,1825448,1825466,1825470-1825471,1825475,1825523,1825525,1825561,1825619-1825621,1825651,1825654,1825992,1826079,1826089-1826090,1826096,1826216,1826237,1826338,1826516,1826532,1826551,1826560,1826638,1826640,1826730,1826833,1826932,1826957,1827423,1827472,1827486,1827816,1827977,1828349,1828439,1828502,1828529,1828827,1828868,1828948,1829527,1829534,1829546,1829569,1829587,1829665,1829854,1829864,1829978,1829985,1829987,1829998,1830019
 ,1830048,1830160,1830171,1830197,1830209,1830239,1830347,1830748,1830911,1830923,1831157-1831158,1831163,1831190,1831374,1831560,1831689,1832258,1832376,1832379,1832535,1833308,1833347,1833702,1833833,1834109,1834112,1834117,1834287,1834291,1834302,1834312,1834326,1834328,1834336,1834428,1834468,1834483,1834610,1834648-1834649,1834681,1834823,1834857-1834858,1835056,1835060,1835062,1835518,1835521,1835635,1835642,1835780,1835819,1836082,1836121,1836167-1836168,1836170-1836187,1836189-1836196,1836206,1836487,1836493,1836548,1837057,1837274,1837296,1837326,1837475,1837503,1837547,1837569,1837596,1837600,1837657,1837718,1837998,1838076,1838637,1839549,1839570,1839637,1839746,1840019,1840024,1840031,1840226,1840455,1840462,1840574,1840769,1841314,1841352,1841909,1842089,1842240,1842677,1843175,1843222,1843231,1843398,1843618,1843621,1843637,1843652,1843669,1843905,1843911,1843994,1844070,1844110,1844325,1844549,1844625,1844627,1844642,1844728,1844775,1844932,1845135,1845336,1845405,1845
 415,1845730-1845731,1845863,1845865,1846057,1846162,1846396,1846429,1846486,1846581,1846617,1847088,1847096,1848073,1848181-1848182,1848191,1848217,1848729,1848769,1848822-1848823,1850221,1850319,1850343,1850837,1850874,1851533-1851535,1851619,1852120,1852135,1852451,1852492-1852493,1852528,1852582,1852584,1852601,1853083,1853141,1853229,1853393,1853429,1853433,1853435,1853866,1853868,1853870,1853893,1853969,1853997,1854034,1854044,1854055,1854113,1854373,1854377,1854380,1854385,1854401,1854403,1854455,1854461-1854462,1854466,1854468,1854515,1854539,1854701,1854773-1854774,1854827,1854848,1854859,1854930,1855032,1855522,1855776,1855905,1855993,1856049,1856056,1856538,1856545,1856818,1857000,1857010,1857221,1857242,1857247,1857253,1857294,1857314,1857332,1857463,1857480,1857634,1857638,1857936,1858032,1858139,1858385,1858424,1858571,1858578,1858810,1858926,1859020,1859231,1859292,1859294,1859533,1859609,1859612,1859711,1859716,1859772,1859776,1859780,1859843,1859881,1860120,1860131,1
 860137,1860202,1860328,1860548,1860564-1860565,1861114,1861626,1861743,1861757,1862044,1862370,1862422,1862448,1862465,1862499,1862536,1862728,1862881,1863540,1864349,1864353
 /jackrabbit/trunk:1345480

Copied: jackrabbit/oak/branches/1.8/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/VersionGCRecommendations.java (from r1862465, jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/VersionGCRecommendations.java)
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.8/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/VersionGCRecommendations.java?p2=jackrabbit/oak/branches/1.8/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/VersionGCRecommendations.java&p1=jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/VersionGCRecommendations.java&r1=1862465&r2=1865335&rev=1865335&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/VersionGCRecommendations.java (original)
+++ jackrabbit/oak/branches/1.8/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/VersionGCRecommendations.java Sat Aug 17 05:09:02 2019
@@ -25,6 +25,7 @@ import org.apache.jackrabbit.oak.plugins
 import org.apache.jackrabbit.oak.plugins.document.util.TimeInterval;
 import org.apache.jackrabbit.oak.plugins.document.util.Utils;
 import org.apache.jackrabbit.oak.spi.gc.GCMonitor;
+import org.apache.jackrabbit.oak.stats.Clock;
 
 import com.google.common.collect.Maps;
 
@@ -62,17 +63,18 @@ public class VersionGCRecommendations {
      * It also updates the time interval recommended for the next run.
      *
      * @param maxRevisionAgeMs the minimum age for revisions to be collected
-     * @param dns DocumentNodeStore to use
+     * @param checkpoints checkpoints from {@link DocumentNodeStore}
+     * @param clock clock from {@link DocumentNodeStore}
      * @param vgc VersionGC support class
      * @param options options for running the gc
      * @param gcMonitor monitor class for messages
      */
-    public VersionGCRecommendations(long maxRevisionAgeMs, DocumentNodeStore dns, VersionGCSupport vgc,
+    public VersionGCRecommendations(long maxRevisionAgeMs, Checkpoints checkpoints, Clock clock, VersionGCSupport vgc,
             VersionGCOptions options, GCMonitor gcMonitor) {
         this.vgc = vgc;
         this.gcmon = gcMonitor;
 
-        TimeInterval keep = new TimeInterval(dns.getClock().getTime() - maxRevisionAgeMs, Long.MAX_VALUE);
+        TimeInterval keep = new TimeInterval(clock.getTime() - maxRevisionAgeMs, Long.MAX_VALUE);
         boolean ignoreDueToCheckPoint = false;
         long deletedOnceCount = 0;
         long suggestedIntervalMs;
@@ -83,7 +85,7 @@ public class VersionGCRecommendations {
         lastOldestTimestamp = settings.get(VersionGarbageCollector.SETTINGS_COLLECTION_OLDEST_TIMESTAMP_PROP);
         if (lastOldestTimestamp == 0) {
             VersionGarbageCollector.log.debug("No lastOldestTimestamp found, querying for the oldest deletedOnce candidate");
-            oldestPossible = vgc.getOldestDeletedOnceTimestamp(dns.getClock(), options.precisionMs) - 1;
+            oldestPossible = vgc.getOldestDeletedOnceTimestamp(clock, options.precisionMs) - 1;
             VersionGarbageCollector.log.debug("lastOldestTimestamp found: {}", Utils.timestampToString(oldestPossible));
         } else {
             oldestPossible = lastOldestTimestamp - 1;
@@ -127,7 +129,7 @@ public class VersionGCRecommendations {
         }
 
         //Check for any registered checkpoint which prevent the GC from running
-        Revision checkpoint = dns.getCheckpoints().getOldestRevisionToKeep();
+        Revision checkpoint = checkpoints.getOldestRevisionToKeep();
         if (checkpoint != null && scope.endsAfter(checkpoint.getTimestamp())) {
             TimeInterval minimalScope = scope.startAndDuration(options.precisionMs);
             if (minimalScope.endsAfter(checkpoint.getTimestamp())) {

Modified: jackrabbit/oak/branches/1.8/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/VersionGarbageCollector.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.8/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/VersionGarbageCollector.java?rev=1865335&r1=1865334&r2=1865335&view=diff
==============================================================================
--- jackrabbit/oak/branches/1.8/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/VersionGarbageCollector.java (original)
+++ jackrabbit/oak/branches/1.8/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/VersionGarbageCollector.java Sat Aug 17 05:09:02 2019
@@ -76,7 +76,7 @@ public class VersionGarbageCollector {
     private static final int PROGRESS_BATCH_SIZE = 10000;
     private static final String STATUS_IDLE = "IDLE";
     private static final String STATUS_INITIALIZING = "INITIALIZING";
-    private static final Logger log = LoggerFactory.getLogger(VersionGarbageCollector.class);
+    static final Logger log = LoggerFactory.getLogger(VersionGarbageCollector.class);
 
     /**
      * Split document types which can be safely garbage collected
@@ -87,17 +87,17 @@ public class VersionGarbageCollector {
     /**
      * Document id stored in settings collection that keeps info about version gc
      */
-    private static final String SETTINGS_COLLECTION_ID = "versionGC";
+    static final String SETTINGS_COLLECTION_ID = "versionGC";
 
     /**
      * Property name to timestamp when last gc run happened
      */
-    private static final String SETTINGS_COLLECTION_OLDEST_TIMESTAMP_PROP = "lastOldestTimeStamp";
+    static final String SETTINGS_COLLECTION_OLDEST_TIMESTAMP_PROP = "lastOldestTimeStamp";
 
     /**
      * Property name to recommended time interval for next collection run
      */
-    private static final String SETTINGS_COLLECTION_REC_INTERVAL_PROP = "recommendedIntervalMs";
+    static final String SETTINGS_COLLECTION_REC_INTERVAL_PROP = "recommendedIntervalMs";
 
     private final DocumentNodeStore nodeStore;
     private final DocumentStore ds;
@@ -202,7 +202,8 @@ public class VersionGarbageCollector {
             throws IOException {
         long maxRevisionAgeInMillis = unit.toMillis(maxRevisionAge);
         long now = nodeStore.getClock().getTime();
-        Recommendations rec = new Recommendations(maxRevisionAgeInMillis, options);
+        VersionGCRecommendations rec = new VersionGCRecommendations(maxRevisionAgeInMillis, nodeStore.getCheckpoints(),
+                nodeStore.getClock(), versionStore, options, gcMonitor);
         int estimatedIterations = -1;
         if (rec.suggestedIntervalMs > 0) {
             estimatedIterations = (int)Math.ceil(
@@ -484,7 +485,8 @@ public class VersionGarbageCollector {
         private VersionGCStats gc(long maxRevisionAgeInMillis) throws IOException {
             VersionGCStats stats = new VersionGCStats();
             stats.active.start();
-            Recommendations rec = new Recommendations(maxRevisionAgeInMillis, options);
+            VersionGCRecommendations rec = new VersionGCRecommendations(maxRevisionAgeInMillis, nodeStore.getCheckpoints(),
+                    nodeStore.getClock(), versionStore, options, gcMonitor);
             GCPhases phases = new GCPhases(cancel, stats, gcMonitor);
             try {
                 if (rec.ignoreDueToCheckPoint) {
@@ -515,7 +517,7 @@ public class VersionGarbageCollector {
 
         private void collectSplitDocuments(GCPhases phases,
                                            RevisionVector sweepRevisions,
-                                           Recommendations rec) {
+                                           VersionGCRecommendations rec) {
             if (phases.start(GCPhase.SPLITS_CLEANUP)) {
                 int splitDocGCCount = phases.stats.splitDocGCCount;
                 int intermediateSplitDocGCCount = phases.stats.intermediateSplitDocGCCount;
@@ -528,7 +530,7 @@ public class VersionGarbageCollector {
 
         private void collectDeletedDocuments(GCPhases phases,
                                              RevisionVector headRevision,
-                                             Recommendations rec)
+                                             VersionGCRecommendations rec)
                 throws IOException, LimitExceededException {
             int docsTraversed = 0;
             DeletedDocsGC gc = new DeletedDocsGC(headRevision, cancel, options, monitor);
@@ -1017,184 +1019,6 @@ public class VersionGarbageCollector {
         }
     };
 
-    private class Recommendations {
-        final boolean ignoreDueToCheckPoint;
-        final TimeInterval scope;
-        final long maxCollect;
-        final long deleteCandidateCount;
-        final long lastOldestTimestamp;
-
-        private final long precisionMs;
-        private final long suggestedIntervalMs;
-        private final boolean scopeIsComplete;
-
-        /**
-         * Gives a recommendation about parameters for the next revision garbage collection run.
-         * <p>
-         * With the given maximum age of revisions to keep (earliest time in the past to collect),
-         * the desired precision in which times shall be sliced and the given limit on the number
-         * of collected documents in one run, calculate <ol>
-         *     <li>if gc shall run at all (ignoreDueToCheckPoint)</li>
-         *     <li>in which time interval documents shall be collected (scope)</li>
-         *     <li>if collection should fail if it reaches maxCollect documents, maxCollect will specify
-         *     the limit or be 0 if no limit shall be enforced.</li>
-         * </ol>
-         * After a run, recommendations evaluate the result of the gc to update its persisted recommendations
-         * for future runs.
-         * <p>
-         * In the settings collection, recommendations keeps "revisionsOlderThan" from the last successful run.
-         * It also updates the time interval recommended for the next run.
-         *
-         * @param maxRevisionAgeMs the minimum age for revisions to be collected
-         * @param options options for running the gc
-         */
-        Recommendations(long maxRevisionAgeMs, VersionGCOptions options) {
-            TimeInterval keep = new TimeInterval(nodeStore.getClock().getTime() - maxRevisionAgeMs, Long.MAX_VALUE);
-            boolean ignoreDueToCheckPoint = false;
-            long deletedOnceCount = 0;
-            long suggestedIntervalMs;
-            long oldestPossible;
-            long collectLimit = options.collectLimit;
-
-            Map<String, Long> settings = getLongSettings();
-            lastOldestTimestamp = settings.get(SETTINGS_COLLECTION_OLDEST_TIMESTAMP_PROP);
-            if (lastOldestTimestamp == 0) {
-                log.debug("No lastOldestTimestamp found, querying for the oldest deletedOnce candidate");
-                oldestPossible = versionStore.getOldestDeletedOnceTimestamp(nodeStore.getClock(), options.precisionMs) - 1;
-                log.debug("lastOldestTimestamp found: {}", Utils.timestampToString(oldestPossible));
-            } else {
-                oldestPossible = lastOldestTimestamp - 1;
-            }
-
-            TimeInterval scope = new TimeInterval(oldestPossible, Long.MAX_VALUE);
-            scope = scope.notLaterThan(keep.fromMs);
-
-            suggestedIntervalMs = settings.get(SETTINGS_COLLECTION_REC_INTERVAL_PROP);
-            if (suggestedIntervalMs > 0) {
-                suggestedIntervalMs = Math.max(suggestedIntervalMs, options.precisionMs);
-                if (suggestedIntervalMs < scope.getDurationMs()) {
-                    scope = scope.startAndDuration(suggestedIntervalMs);
-                    log.debug("previous runs recommend a {} sec duration, scope now {}",
-                            TimeUnit.MILLISECONDS.toSeconds(suggestedIntervalMs), scope);
-                }
-            } else if (scope.getDurationMs() <= options.precisionMs) {
-                // the scope is smaller than the minimum precision
-                // -> no need to refine the scope
-                log.debug("scope <= precision ({} ms)", options.precisionMs);
-            } else {
-                /* Need to guess. Count the overall number of _deletedOnce documents. If those
-                 * are more than we want to collect in a single run, reduce the time scope so
-                 * that we likely see a fitting fraction of those documents.
-                 */
-                try {
-                    long preferredLimit = Math.min(collectLimit, (long)Math.ceil(options.overflowToDiskThreshold * 0.95));
-                    deletedOnceCount = versionStore.getDeletedOnceCount();
-                    if (deletedOnceCount > preferredLimit) {
-                        double chunks = ((double) deletedOnceCount) / preferredLimit;
-                        suggestedIntervalMs = (long) Math.floor((scope.getDurationMs() + maxRevisionAgeMs) / chunks);
-                        if (suggestedIntervalMs < scope.getDurationMs()) {
-                            scope = scope.startAndDuration(suggestedIntervalMs);
-                            log.debug("deletedOnce candidates: {} found, {} preferred, scope now {}",
-                                    deletedOnceCount, preferredLimit, scope);
-                        }
-                    }
-                } catch (UnsupportedOperationException ex) {
-                    log.debug("check on upper bounds of delete candidates not supported, skipped");
-                }
-            }
-
-            //Check for any registered checkpoint which prevent the GC from running
-            Revision checkpoint = nodeStore.getCheckpoints().getOldestRevisionToKeep();
-            if (checkpoint != null && scope.endsAfter(checkpoint.getTimestamp())) {
-                TimeInterval minimalScope = scope.startAndDuration(options.precisionMs);
-                if (minimalScope.endsAfter(checkpoint.getTimestamp())) {
-                    log.warn("Ignoring RGC run because a valid checkpoint [{}] exists inside minimal scope {}.",
-                            checkpoint.toReadableString(), minimalScope);
-                    ignoreDueToCheckPoint = true;
-                } else {
-                    scope = scope.notLaterThan(checkpoint.getTimestamp() - 1);
-                    log.debug("checkpoint at [{}] found, scope now {}",
-                            Utils.timestampToString(checkpoint.getTimestamp()), scope);
-                }
-            }
-
-            if (scope.getDurationMs() <= options.precisionMs) {
-                // If we have narrowed the collect time interval down as much as we can, no
-                // longer enforce a limit. We need to get through this.
-                collectLimit = 0;
-                log.debug("time interval <= precision ({} ms), disabling collection limits", options.precisionMs);
-            }
-
-            this.precisionMs = options.precisionMs;
-            this.ignoreDueToCheckPoint = ignoreDueToCheckPoint;
-            this.scope = scope;
-            this.scopeIsComplete = scope.toMs >= keep.fromMs;
-            this.maxCollect = collectLimit;
-            this.suggestedIntervalMs = suggestedIntervalMs;
-            this.deleteCandidateCount = deletedOnceCount;
-        }
-
-        /**
-         * Evaluate the results of the last run. Update recommendations for future runs.
-         * Will set {@link VersionGCStats#needRepeat} if collection needs to run another
-         * iteration for collecting documents up to "now".
-         *
-         * @param stats the statistics from the last run
-         */
-        public void evaluate(VersionGCStats stats) {
-            if (stats.limitExceeded) {
-                // if the limit was exceeded, slash the recommended interval in half.
-                long nextDuration = Math.max(precisionMs, scope.getDurationMs() / 2);
-                gcMonitor.info("Limit {} documents exceeded, reducing next collection interval to {} seconds",
-                        this.maxCollect, TimeUnit.MILLISECONDS.toSeconds(nextDuration));
-                setLongSetting(SETTINGS_COLLECTION_REC_INTERVAL_PROP, nextDuration);
-                stats.needRepeat = true;
-            } else if (!stats.canceled && !stats.ignoredGCDueToCheckPoint) {
-                // success, we would not expect to encounter revisions older than this in the future
-                setLongSetting(SETTINGS_COLLECTION_OLDEST_TIMESTAMP_PROP, scope.toMs);
-
-                if (maxCollect <= 0) {
-                    log.debug("successful run without effective limit, keeping recommendations");
-                } else if (scope.getDurationMs() == suggestedIntervalMs) {
-                    int count = stats.deletedDocGCCount - stats.deletedLeafDocGCCount;
-                    double used = count / (double) maxCollect;
-                    if (used < 0.66) {
-                        long nextDuration = (long) Math.ceil(suggestedIntervalMs * 1.5);
-                        log.debug("successful run using {}% of limit, raising recommended interval to {} seconds",
-                                Math.round(used*1000)/10.0, TimeUnit.MILLISECONDS.toSeconds(nextDuration));
-                        setLongSetting(SETTINGS_COLLECTION_REC_INTERVAL_PROP, nextDuration);
-                    }
-                } else {
-                    log.debug("successful run not following recommendations, keeping them");
-                }
-                stats.needRepeat = !scopeIsComplete;
-            }
-        }
-
-        private Map<String, Long> getLongSettings() {
-            Document versionGCDoc = ds.find(Collection.SETTINGS, SETTINGS_COLLECTION_ID, 0);
-            Map<String, Long> settings = Maps.newHashMap();
-            // default values
-            settings.put(SETTINGS_COLLECTION_OLDEST_TIMESTAMP_PROP, 0L);
-            settings.put(SETTINGS_COLLECTION_REC_INTERVAL_PROP, 0L);
-            if (versionGCDoc != null) {
-                for (String k : versionGCDoc.keySet()) {
-                    Object value = versionGCDoc.get(k);
-                    if (value instanceof Number) {
-                        settings.put(k, ((Number) value).longValue());
-                    }
-                }
-            }
-            return settings;
-        }
-
-        private void setLongSetting(String propName, long val) {
-            UpdateOp updateOp = new UpdateOp(SETTINGS_COLLECTION_ID, true);
-            updateOp.set(propName, val);
-            ds.createOrUpdate(Collection.SETTINGS, updateOp);
-        }
-    }
-
     /**
      * GCMessageTracker is a partial implementation of GCMonitor. We use it to
      * keep track of the last message issued by the GC job.

Modified: jackrabbit/oak/branches/1.8/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/VersionGCTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.8/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/VersionGCTest.java?rev=1865335&r1=1865334&r2=1865335&view=diff
==============================================================================
--- jackrabbit/oak/branches/1.8/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/VersionGCTest.java (original)
+++ jackrabbit/oak/branches/1.8/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/VersionGCTest.java Sat Aug 17 05:09:02 2019
@@ -194,13 +194,7 @@ public class VersionGCTest {
 
     @Test
     public void gcMonitorStatusUpdates() throws Exception {
-        final List<String> statusMessages = Lists.newArrayList();
-        GCMonitor monitor = new GCMonitor.Empty() {
-            @Override
-            public void updateStatus(String status) {
-                statusMessages.add(status);
-            }
-        };
+        TestGCMonitor monitor = new TestGCMonitor();
         gc.setGCMonitor(monitor);
 
         gc.gc(30, TimeUnit.MINUTES);
@@ -208,22 +202,17 @@ public class VersionGCTest {
         List<String> expected = Lists.newArrayList("INITIALIZING",
                 "COLLECTING", "CHECKING", "COLLECTING", "DELETING", "SORTING",
                 "DELETING", "UPDATING", "SPLITS_CLEANUP", "IDLE");
-        assertEquals(expected, statusMessages);
+        assertEquals(expected, monitor.getStatusMessages());
     }
 
     @Test
     public void gcMonitorInfoMessages() throws Exception {
-        final List<String> infoMessages = Lists.newArrayList();
-        GCMonitor monitor = new GCMonitor.Empty() {
-            @Override
-            public void info(String message, Object... arguments) {
-                infoMessages.add(arrayFormat(message, arguments).getMessage());
-            }
-        };
+        TestGCMonitor monitor = new TestGCMonitor();
         gc.setGCMonitor(monitor);
 
         gc.gc(2, TimeUnit.HOURS);
 
+        List<String> infoMessages = monitor.getInfoMessages();
         assertEquals(3, infoMessages.size());
         assertTrue(infoMessages.get(0).startsWith("Start "));
         assertTrue(infoMessages.get(1).startsWith("Looking at revisions"));
@@ -238,6 +227,38 @@ public class VersionGCTest {
         assertEquals(1, store.findVersionGC.get());
     }
 
+    @Test
+    public void recommendationsOnHugeBacklog() throws Exception {
+
+        VersionGCOptions options = gc.getOptions();
+        final long oneYearAgo = ns.getClock().getTime() - TimeUnit.DAYS.toMillis(365);
+        final long twelveTimesTheLimit = options.collectLimit * 12;
+        final long secondsPerDay = TimeUnit.DAYS.toMillis(1);
+
+        VersionGCSupport localgcsupport = fakeVersionGCSupport(ns.getDocumentStore(), oneYearAgo, twelveTimesTheLimit);
+
+        VersionGCRecommendations rec = new VersionGCRecommendations(secondsPerDay, ns.getCheckpoints(), ns.getClock(), localgcsupport,
+                options, new TestGCMonitor());
+
+        // should select a duration of roughly one month
+        long duration= rec.scope.getDurationMs();
+
+        assertTrue(duration <= TimeUnit.DAYS.toMillis(33));
+        assertTrue(duration >= TimeUnit.DAYS.toMillis(28));
+
+        VersionGCStats stats = new VersionGCStats();
+        stats.limitExceeded = true;
+        rec.evaluate(stats);
+        assertTrue(stats.needRepeat);
+
+        rec = new VersionGCRecommendations(secondsPerDay, ns.getCheckpoints(), ns.getClock(), localgcsupport, options,
+                new TestGCMonitor());
+
+        // new duration should be half
+        long nduration = rec.scope.getDurationMs();
+        assertTrue(nduration == duration / 2);
+    }
+
     // OAK-7378
     @Test
     public void recommendedInterval() throws Exception {
@@ -332,4 +353,61 @@ public class VersionGCTest {
         }
     }
 
+    private class TestGCMonitor implements GCMonitor {
+        final List<String> infoMessages = Lists.newArrayList();
+        final List<String> statusMessages = Lists.newArrayList();
+
+        @Override
+        public void info(String message, Object... arguments) {
+            this.infoMessages.add(arrayFormat(message, arguments).getMessage());
+        }
+
+        @Override
+        public void warn(String message, Object... arguments) {
+        }
+
+        @Override
+        public void error(String message, Exception exception) {
+        }
+
+        @Override
+        public void skipped(String reason, Object... arguments) {
+        }
+
+        @Override
+        public void compacted() {
+        }
+
+        @Override
+        public void cleaned(long reclaimedSize, long currentSize) {
+        }
+
+        @Override
+        public void updateStatus(String status) {
+            this.statusMessages.add(status);
+        }
+
+        public List<String> getInfoMessages() {
+            return this.infoMessages;
+        }
+
+        public List<String> getStatusMessages() {
+            return this.statusMessages;
+        }
+    }
+
+    private VersionGCSupport fakeVersionGCSupport(final DocumentStore ds, final long oldestDeleted, final long countDeleted) {
+        return new VersionGCSupport(ds) {
+
+            @Override
+            public long getOldestDeletedOnceTimestamp(Clock clock, long precisionMs) {
+                return oldestDeleted;
+            }
+
+            @Override
+            public long getDeletedOnceCount() {
+                return countDeleted;
+            }
+        };
+    }
 }