Author: chetanm
Date: Thu Dec 24 05:25:34 2015
New Revision: 1721597

URL: http://svn.apache.org/viewvc?rev=1721597&view=rev
Log:
OAK-3806 - Collect and expose statistics related to BlobStore operations

Expose BlobStore stats from DocumentNodeStore when BlobStore instances are 
created implicitly

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/DocumentNodeStoreService.java
    
jackrabbit/oak/trunk/oak-pojosr/src/test/groovy/org/apache/jackrabbit/oak/run/osgi/DocumentNodeStoreConfigTest.groovy

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=1721597&r1=1721596&r2=1721597&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
 Thu Dec 24 05:25:34 2015
@@ -25,6 +25,7 @@ import java.util.Set;
 import java.util.concurrent.Executor;
 import java.util.concurrent.TimeUnit;
 
+import javax.annotation.CheckForNull;
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 import javax.sql.DataSource;
@@ -45,6 +46,7 @@ import org.apache.jackrabbit.oak.commons
 import org.apache.jackrabbit.oak.commons.json.JsopStream;
 import org.apache.jackrabbit.oak.commons.json.JsopTokenizer;
 import org.apache.jackrabbit.oak.json.JsopDiff;
+import org.apache.jackrabbit.oak.plugins.blob.BlobStoreStats;
 import org.apache.jackrabbit.oak.plugins.blob.ReferencedBlob;
 import org.apache.jackrabbit.oak.plugins.document.DocumentNodeState.Children;
 import org.apache.jackrabbit.oak.plugins.document.cache.NodeDocumentCache;
@@ -64,10 +66,12 @@ import org.apache.jackrabbit.oak.plugins
 import org.apache.jackrabbit.oak.plugins.document.util.MongoConnection;
 import org.apache.jackrabbit.oak.plugins.document.util.RevisionsKey;
 import org.apache.jackrabbit.oak.plugins.document.util.StringValue;
+import org.apache.jackrabbit.oak.spi.blob.AbstractBlobStore;
 import org.apache.jackrabbit.oak.spi.blob.BlobStore;
 import org.apache.jackrabbit.oak.spi.blob.GarbageCollectableBlobStore;
 import org.apache.jackrabbit.oak.spi.blob.MemoryBlobStore;
 import org.apache.jackrabbit.oak.stats.Clock;
+import org.apache.jackrabbit.oak.stats.StatisticsProvider;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -512,6 +516,8 @@ public class DocumentMK {
         private String persistentCacheURI = DEFAULT_PERSISTENT_CACHE_URI;
         private PersistentCache persistentCache;
         private LeaseFailureHandler leaseFailureHandler;
+        private StatisticsProvider statisticsProvider = 
StatisticsProvider.NOOP;
+        private BlobStoreStats blobStoreStats;
 
         public Builder() {
         }
@@ -562,6 +568,7 @@ public class DocumentMK {
 
             if (this.blobStore == null) {
                 GarbageCollectableBlobStore s = new MongoBlobStore(db, 
blobCacheSizeMB * 1024 * 1024L);
+                configureStatsCollector(s);
                 PersistentCache p = getPersistentCache();
                 if (p != null) {
                     s = p.wrapBlobStore(s);
@@ -591,6 +598,7 @@ public class DocumentMK {
             this.documentStore = new RDBDocumentStore(ds, this);
             if(this.blobStore == null) {
                 this.blobStore = new RDBBlobStore(ds);
+                configureStatsCollector(blobStore);
             }
             return this;
         }
@@ -605,6 +613,7 @@ public class DocumentMK {
             this.documentStore = new RDBDocumentStore(ds, this, options);
             if(this.blobStore == null) {
                 this.blobStore = new RDBBlobStore(ds, options);
+                configureStatsCollector(blobStore);
             }
             return this;
         }
@@ -628,6 +637,7 @@ public class DocumentMK {
         public Builder setRDBConnection(DataSource documentStoreDataSource, 
DataSource blobStoreDataSource) {
             this.documentStore = new RDBDocumentStore(documentStoreDataSource, 
this);
             this.blobStore = new RDBBlobStore(blobStoreDataSource);
+            configureStatsCollector(blobStore);
             return this;
         }
 
@@ -724,6 +734,7 @@ public class DocumentMK {
         public BlobStore getBlobStore() {
             if (blobStore == null) {
                 blobStore = new MemoryBlobStore();
+                configureStatsCollector(blobStore);
             }
             return blobStore;
         }
@@ -856,6 +867,16 @@ public class DocumentMK {
             return this;
         }
 
+        public Builder setStatisticsProvider(StatisticsProvider 
statisticsProvider){
+            this.statisticsProvider = statisticsProvider;
+            return this;
+        }
+
+        @CheckForNull
+        public BlobStoreStats getBlobStoreStats() {
+            return blobStoreStats;
+        }
+
         public Clock getClock() {
             return clock;
         }
@@ -1016,6 +1037,13 @@ public class DocumentMK {
                     build();
         }
 
+        private void configureStatsCollector(BlobStore blobStore) {
+            if (blobStore instanceof AbstractBlobStore){
+                this.blobStoreStats = new BlobStoreStats(statisticsProvider);
+                ((AbstractBlobStore) 
blobStore).setStatsCollector(blobStoreStats);
+            }
+        }
+
     }
     
 }

Modified: 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreService.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreService.java?rev=1721597&r1=1721596&r2=1721597&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreService.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreService.java
 Thu Dec 24 05:25:34 2015
@@ -63,6 +63,7 @@ import org.apache.jackrabbit.oak.osgi.Os
 import org.apache.jackrabbit.oak.plugins.blob.BlobGC;
 import org.apache.jackrabbit.oak.plugins.blob.BlobGCMBean;
 import org.apache.jackrabbit.oak.plugins.blob.BlobGarbageCollector;
+import org.apache.jackrabbit.oak.plugins.blob.BlobStoreStats;
 import org.apache.jackrabbit.oak.plugins.blob.SharedDataStore;
 import org.apache.jackrabbit.oak.plugins.blob.datastore.SharedDataStoreUtils;
 import org.apache.jackrabbit.oak.plugins.document.util.MongoConnection;
@@ -70,6 +71,7 @@ import org.apache.jackrabbit.oak.plugins
 import org.apache.jackrabbit.oak.spi.blob.BlobStore;
 import org.apache.jackrabbit.oak.spi.blob.BlobStoreWrapper;
 import org.apache.jackrabbit.oak.spi.blob.GarbageCollectableBlobStore;
+import org.apache.jackrabbit.oak.spi.blob.stats.BlobStoreStatsMBean;
 import org.apache.jackrabbit.oak.spi.state.Clusterable;
 import org.apache.jackrabbit.oak.spi.state.NodeStore;
 import org.apache.jackrabbit.oak.spi.state.RevisionGC;
@@ -78,6 +80,7 @@ import org.apache.jackrabbit.oak.spi.whi
 import org.apache.jackrabbit.oak.spi.whiteboard.Whiteboard;
 import org.apache.jackrabbit.oak.spi.whiteboard.WhiteboardExecutor;
 import org.apache.jackrabbit.oak.spi.whiteboard.WhiteboardUtils;
+import org.apache.jackrabbit.oak.stats.StatisticsProvider;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleException;
 import org.osgi.framework.Constants;
@@ -310,6 +313,9 @@ public class DocumentNodeStoreService {
     public static final String PROP_DS_TYPE = "documentStoreType";
     private DocumentStoreType documentStoreType;
 
+    @Reference
+    private StatisticsProvider statisticsProvider;
+
     private boolean customBlobStore;
 
     @Activate
@@ -355,9 +361,9 @@ public class DocumentNodeStoreService {
         String persistentCache = 
PropertiesUtil.toString(prop(PROP_PERSISTENT_CACHE), DEFAULT_PERSISTENT_CACHE);
         int cacheSegmentCount = toInteger(prop(PROP_CACHE_SEGMENT_COUNT), 
DEFAULT_CACHE_SEGMENT_COUNT);
         int cacheStackMoveDistance = 
toInteger(prop(PROP_CACHE_STACK_MOVE_DISTANCE), 
DEFAULT_CACHE_STACK_MOVE_DISTANCE);
-
         DocumentMK.Builder mkBuilder =
                 new DocumentMK.Builder().
+                setStatisticsProvider(statisticsProvider).
                 memoryCacheSize(cacheSize * MB).
                 memoryCacheDistribution(
                         nodeCachePercentage, 
@@ -453,7 +459,7 @@ public class DocumentNodeStoreService {
             }
         }
 
-        registerJMXBeans(mk.getNodeStore());
+        registerJMXBeans(mk.getNodeStore(), mkBuilder);
         registerLastRevRecoveryJob(mk.getNodeStore());
         registerJournalGC(mk.getNodeStore());
 
@@ -570,7 +576,8 @@ public class DocumentNodeStoreService {
         }
     }
 
-    private void registerJMXBeans(final DocumentNodeStore store) throws 
IOException {
+    private void registerJMXBeans(final DocumentNodeStore store, 
DocumentMK.Builder mkBuilder) throws
+            IOException {
         registrations.add(
                 registerMBean(whiteboard,
                         CacheStatsMBean.class,
@@ -647,6 +654,14 @@ public class DocumentNodeStoreService {
         registrations.add(registerMBean(whiteboard, RevisionGCMBean.class, 
revisionGC,
                 RevisionGCMBean.TYPE, "Document node store revision garbage 
collection"));
 
+        BlobStoreStats blobStoreStats = mkBuilder.getBlobStoreStats();
+        if (!customBlobStore && blobStoreStats != null) {
+            registrations.add(registerMBean(whiteboard,
+                    BlobStoreStatsMBean.class,
+                    blobStoreStats,
+                    BlobStoreStatsMBean.TYPE,
+                    ds.getClass().getSimpleName()));
+        }
         //TODO Register JMX bean for Off Heap Cache stats
     }
 

Modified: 
jackrabbit/oak/trunk/oak-pojosr/src/test/groovy/org/apache/jackrabbit/oak/run/osgi/DocumentNodeStoreConfigTest.groovy
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-pojosr/src/test/groovy/org/apache/jackrabbit/oak/run/osgi/DocumentNodeStoreConfigTest.groovy?rev=1721597&r1=1721596&r2=1721597&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-pojosr/src/test/groovy/org/apache/jackrabbit/oak/run/osgi/DocumentNodeStoreConfigTest.groovy
 (original)
+++ 
jackrabbit/oak/trunk/oak-pojosr/src/test/groovy/org/apache/jackrabbit/oak/run/osgi/DocumentNodeStoreConfigTest.groovy
 Thu Dec 24 05:25:34 2015
@@ -20,11 +20,14 @@
 package org.apache.jackrabbit.oak.run.osgi
 
 import org.apache.felix.connect.launch.PojoServiceRegistry
+import org.apache.jackrabbit.oak.api.Blob
 import org.apache.jackrabbit.oak.plugins.document.DocumentNodeStore
 import org.apache.jackrabbit.oak.plugins.document.mongo.MongoBlobStore
 import org.apache.jackrabbit.oak.plugins.document.util.MongoConnection
 import org.apache.jackrabbit.oak.spi.blob.BlobStore
+import org.apache.jackrabbit.oak.spi.blob.GarbageCollectableBlobStore
 import org.apache.jackrabbit.oak.spi.blob.MemoryBlobStore
+import org.apache.jackrabbit.oak.spi.blob.stats.BlobStoreStatsMBean
 import org.apache.jackrabbit.oak.spi.state.NodeStore
 import org.h2.jdbcx.JdbcDataSource
 import org.junit.After
@@ -64,6 +67,7 @@ class DocumentNodeStoreConfigTest extend
 
         //4. Check that only one cluster node was instantiated
         assert getIdsOfClusterNodes(ds).size() == 1
+        testBlobStoreStats(ns)
     }
 
     @Test
@@ -221,6 +225,8 @@ class DocumentNodeStoreConfigTest extend
         Collection<String> colNames = getCollectionNames()
         assert colNames.containsAll(['NODES'])
         assert !colNames.contains(['BLOBS'])
+        assert registry.getServiceReference(BlobStoreStatsMBean.class.name) == 
null : "BlobStoreStatsMBean should " +
+                "*NOT* be registered by DocumentNodeStoreService in case 
custom blobStore used"
     }
 
     @Test
@@ -232,7 +238,7 @@ class DocumentNodeStoreConfigTest extend
                 
'org.apache.jackrabbit.oak.plugins.document.DocumentNodeStoreService': [
                         mongouri: MongoUtils.mongoURI,
                         db      : MongoUtils.mongoDB,
-                        blobCacheSize      : 1024,
+                        blobCacheSize      : 1,
                 ]
         ])
 
@@ -241,7 +247,29 @@ class DocumentNodeStoreConfigTest extend
         Collection<String> colNames = getCollectionNames()
         assert colNames.containsAll(['NODES', "BLOBS"])
 
-        assert 1024*1024*1024 == ((MongoBlobStore)ns.blobStore).blobCacheSize
+        assert 1*1024*1024 == ((MongoBlobStore)ns.blobStore).blobCacheSize
+        assert getService(BlobStoreStatsMBean.class) : "BlobStoreStatsMBean 
should " +
+                "be registered by DocumentNodeStoreService in default 
blobStore used"
+
+        testBlobStoreStats(ns)
+    }
+
+
+    public void testBlobStoreStats(DocumentNodeStore nodeStore) throws 
Exception{
+        int size = 1024 * 1024 * 5
+        Blob blob = nodeStore.createBlob(testStream(size));
+        BlobStoreStatsMBean stats = getService(BlobStoreStatsMBean.class)
+        assert stats.getUploadTotalSize() == size
+        assert stats.uploadCount > 0
+
+        BlobStore bs = nodeStore.blobStore;
+        assert bs instanceof GarbageCollectableBlobStore
+        bs.clearCache()
+
+        assert size == blob.newStream.getBytes().length
+
+        assert stats.downloadCount > 0
+        assert stats.downloadTotalSize > 0
     }
 
     @Override
@@ -299,4 +327,11 @@ class DocumentNodeStoreConfigTest extend
         ds.url = url
         return ds
     }
+
+    private InputStream testStream(int size) {
+        //Cannot use NullInputStream as it throws exception upon EOF
+        byte[] data = new byte[size];
+        new Random().nextBytes(data);
+        return new ByteArrayInputStream(data);
+    }
 }


Reply via email to