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 ch...@apache.org on 2016/06/19 16:09:15 UTC

svn commit: r1749183 - in /jackrabbit/oak/trunk/oak-core/src: main/java/org/apache/jackrabbit/oak/plugins/document/ test/java/org/apache/jackrabbit/oak/plugins/document/

Author: chetanm
Date: Sun Jun 19 16:09:15 2016
New Revision: 1749183

URL: http://svn.apache.org/viewvc?rev=1749183&view=rev
Log:
OAK-2065 - JMX stats for operations being performed in DocumentNodeStore

Introducing DocumentNodeStoreStatsCollector which is called from various part of DocumentNodeStore. DocumentNodeStoreStats is a Metric based implementation to collect the stats

Added:
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreStats.java   (with props)
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreStatsCollector.java   (with props)
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreStatsCollectorIT.java   (with props)
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreStatsTest.java   (with props)
Modified:
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentMK.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreBranch.java

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentMK.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentMK.java?rev=1749183&r1=1749182&r2=1749183&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentMK.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentMK.java Sun Jun 19 16:09:15 2016
@@ -529,6 +529,7 @@ public class DocumentMK {
         private BlobStoreStats blobStoreStats;
         private CacheStats blobStoreCacheStats;
         private DocumentStoreStatsCollector documentStoreStatsCollector;
+        private DocumentNodeStoreStatsCollector nodeStoreStatsCollector;
         private Map<CacheType, PersistentCacheStats> persistentCacheStats =
                 new EnumMap<CacheType, PersistentCacheStats>(CacheType.class);
 
@@ -924,6 +925,18 @@ public class DocumentMK {
             return this;
         }
 
+        public DocumentNodeStoreStatsCollector getNodeStoreStatsCollector() {
+            if (nodeStoreStatsCollector == null) {
+                nodeStoreStatsCollector = new DocumentNodeStoreStats(statisticsProvider);
+            }
+            return nodeStoreStatsCollector;
+        }
+
+        public Builder setNodeStoreStatsCollector(DocumentNodeStoreStatsCollector statsCollector) {
+            this.nodeStoreStatsCollector = statsCollector;
+            return this;
+        }
+
         @Nonnull
         public Map<CacheType, PersistentCacheStats> getPersistenceCacheStats() {
             return persistentCacheStats;

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java?rev=1749183&r1=1749182&r2=1749183&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java Sun Jun 19 16:09:15 2016
@@ -408,8 +408,11 @@ public final class DocumentNodeStore
 
     private final boolean readOnlyMode;
 
+    private final DocumentNodeStoreStatsCollector nodeStoreStatsCollector;
+
     public DocumentNodeStore(DocumentMK.Builder builder) {
         this.blobStore = builder.getBlobStore();
+        this.nodeStoreStatsCollector = builder.getNodeStoreStatsCollector();
         if (builder.isUseSimpleRevision()) {
             this.simpleRevisionCounter = new AtomicInteger(0);
         }
@@ -1717,6 +1720,7 @@ public final class DocumentNodeStore
     }
 
     private void internalRunBackgroundUpdateOperations() {
+        BackgroundWriteStats stats = null;
         synchronized (backgroundWriteMonitor) {
             long start = clock.getTime();
             long time = start;
@@ -1729,7 +1733,7 @@ public final class DocumentNodeStore
             backgroundSplit();
             long splitTime = clock.getTime() - time;
             // write back pending updates to _lastRev
-            BackgroundWriteStats stats = backgroundWrite();
+            stats = backgroundWrite();
             stats.split = splitTime;
             stats.clean = cleanTime;
             stats.totalWriteTime = clock.getTime() - start;
@@ -1741,6 +1745,8 @@ public final class DocumentNodeStore
                 LOG.debug(msg, stats);
             }
         }
+        //Push stats outside of sync block
+        nodeStoreStatsCollector.doneBackgroundUpdate(stats);
     }
 
     //----------------------< background read operations >----------------------
@@ -1763,10 +1769,11 @@ public final class DocumentNodeStore
 
     /** OAK-2624 : background read operations are split from background update ops */
     private void internalRunBackgroundReadOperations() {
+        BackgroundReadStats readStats = null;
         synchronized (backgroundReadMonitor) {
             long start = clock.getTime();
             // pull in changes from other cluster nodes
-            BackgroundReadStats readStats = backgroundRead();
+            readStats = backgroundRead();
             readStats.totalReadTime = clock.getTime() - start;
             String msg = "Background read operations stats (read:{} {})";
             if (clock.getTime() - start > TimeUnit.SECONDS.toMillis(10)) {
@@ -1776,6 +1783,7 @@ public final class DocumentNodeStore
                 LOG.debug(msg, readStats.totalReadTime, readStats);
             }
         }
+        nodeStoreStatsCollector.doneBackgroundRead(readStats);
     }
 
     /**
@@ -2754,4 +2762,8 @@ public final class DocumentNodeStore
     public String getInstanceId() {
         return String.valueOf(getClusterId());
     }
-}
+
+    public DocumentNodeStoreStatsCollector getStatsCollector() {
+        return nodeStoreStatsCollector;
+    }
+}
\ No newline at end of file

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreBranch.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreBranch.java?rev=1749183&r1=1749182&r2=1749183&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreBranch.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreBranch.java Sun Jun 19 16:09:15 2016
@@ -155,6 +155,7 @@ class DocumentNodeStoreBranch implements
         Set<Revision> conflictRevisions = new HashSet<Revision>();
         long time = System.currentTimeMillis();
         int numRetries = 0;
+        boolean suspended= false;
         for (long backoff = MIN_BACKOFF; backoff <= maximumBackoff; backoff *= 2) {
             if (ex != null) {
                 try {
@@ -166,6 +167,7 @@ class DocumentNodeStoreBranch implements
                         // suspend until conflicting revision is visible
                         LOG.debug("Suspending until {} is visible. Current head {}.",
                                 conflictRevisions, store.getHeadRevision());
+                        suspended = true;
                         store.suspendUntilAll(conflictRevisions);
                         conflictRevisions.clear();
                         LOG.debug("Resumed. Current head {}.", store.getHeadRevision());
@@ -179,8 +181,10 @@ class DocumentNodeStoreBranch implements
                 }
             }
             try {
-                return branchState.merge(checkNotNull(hook),
+                NodeState result = branchState.merge(checkNotNull(hook),
                         checkNotNull(info), exclusive);
+                store.getStatsCollector().doneMerge(numRetries, System.currentTimeMillis() - time, suspended, exclusive);
+                return result;
             } catch (FailedWithConflictException e) {
                 ex = e;
                 conflictRevisions.addAll(e.getConflictRevisions());
@@ -198,6 +202,7 @@ class DocumentNodeStoreBranch implements
         }
         // if we get here retrying failed
         time = System.currentTimeMillis() - time;
+        store.getStatsCollector().failedMerge(numRetries, time, suspended, exclusive);
         String msg = ex.getMessage() + " (retries " + numRetries + ", " + time + " ms)";
         throw new CommitFailedException(ex.getSource(), ex.getType(),
                 ex.getCode(), msg, ex.getCause());

Added: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreStats.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreStats.java?rev=1749183&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreStats.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreStats.java Sun Jun 19 16:09:15 2016
@@ -0,0 +1,154 @@
+/*
+ * 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.document;
+
+import java.util.concurrent.TimeUnit;
+
+import org.apache.jackrabbit.oak.stats.HistogramStats;
+import org.apache.jackrabbit.oak.stats.MeterStats;
+import org.apache.jackrabbit.oak.stats.StatisticsProvider;
+import org.apache.jackrabbit.oak.stats.StatsOptions;
+import org.apache.jackrabbit.oak.stats.TimerStats;
+
+public class DocumentNodeStoreStats implements DocumentNodeStoreStatsCollector {
+    private static final String BGR_READ_HEAD = "DOCUMENT_NS_BGR_READ_HEAD";
+    private static final String BGR_CACHE_INVALIDATE = "DOCUMENT_NS_BGR_CACHE_INVALIDATE";
+    private static final String BGR_DIFF_CACHE = "DOCUMENT_NS_BGR_DIFF_CACHE";
+    private static final String BGR_LOCK = "DOCUMENT_NS_BGR_LOCK";
+    private static final String BGR_DISPATCH = "DOCUMENT_NS_BGR_DISPATCH";
+    private static final String BGR_TOTAL_TIME = "DOCUMENT_NS_BGR_TOTAL_TIME";
+    static final String BGR_NUM_CHANGES_RATE = "DOCUMENT_NS_BGR_NUM_CHANGES_RATE";
+    private static final String BGR_NUM_CHANGES_HISTO = "DOCUMENT_NS_BGR_NUM_CHANGES_HISTO";
+
+    private static final String BGW_CLEAN = "DOCUMENT_NS_BGW_CLEAN";
+    private static final String BGW_SPLIT = "DOCUMENT_NS_BGW_SPLIT";
+    private static final String BGW_WRITE = "DOCUMENT_NS_BGW_LOCK";
+    static final String BGW_NUM = "DOCUMENT_NS_BGW_NUM";
+    static final String BGW_NUM_WRITES_RATE = "DOCUMENT_NS_BGW_NUM_WRITE_RATE";
+    private static final String BGW_TOTAL = "DOCUMENT_NS_BGW_TOTAL_TIME";
+
+    private static final String MERGE_SUCCESS_NUM_RETRY = "DOCUMENT_NS_MERGE_SUCCESS_RETRY";
+    private static final String MERGE_SUCCESS_COUNT = "DOCUMENT_NS_MERGE_SUCCESS_COUNT";
+    private static final String MERGE_SUCCESS_TIME = "DOCUMENT_NS_MERGE_SUCCESS_TIME";
+    private static final String MERGE_SUCCESS_SUSPENDED = "DOCUMENT_NS_MERGE_SUCCESS_SUSPENDED";
+    private static final String MERGE_SUCCESS_EXCLUSIVE = "DOCUMENT_NS_MERGE_SUCCESS_EXCLUSIVE";
+
+    private static final String MERGE_FAILED_EXCLUSIVE = "DOCUMENT_NS_MERGE_FAILED_EXCLUSIVE";
+
+    private final TimerStats readHead;
+    private final TimerStats readCacheInvalidate;
+    private final TimerStats readDiffCache;
+    private final TimerStats readLock;
+    private final TimerStats readDispatch;
+    private final TimerStats readTotalTime;
+    private final MeterStats numChangesRate;
+    private final HistogramStats numChangesHisto;
+
+    private final TimerStats writeClean;
+    private final TimerStats writeSplit;
+    private final HistogramStats writeNum;
+    private final TimerStats writeWrite;
+    private final TimerStats writeTotal;
+    private final MeterStats numWritesRate;
+
+    private final HistogramStats mergeSuccessRetries;
+    private final MeterStats mergeSuccessRate;
+    private final TimerStats mergeSuccessTime;
+    private final MeterStats mergeSuccessExclusive;
+    private final MeterStats mergeSuccessSuspended;
+
+    private final MeterStats mergeFailedExclusive;
+
+
+    public DocumentNodeStoreStats(StatisticsProvider sp) {
+        readHead = sp.getTimer(BGR_READ_HEAD, StatsOptions.METRICS_ONLY);
+        readCacheInvalidate = sp.getTimer(BGR_CACHE_INVALIDATE, StatsOptions.METRICS_ONLY);
+        readDiffCache = sp.getTimer(BGR_DIFF_CACHE, StatsOptions.METRICS_ONLY);
+        readLock = sp.getTimer(BGR_LOCK, StatsOptions.METRICS_ONLY);
+        readDispatch = sp.getTimer(BGR_DISPATCH, StatsOptions.METRICS_ONLY);
+        readTotalTime = sp.getTimer(BGR_TOTAL_TIME, StatsOptions.METRICS_ONLY);
+        numChangesRate = sp.getMeter(BGR_NUM_CHANGES_RATE, StatsOptions.DEFAULT); //Enable time series
+        numChangesHisto = sp.getHistogram(BGR_NUM_CHANGES_HISTO, StatsOptions.METRICS_ONLY);
+
+        writeClean = sp.getTimer(BGW_CLEAN, StatsOptions.METRICS_ONLY);
+        writeSplit = sp.getTimer(BGW_SPLIT, StatsOptions.METRICS_ONLY);
+        writeWrite = sp.getTimer(BGW_WRITE, StatsOptions.METRICS_ONLY);
+        writeTotal = sp.getTimer(BGW_TOTAL, StatsOptions.METRICS_ONLY);
+        writeNum = sp.getHistogram(BGW_NUM, StatsOptions.DEFAULT);
+        numWritesRate = sp.getMeter(BGW_NUM_WRITES_RATE, StatsOptions.DEFAULT); //Enable time series
+
+        mergeSuccessRetries = sp.getHistogram(MERGE_SUCCESS_NUM_RETRY, StatsOptions.METRICS_ONLY);
+        mergeSuccessRate = sp.getMeter(MERGE_SUCCESS_COUNT, StatsOptions.DEFAULT); //Enable time series
+        mergeSuccessTime = sp.getTimer(MERGE_SUCCESS_TIME, StatsOptions.METRICS_ONLY);
+        mergeSuccessExclusive = sp.getMeter(MERGE_SUCCESS_EXCLUSIVE, StatsOptions.METRICS_ONLY);
+        mergeSuccessSuspended = sp.getMeter(MERGE_SUCCESS_SUSPENDED, StatsOptions.METRICS_ONLY);
+
+        mergeFailedExclusive = sp.getMeter(MERGE_FAILED_EXCLUSIVE, StatsOptions.DEFAULT); //Enable time series
+    }
+
+    @Override
+    public void doneBackgroundRead(BackgroundReadStats stats) {
+        readHead.update(stats.readHead, TimeUnit.MILLISECONDS);
+        readCacheInvalidate.update(stats.cacheInvalidationTime, TimeUnit.MILLISECONDS);
+        readDiffCache.update(stats.populateDiffCache, TimeUnit.MILLISECONDS);
+        readLock.update(stats.lock, TimeUnit.MILLISECONDS);
+        readDispatch.update(stats.dispatchChanges, TimeUnit.MILLISECONDS);
+        readTotalTime.update(stats.totalReadTime, TimeUnit.MILLISECONDS);
+
+        //Record rate of num of external changes pulled per second
+        numChangesRate.mark(stats.numExternalChanges);
+        numChangesHisto.update(stats.numExternalChanges);
+    }
+
+    @Override
+    public void doneBackgroundUpdate(BackgroundWriteStats stats) {
+        writeClean.update(stats.clean, TimeUnit.MILLISECONDS);
+        writeSplit.update(stats.split, TimeUnit.MILLISECONDS);
+        writeWrite.update(stats.write, TimeUnit.MILLISECONDS);
+        writeTotal.update(stats.totalWriteTime, TimeUnit.MILLISECONDS);
+
+        writeNum.update(stats.num);
+
+        //Record rate of num of bg writes pushed per second
+        numWritesRate.mark(stats.num);
+    }
+
+    @Override
+    public void doneMerge(int numRetries, long timeTaken, boolean suspended, boolean exclusive) {
+        mergeSuccessRate.mark();
+        mergeSuccessRetries.update(numRetries);
+        mergeSuccessTime.update(timeTaken, TimeUnit.MILLISECONDS);
+
+        if (exclusive) {
+            mergeSuccessExclusive.mark();
+        }
+
+        if (suspended) {
+            mergeSuccessSuspended.mark();
+        }
+    }
+
+    @Override
+    public void failedMerge(int numRetries, long time, boolean suspended, boolean exclusive) {
+        if (exclusive){
+            mergeFailedExclusive.mark();
+        }
+    }
+}

Propchange: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreStats.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreStatsCollector.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreStatsCollector.java?rev=1749183&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreStatsCollector.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreStatsCollector.java Sun Jun 19 16:09:15 2016
@@ -0,0 +1,30 @@
+/*
+ * 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.document;
+
+public interface DocumentNodeStoreStatsCollector {
+    void doneBackgroundRead(BackgroundReadStats stats);
+
+    void doneBackgroundUpdate(BackgroundWriteStats stats);
+
+    void doneMerge(int numRetries, long timeTaken, boolean suspended, boolean exclusive);
+
+    void failedMerge(int numRetries, long time, boolean suspended, boolean exclusive);
+}

Propchange: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreStatsCollector.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreStatsCollectorIT.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreStatsCollectorIT.java?rev=1749183&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreStatsCollectorIT.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreStatsCollectorIT.java Sun Jun 19 16:09:15 2016
@@ -0,0 +1,105 @@
+/*
+ * 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.document;
+
+
+import org.apache.jackrabbit.oak.api.CommitFailedException;
+import org.apache.jackrabbit.oak.spi.commit.CommitHook;
+import org.apache.jackrabbit.oak.spi.commit.CommitInfo;
+import org.apache.jackrabbit.oak.spi.commit.EmptyHook;
+import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+import static org.junit.Assert.fail;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyLong;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+public class DocumentNodeStoreStatsCollectorIT {
+    @Rule
+    public DocumentMKBuilderProvider builderProvider = new DocumentMKBuilderProvider();
+
+    private DocumentNodeStoreStatsCollector statsCollector = mock(DocumentNodeStoreStatsCollector.class);
+
+    private DocumentNodeStore nodeStore;
+
+    @Before
+    public void setUp(){
+        nodeStore = builderProvider.newBuilder()
+                .setAsyncDelay(0)
+                .setNodeStoreStatsCollector(statsCollector)
+                .getNodeStore();
+    }
+
+    @Test
+    public void doneBackgroundRead() throws Exception {
+        nodeStore.runBackgroundReadOperations();
+        verify(statsCollector).doneBackgroundRead(any(BackgroundReadStats.class));
+    }
+
+    @Test
+    public void doneBackgroundUpdate() throws Exception {
+        nodeStore.runBackgroundUpdateOperations();
+        verify(statsCollector).doneBackgroundUpdate(any(BackgroundWriteStats.class));
+    }
+
+    @Test
+    public void doneMerge() throws Exception {
+        NodeBuilder nb = nodeStore.getRoot().builder();
+        nb.child("a");
+        nodeStore.merge(nb, EmptyHook.INSTANCE, CommitInfo.EMPTY);
+        verify(statsCollector).doneMerge(eq(0), anyLong(), eq(false), eq(false));
+    }
+
+    @Test
+    public void failedMerge() throws Exception {
+        CommitHook failingHook = new CommitHook() {
+            @Override
+            public NodeState processCommit(NodeState before, NodeState after,
+                                           CommitInfo info) throws CommitFailedException {
+
+                throw new CommitFailedException(CommitFailedException.MERGE, 0 , "");
+
+            }
+        };
+
+        NodeBuilder nb1 = nodeStore.getRoot().builder();
+        nb1.child("a");
+
+        try {
+            nodeStore.merge(nb1, failingHook, CommitInfo.EMPTY);
+            fail();
+        } catch (CommitFailedException ignore){
+
+        }
+
+        verify(statsCollector).failedMerge(anyInt(), anyLong(), eq(false), eq(false));
+
+        //Should be called once more with exclusive lock
+        verify(statsCollector).failedMerge(anyInt(), anyLong(), eq(false), eq(true));
+    }
+
+}
\ No newline at end of file

Propchange: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreStatsCollectorIT.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreStatsTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreStatsTest.java?rev=1749183&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreStatsTest.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreStatsTest.java Sun Jun 19 16:09:15 2016
@@ -0,0 +1,66 @@
+/*
+ * 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.document;
+
+import java.lang.management.ManagementFactory;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+
+import com.codahale.metrics.Meter;
+import org.apache.jackrabbit.oak.commons.concurrent.ExecutorCloser;
+import org.apache.jackrabbit.oak.plugins.metric.MetricStatisticsProvider;
+import org.junit.After;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+public class DocumentNodeStoreStatsTest {
+    private ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
+    private MetricStatisticsProvider statsProvider =
+            new MetricStatisticsProvider(ManagementFactory.getPlatformMBeanServer(),executor);
+    private DocumentNodeStoreStats stats = new DocumentNodeStoreStats(statsProvider);
+
+    @After
+    public void shutDown(){
+        statsProvider.close();
+        new ExecutorCloser(executor).close();
+    }
+
+    @Test
+    public void backgroundRead() throws Exception{
+        BackgroundReadStats readStats = new BackgroundReadStats();
+        readStats.numExternalChanges = 5;
+        stats.doneBackgroundRead(readStats);
+        assertEquals(5, getMeter(DocumentNodeStoreStats.BGR_NUM_CHANGES_RATE).getCount());
+    }
+
+    @Test
+    public void backgroundWrite() throws Exception{
+        BackgroundWriteStats writeStats = new BackgroundWriteStats();
+        writeStats.num = 7;
+        stats.doneBackgroundUpdate(writeStats);
+        assertEquals(7, getMeter(DocumentNodeStoreStats.BGW_NUM_WRITES_RATE).getCount());
+
+    }
+
+    private Meter getMeter(String name) {
+        return statsProvider.getRegistry().getMeters().get(name);
+    }
+}

Propchange: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreStatsTest.java
------------------------------------------------------------------------------
    svn:eol-style = native