Author: amitj
Date: Fri Jun  1 10:42:02 2018
New Revision: 1832676

URL: http://svn.apache.org/viewvc?rev=1832676&view=rev
Log:
OAK-7522: Enable collection of simple operation stats for DataStore garbage 
collection

Added simple metrics for dsgc

Added:
    
jackrabbit/oak/trunk/oak-blob-plugins/src/main/java/org/apache/jackrabbit/oak/plugins/blob/OperationStatsCollector.java
   (with props)
    
jackrabbit/oak/trunk/oak-blob-plugins/src/main/java/org/apache/jackrabbit/oak/plugins/blob/OperationsStatsMBean.java
   (with props)
Modified:
    
jackrabbit/oak/trunk/oak-blob-plugins/src/main/java/org/apache/jackrabbit/oak/plugins/blob/BlobGC.java
    
jackrabbit/oak/trunk/oak-blob-plugins/src/main/java/org/apache/jackrabbit/oak/plugins/blob/BlobGCMBean.java
    
jackrabbit/oak/trunk/oak-blob-plugins/src/main/java/org/apache/jackrabbit/oak/plugins/blob/BlobGarbageCollector.java
    
jackrabbit/oak/trunk/oak-blob-plugins/src/main/java/org/apache/jackrabbit/oak/plugins/blob/MarkSweepGarbageCollector.java
    
jackrabbit/oak/trunk/oak-blob-plugins/src/test/java/org/apache/jackrabbit/oak/plugins/blob/BlobGCTest.java
    
jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentNodeStoreService.java
    
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java
    
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreService.java

Modified: 
jackrabbit/oak/trunk/oak-blob-plugins/src/main/java/org/apache/jackrabbit/oak/plugins/blob/BlobGC.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-blob-plugins/src/main/java/org/apache/jackrabbit/oak/plugins/blob/BlobGC.java?rev=1832676&r1=1832675&r2=1832676&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-blob-plugins/src/main/java/org/apache/jackrabbit/oak/plugins/blob/BlobGC.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-blob-plugins/src/main/java/org/apache/jackrabbit/oak/plugins/blob/BlobGC.java
 Fri Jun  1 10:42:02 2018
@@ -114,27 +114,9 @@ public class  BlobGC extends AnnotatedSt
     public CompositeData getBlobGCStatus() {
         return gcOp.getStatus().toCompositeData();
     }
-    
-    @Override 
-    public TabularData getGlobalMarkStats() {
-        TabularDataSupport tds;
-        try {
-            TabularType tt = new TabularType(BlobGC.class.getName(),
-                                                "Garbage collection global 
mark phase Stats", 
-                                                TYPE,
-                                                new String[] {"repositoryId"});
-            tds = new TabularDataSupport(tt);           
-            List<GarbageCollectionRepoStats> stats = 
blobGarbageCollector.getStats();
-            for (GarbageCollectionRepoStats stat : stats) {
-                tds.put(toCompositeData(stat));
-            }
-        } catch (Exception e) {
-            throw new IllegalStateException(e);
-        }
-        return tds;
-    }
-    
-    @Override 
+
+
+    @Override
     public CompositeData checkConsistency() {
         if (consistencyOp.isDone()) {
             consistencyOp = newManagementOperation(CONSISTENCY_OP_NAME, new 
Callable<String>() {
@@ -143,21 +125,39 @@ public class  BlobGC extends AnnotatedSt
                     long t0 = nanoTime();
                     long missing = blobGarbageCollector.checkConsistency();
                     return "Consistency check completed in "
-                                + formatTime(nanoTime() - t0) + ". " +
-                                + missing + " missing blobs found (details in 
the log).";
+                        + formatTime(nanoTime() - t0) + ". " +
+                        + missing + " missing blobs found (details in the 
log).";
                 }
             });
             executor.execute(consistencyOp);
         }
         return getConsistencyCheckStatus();
     }
-    
+
     @Nonnull
     @Override
     public CompositeData getConsistencyCheckStatus() {
         return consistencyOp.getStatus().toCompositeData();
     }
-    
+
+    @Override 
+    public TabularData getGlobalMarkStats() {
+        TabularDataSupport tds;
+        try {
+            TabularType tt = new TabularType(BlobGC.class.getName(),
+                                                "Garbage collection global 
mark phase Stats", MARK_TYPE,
+                                                new String[] {"repositoryId"});
+            tds = new TabularDataSupport(tt);           
+            List<GarbageCollectionRepoStats> stats = 
blobGarbageCollector.getStats();
+            for (GarbageCollectionRepoStats stat : stats) {
+                tds.put(toCompositeData(stat));
+            }
+        } catch (Exception e) {
+            throw new IllegalStateException(e);
+        }
+        return tds;
+    }
+
     private CompositeDataSupport toCompositeData(GarbageCollectionRepoStats 
statObj) throws OpenDataException {
         Object[] values = new Object[] {
                 statObj.getRepositoryId() + (statObj.isLocal() ? " *" : ""),
@@ -167,10 +167,10 @@ public class  BlobGC extends AnnotatedSt
                 humanReadableByteCount(statObj.getLength()),
                 statObj.getNumLines()
         };
-        return new CompositeDataSupport(TYPE, FIELD_NAMES, values);
+        return new CompositeDataSupport(MARK_TYPE, MARK_FIELD_NAMES, values);
     }
     
-    private static final String[] FIELD_NAMES = new String[] {
+    private static final String[] MARK_FIELD_NAMES = new String[] {
             "repositoryId",
             "markStartTime",
             "markEndTime",
@@ -179,16 +179,16 @@ public class  BlobGC extends AnnotatedSt
             "numReferences",
     };
     
-    private static final String[] FIELD_DESCRIPTIONS = new String[] {
-           "Repository ID", 
+    private static final String[] MARK_FIELD_DESCRIPTIONS = new String[] {
+           "Repository ID",
            "Start time of mark",
            "End time of mark",
            "References file size in bytes",
            "References file size in human readable format",
-           "Number of references" 
+           "Number of references"
     };
     
-    private static final OpenType[] FIELD_TYPES = new OpenType[] {
+    private static final OpenType[] MARK_FIELD_TYPES = new OpenType[] {
             SimpleType.STRING,
             SimpleType.STRING,
             SimpleType.STRING,
@@ -197,18 +197,76 @@ public class  BlobGC extends AnnotatedSt
             SimpleType.INTEGER
     };
     
-    private static final CompositeType TYPE = createCompositeType();
+    private static final CompositeType MARK_TYPE = createMarkCompositeType();
     
-    private static CompositeType createCompositeType() {
+    private static CompositeType createMarkCompositeType() {
         try {
             return new CompositeType(
                     GarbageCollectionRepoStats.class.getName(),
-                    "Composite data type for datastore GC statistics",
-                    FIELD_NAMES,
-                    FIELD_DESCRIPTIONS,
-                    FIELD_TYPES);
+                    "Composite data type for datastore GC statistics", 
MARK_FIELD_NAMES, MARK_FIELD_DESCRIPTIONS,
+                MARK_FIELD_TYPES);
+        } catch (OpenDataException e) {
+            throw new IllegalStateException(e);
+        }
+    }
+
+    @Override
+    public TabularData getOperationStats() {
+        TabularDataSupport tds;
+        try {
+            TabularType tt = new TabularType(BlobGC.class.getName(),
+                "Garbage Collection Operation Stats", OP_STATS_TYPE,
+                OP_STATS_FIELD_NAMES);
+            tds = new TabularDataSupport(tt);
+            OperationsStatsMBean operationStats = 
blobGarbageCollector.getOperationStats();
+            tds.put(toCompositeData(operationStats));
+        } catch (Exception e) {
+            throw new IllegalStateException(e);
+        }
+        return tds;
+    }
+
+    private CompositeData toCompositeData(OperationsStatsMBean statObj) throws 
OpenDataException {
+        Object[] values = new Object[] {
+            statObj.getStartCount(),
+            statObj.getFinishSucessCount(),
+            statObj.getFinishErrorCount(),
+            statObj.duration()
+        };
+        return new CompositeDataSupport(OP_STATS_TYPE, OP_STATS_FIELD_NAMES, 
values);
+    }
+
+    private static final String[] OP_STATS_FIELD_NAMES = new String[] {
+        "startCount",
+        "finishSuccessCount",
+        "finishErrorCount",
+        "duration"
+    };
+
+    private static final String[] OP_STATS_FIELD_DESCRIPTIONS = new String[] {
+        "Start Count",
+        "Finish Success Count",
+        "Finish Error Count",
+        "Duration"
+    };
+
+    private static final OpenType[] OP_STATS_FIELD_TYPES = new OpenType[] {
+        SimpleType.LONG,
+        SimpleType.LONG,
+        SimpleType.LONG,
+        SimpleType.LONG
+    };
+
+    private static final CompositeType OP_STATS_TYPE = 
createOpStatsCompositeType();
+
+    private static CompositeType createOpStatsCompositeType() {
+        try {
+            return new CompositeType(
+                GarbageCollectionRepoStats.class.getName(),
+                "Composite data type for datastore GC operation stats", 
OP_STATS_FIELD_NAMES, OP_STATS_FIELD_DESCRIPTIONS,
+                OP_STATS_FIELD_TYPES);
         } catch (OpenDataException e) {
             throw new IllegalStateException(e);
         }
-    }    
+    }
 }

Modified: 
jackrabbit/oak/trunk/oak-blob-plugins/src/main/java/org/apache/jackrabbit/oak/plugins/blob/BlobGCMBean.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-blob-plugins/src/main/java/org/apache/jackrabbit/oak/plugins/blob/BlobGCMBean.java?rev=1832676&r1=1832675&r2=1832676&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-blob-plugins/src/main/java/org/apache/jackrabbit/oak/plugins/blob/BlobGCMBean.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-blob-plugins/src/main/java/org/apache/jackrabbit/oak/plugins/blob/BlobGCMBean.java
 Fri Jun  1 10:42:02 2018
@@ -77,7 +77,14 @@ public interface BlobGCMBean {
      * @return List of available repositories and their status
      */
     TabularData getGlobalMarkStats();
-    
+
+    /**
+     * Show details of the data Store garbage collection invocations.
+     *
+     * @return Data about all the previous gc invocations
+     */
+    TabularData getOperationStats();
+
     /**
      * Data Store consistency check
      * 

Modified: 
jackrabbit/oak/trunk/oak-blob-plugins/src/main/java/org/apache/jackrabbit/oak/plugins/blob/BlobGarbageCollector.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-blob-plugins/src/main/java/org/apache/jackrabbit/oak/plugins/blob/BlobGarbageCollector.java?rev=1832676&r1=1832675&r2=1832676&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-blob-plugins/src/main/java/org/apache/jackrabbit/oak/plugins/blob/BlobGarbageCollector.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-blob-plugins/src/main/java/org/apache/jackrabbit/oak/plugins/blob/BlobGarbageCollector.java
 Fri Jun  1 10:42:02 2018
@@ -58,4 +58,12 @@ public interface BlobGarbageCollector {
      * @throws Exception
      */
     long checkConsistency() throws Exception;
+
+    /**
+     * Returns operation statistics
+     *
+     * @return stats object
+     * @throws Exception
+     */
+    OperationsStatsMBean getOperationStats() throws Exception;
 }

Modified: 
jackrabbit/oak/trunk/oak-blob-plugins/src/main/java/org/apache/jackrabbit/oak/plugins/blob/MarkSweepGarbageCollector.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-blob-plugins/src/main/java/org/apache/jackrabbit/oak/plugins/blob/MarkSweepGarbageCollector.java?rev=1832676&r1=1832675&r2=1832676&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-blob-plugins/src/main/java/org/apache/jackrabbit/oak/plugins/blob/MarkSweepGarbageCollector.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-blob-plugins/src/main/java/org/apache/jackrabbit/oak/plugins/blob/MarkSweepGarbageCollector.java
 Fri Jun  1 10:42:02 2018
@@ -72,6 +72,10 @@ import org.apache.jackrabbit.oak.plugins
 import org.apache.jackrabbit.oak.spi.blob.GarbageCollectableBlobStore;
 import org.apache.jackrabbit.oak.spi.whiteboard.Whiteboard;
 import org.apache.jackrabbit.oak.spi.whiteboard.WhiteboardUtils;
+import org.apache.jackrabbit.oak.stats.CounterStats;
+import org.apache.jackrabbit.oak.stats.StatisticsProvider;
+import org.apache.jackrabbit.oak.stats.StatsOptions;
+import org.apache.jackrabbit.oak.stats.TimerStats;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -124,6 +128,11 @@ public class MarkSweepGarbageCollector i
 
     private CheckpointMBean checkpointMbean;
 
+    /** Operation stats object **/
+    private final GarbageCollectionOperationStats stats;
+
+    private final OperationStatsCollector statsCollector;
+
     /**
      * Creates an instance of MarkSweepGarbageCollector
      *
@@ -135,7 +144,9 @@ public class MarkSweepGarbageCollector i
      * @param batchCount batch sized used for saving intermediate state
      * @param maxLastModifiedInterval lastModifiedTime in millis. Only files 
with time
      *                                less than this time would be considered 
for GC
-     * @param repositoryId - unique repository id for this node
+     * @param repositoryId unique repository id for this node
+     * @param whiteboard whiteboard instance
+     * @param statisticsProvider statistics provider instance
      * @throws IOException
      */
     public MarkSweepGarbageCollector(
@@ -146,7 +157,8 @@ public class MarkSweepGarbageCollector i
             int batchCount,
             long maxLastModifiedInterval,
             @Nullable String repositoryId,
-            @Nullable Whiteboard whiteboard)
+            @Nullable Whiteboard whiteboard,
+            @Nullable StatisticsProvider statisticsProvider)
             throws IOException {
         this.executor = executor;
         this.blobStore = blobStore;
@@ -159,6 +171,13 @@ public class MarkSweepGarbageCollector i
         if (whiteboard != null) {
             this.checkpointMbean = WhiteboardUtils.getService(whiteboard, 
CheckpointMBean.class);
         }
+
+        // re-initialize the statsProvider if passed as parameter
+        if (statisticsProvider == null) {
+            statisticsProvider = StatisticsProvider.NOOP;
+        }
+        this.stats = new GarbageCollectionOperationStats(statisticsProvider);
+        this.statsCollector = stats.getCollector();
     }
 
     public MarkSweepGarbageCollector(
@@ -170,7 +189,7 @@ public class MarkSweepGarbageCollector i
             long maxLastModifiedInterval,
             @Nullable String repositoryId)
             throws IOException {
-        this(marker, blobStore, executor, root, batchCount, 
maxLastModifiedInterval, repositoryId, null);
+        this(marker, blobStore, executor, root, batchCount, 
maxLastModifiedInterval, repositoryId, null, null);
     }
 
     /**
@@ -182,9 +201,10 @@ public class MarkSweepGarbageCollector i
             Executor executor,
             long maxLastModifiedInterval,
             @Nullable String repositoryId,
-            @Nullable Whiteboard whiteboard)
+            @Nullable Whiteboard whiteboard,
+            @Nullable StatisticsProvider statisticsProvider)
             throws IOException {
-        this(marker, blobStore, executor, TEMP_DIR, DEFAULT_BATCH_COUNT, 
maxLastModifiedInterval, repositoryId, whiteboard);
+        this(marker, blobStore, executor, TEMP_DIR, DEFAULT_BATCH_COUNT, 
maxLastModifiedInterval, repositoryId, whiteboard, statisticsProvider);
     }
 
     @Override
@@ -264,6 +284,10 @@ public class MarkSweepGarbageCollector i
         return stats;
     }
 
+    @Override
+    public OperationsStatsMBean getOperationStats() {
+        return stats;
+    }
 
     /**
      * Mark and sweep. Main entry method for GC.
@@ -273,6 +297,7 @@ public class MarkSweepGarbageCollector i
      * @throws Exception the exception
      */
     protected void markAndSweep(boolean markOnly, boolean forceBlobRetrieve) 
throws Exception {
+        statsCollector.start();
         boolean threw = true;
         GarbageCollectorFileState fs = new GarbageCollectorFileState(root);
         try {
@@ -290,8 +315,15 @@ public class MarkSweepGarbageCollector i
 
                 LOG.info("Blob garbage collection completed in {} ({} ms). 
Number of blobs deleted [{}] with max modification time of [{}]",
                         sw.toString(), sw.elapsed(TimeUnit.MILLISECONDS), 
deleteCount, timestampToString(maxTime));
+            } else {
+                sw.stop();
+                LOG.info("Blob garbage collection Mark completed in {} ({} 
ms).",
+                    sw.toString(), sw.elapsed(TimeUnit.MILLISECONDS));
             }
+            statsCollector.finishSuccess();
+            statsCollector.updateDuration(sw.elapsed(TimeUnit.MILLISECONDS), 
TimeUnit.MILLISECONDS);
         } catch (Exception e) {
+            statsCollector.finishFailure();
             LOG.error("Blob garbage collection error", e);
             throw e;
         } finally {
@@ -935,4 +967,73 @@ public class MarkSweepGarbageCollector i
             return FileIOUtils.writeStrings(iter, fs.getGcCandidates(), true);
         }
     }
+
+    class GarbageCollectionOperationStats implements OperationsStatsMBean {
+        private static final String START = "START";
+        private static final String FINISH_SUCCESS = "FINISH_SUCCESS";
+        private static final String FINISH_FAILURE = "FINISH_FAILURE";
+        private static final String DURATION = "DURATION";
+
+        private CounterStats startCounter;
+        private CounterStats finishSuccessCounter;
+        private CounterStats finishFailureCounter;
+        private TimerStats duration;
+        private final OperationStatsCollector collector;
+
+        GarbageCollectionOperationStats(StatisticsProvider sp) {
+            this.startCounter = sp.getCounterStats(getMetricName(START), 
StatsOptions.METRICS_ONLY);
+            this.finishSuccessCounter = 
sp.getCounterStats(getMetricName(FINISH_SUCCESS), StatsOptions.METRICS_ONLY);
+            this.finishFailureCounter = 
sp.getCounterStats(getMetricName(FINISH_FAILURE), StatsOptions.METRICS_ONLY);
+            this.duration = sp.getTimer(getMetricName(DURATION), 
StatsOptions.METRICS_ONLY);
+            this.collector = new OperationStatsCollector() {
+                @Override
+                public void start() {
+                    startCounter.inc();
+                }
+
+                @Override
+                public void finishSuccess() {
+                    finishSuccessCounter.inc();
+                }
+
+                @Override
+                public void finishFailure() {
+                    finishFailureCounter.inc();
+                }
+
+                @Override
+                public void updateDuration(long time, TimeUnit timeUnit) {
+                    duration.update(time, timeUnit);
+                }
+            };
+        }
+
+        private String getMetricName(String name) {
+            return getName() + "." + name;
+        }
+
+        protected OperationStatsCollector getCollector() {
+            return collector;
+        }
+
+        @Override public String getName() {
+            return TYPE + "." + 
GarbageCollectionOperationStats.class.getSimpleName();
+        }
+
+        @Override public long getStartCount() {
+            return startCounter.getCount();
+        }
+
+        @Override public long getFinishSucessCount() {
+            return finishSuccessCounter.getCount();
+        }
+
+        @Override public long getFinishErrorCount() {
+            return finishFailureCounter.getCount();
+        }
+
+        @Override public long duration() {
+            return duration.getCount();
+        }
+    }
 }

Added: 
jackrabbit/oak/trunk/oak-blob-plugins/src/main/java/org/apache/jackrabbit/oak/plugins/blob/OperationStatsCollector.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-blob-plugins/src/main/java/org/apache/jackrabbit/oak/plugins/blob/OperationStatsCollector.java?rev=1832676&view=auto
==============================================================================
--- 
jackrabbit/oak/trunk/oak-blob-plugins/src/main/java/org/apache/jackrabbit/oak/plugins/blob/OperationStatsCollector.java
 (added)
+++ 
jackrabbit/oak/trunk/oak-blob-plugins/src/main/java/org/apache/jackrabbit/oak/plugins/blob/OperationStatsCollector.java
 Fri Jun  1 10:42:02 2018
@@ -0,0 +1,64 @@
+/*
+ * 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.plugins.blob;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Implementations of this can use to mark the relevant statistics.
+ */
+public interface OperationStatsCollector {
+    OperationStatsCollector NOOP = new OperationStatsCollector() {
+        public void start() {
+        }
+
+        public void finishSuccess() {
+        }
+
+        public void finishFailure() {
+        }
+
+        public void updateDuration(long time, TimeUnit timeUnit) {
+        }
+    };
+
+    /**
+     * Increment the start counter
+     */
+    void start();
+
+    /**
+     * Increment the finishSuccess counter
+     */
+    void finishSuccess();
+
+    /**
+     * Increment the finishFailure counter
+     */
+    void finishFailure();
+
+    /**
+     * Increment the duration timer
+     *
+     * @param time time recorded for the operation
+     * @param timeUnit unit of time
+     */
+    void updateDuration(long time, TimeUnit timeUnit);
+}

Propchange: 
jackrabbit/oak/trunk/oak-blob-plugins/src/main/java/org/apache/jackrabbit/oak/plugins/blob/OperationStatsCollector.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: 
jackrabbit/oak/trunk/oak-blob-plugins/src/main/java/org/apache/jackrabbit/oak/plugins/blob/OperationsStatsMBean.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-blob-plugins/src/main/java/org/apache/jackrabbit/oak/plugins/blob/OperationsStatsMBean.java?rev=1832676&view=auto
==============================================================================
--- 
jackrabbit/oak/trunk/oak-blob-plugins/src/main/java/org/apache/jackrabbit/oak/plugins/blob/OperationsStatsMBean.java
 (added)
+++ 
jackrabbit/oak/trunk/oak-blob-plugins/src/main/java/org/apache/jackrabbit/oak/plugins/blob/OperationsStatsMBean.java
 Fri Jun  1 10:42:02 2018
@@ -0,0 +1,56 @@
+/*
+ * 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.plugins.blob;
+
+/**
+ * Interface to give useful statistics for maintenance operations.
+ */
+public interface OperationsStatsMBean {
+    String TYPE = "OperationStats";
+
+    String getName();
+
+    /**
+     * Returns the start counts of the operation
+     *
+     * @return
+     */
+    long getStartCount();
+
+    /**
+     * Returns the finish success count
+     *
+     * @return
+     */
+    long getFinishSucessCount();
+
+    /**
+     * Returns the finish error count
+     *
+     * @return
+     */
+    long getFinishErrorCount();
+
+    /**
+     * Returns the duration of the operation
+     * @return
+     */
+    long duration();
+}

Propchange: 
jackrabbit/oak/trunk/oak-blob-plugins/src/main/java/org/apache/jackrabbit/oak/plugins/blob/OperationsStatsMBean.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: 
jackrabbit/oak/trunk/oak-blob-plugins/src/test/java/org/apache/jackrabbit/oak/plugins/blob/BlobGCTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-blob-plugins/src/test/java/org/apache/jackrabbit/oak/plugins/blob/BlobGCTest.java?rev=1832676&r1=1832675&r2=1832676&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-blob-plugins/src/test/java/org/apache/jackrabbit/oak/plugins/blob/BlobGCTest.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-blob-plugins/src/test/java/org/apache/jackrabbit/oak/plugins/blob/BlobGCTest.java
 Fri Jun  1 10:42:02 2018
@@ -69,6 +69,7 @@ import org.apache.jackrabbit.oak.spi.whi
 import org.apache.jackrabbit.oak.spi.whiteboard.Registration;
 import org.apache.jackrabbit.oak.spi.whiteboard.Whiteboard;
 import org.apache.jackrabbit.oak.stats.Clock;
+import org.apache.jackrabbit.oak.stats.DefaultStatisticsProvider;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -177,17 +178,42 @@ public class BlobGCTest {
         assertTrue(Sets.symmetricDifference(state.blobsPresent, 
existingAfterGC).isEmpty());
     }
 
+    @Test
+    public void gcMarkOnly() throws Exception {
+        log.info("Staring gcMarkOnly()");
+
+        BlobStoreState state = setUp(10, 5, 100);
+
+        log.info("{} blobs added : {}", state.blobsAdded.size(), 
state.blobsAdded);
+        log.info("{} blobs remaining : {}", state.blobsPresent.size(), 
state.blobsPresent);
+
+        Set<String> existingAfterGC = gcInternal(0, true);
+        assertTrue(Sets.symmetricDifference(state.blobsAdded, 
existingAfterGC).isEmpty());
+    }
+
     protected Set<String> gcInternal(long maxBlobGcInSecs) throws Exception {
+        return gcInternal(maxBlobGcInSecs, false);
+    }
+
+    protected Set<String> gcInternal(long maxBlobGcInSecs, boolean markOnly) 
throws Exception {
         ThreadPoolExecutor executor = (ThreadPoolExecutor) 
Executors.newFixedThreadPool(10);
         MarkSweepGarbageCollector gc = initGC(maxBlobGcInSecs, executor);
-        gc.collectGarbage(false);
+        gc.collectGarbage(markOnly);
 
         assertEquals(0, executor.getTaskCount());
         Set<String> existingAfterGC = iterate();
         log.info("{} blobs existing after gc : {}", existingAfterGC.size(), 
existingAfterGC);
+        assertStats(gc.getOperationStats());
+
         return existingAfterGC;
     }
 
+    private void assertStats(OperationsStatsMBean operationStats) {
+        assertEquals("Start counter mismatch", 1, 
operationStats.getStartCount());
+        assertEquals("Finish success mismatch", 1, 
operationStats.getFinishSucessCount());
+        assertEquals("Finish error mismatch", 0, 
operationStats.getFinishErrorCount());
+    }
+
     private MarkSweepGarbageCollector initGC(long blobGcMaxAgeInSecs, 
ThreadPoolExecutor executor)
         throws Exception {
         return initGC(blobGcMaxAgeInSecs, executor, 
folder.newFolder().getAbsolutePath());
@@ -195,6 +221,7 @@ public class BlobGCTest {
 
     private MarkSweepGarbageCollector initGC(long blobGcMaxAgeInSecs, 
ThreadPoolExecutor executor,
         String root) throws Exception {
+        DefaultStatisticsProvider statsProvider = new 
DefaultStatisticsProvider(Executors.newSingleThreadScheduledExecutor());
         String repoId = null;
         if (SharedDataStoreUtils.isShared(blobStore)) {
             repoId = ClusterRepositoryInfo.getOrCreateId(nodeStore);
@@ -206,7 +233,7 @@ public class BlobGCTest {
         MarkSweepGarbageCollector gc =
             new MarkSweepGarbageCollector(referenceRetriever,
                 blobStore, executor,
-                root, 2048, blobGcMaxAgeInSecs, repoId, wb);
+                root, 2048, blobGcMaxAgeInSecs, repoId, wb, statsProvider);
         return gc;
     }
 

Modified: 
jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentNodeStoreService.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentNodeStoreService.java?rev=1832676&r1=1832675&r2=1832676&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentNodeStoreService.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentNodeStoreService.java
 Fri Jun  1 10:42:02 2018
@@ -689,7 +689,8 @@ public class SegmentNodeStoreService {
                     executor,
                     TimeUnit.SECONDS.toMillis(configuration.getBlobGcMaxAge()),
                     getOrCreateId(segmentNodeStore),
-                    whiteboard
+                    whiteboard,
+                    statisticsProvider
             );
             closeables.add(registrations.registerMBean(
                     BlobGCMBean.class,

Modified: 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java?rev=1832676&r1=1832675&r2=1832676&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java
 Fri Jun  1 10:42:02 2018
@@ -125,6 +125,7 @@ import org.apache.jackrabbit.oak.spi.sta
 import org.apache.jackrabbit.oak.spi.whiteboard.Whiteboard;
 import org.apache.jackrabbit.oak.stats.Clock;
 import org.apache.jackrabbit.oak.commons.PerfLogger;
+import org.apache.jackrabbit.oak.stats.StatisticsProvider;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -2960,11 +2961,12 @@ public final class DocumentNodeStore
      * @param blobGcMaxAgeInSecs
      * @param repositoryId
      * @param whiteboard
+     * @param statisticsProvider
      * @return garbage collector of the BlobStore supports GC otherwise null
      */
     @CheckForNull
     public MarkSweepGarbageCollector createBlobGarbageCollector(long 
blobGcMaxAgeInSecs, String repositoryId,
-        Whiteboard whiteboard) {
+        Whiteboard whiteboard, StatisticsProvider statisticsProvider) {
         MarkSweepGarbageCollector blobGC = null;
         if(blobStore instanceof GarbageCollectableBlobStore){
             try {
@@ -2974,7 +2976,8 @@ public final class DocumentNodeStore
                         executor,
                         SECONDS.toMillis(blobGcMaxAgeInSecs),
                         repositoryId,
-                        whiteboard);
+                        whiteboard,
+                        statisticsProvider);
             } catch (IOException e) {
                 throw new RuntimeException("Error occurred while initializing 
" +
                         "the MarkSweepGarbageCollector",e);

Modified: 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreService.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreService.java?rev=1832676&r1=1832675&r2=1832676&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreService.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreService.java
 Fri Jun  1 10:42:02 2018
@@ -746,7 +746,7 @@ public class DocumentNodeStoreService {
         if (store.getBlobStore() instanceof GarbageCollectableBlobStore) {
             BlobGarbageCollector gc = 
store.createBlobGarbageCollector(blobGcMaxAgeInSecs, 
                                                         
ClusterRepositoryInfo.getOrCreateId(nodeStore),
-                                                        whiteboard);
+                                                        whiteboard, 
statisticsProvider);
             addRegistration(registerMBean(whiteboard, BlobGCMBean.class, new 
BlobGC(gc, executor),
                     BlobGCMBean.TYPE, "Document node store blob garbage 
collection"));
         }


Reply via email to