jackrabbit-oak-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From chet...@apache.org
Subject svn commit: r1497267 - in /jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak: api/jmx/ cache/ kernel/ osgi/ plugins/mongomk/ plugins/segment/
Date Thu, 27 Jun 2013 09:45:23 GMT
Author: chetanm
Date: Thu Jun 27 09:45:22 2013
New Revision: 1497267

URL: http://svn.apache.org/r1497267
Log:
OAK-863 - Enable stats for various caches used in Oak by default

-- Enabling the stats collection by default
-- Added new CacheStatsMBean class for exposing the cache stats via JMX
-- Using the Whiteboard to register the JMX beans

Added:
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/jmx/
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/jmx/CacheStatsMBean.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/cache/
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/cache/CacheStats.java
Modified:
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeStore.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/osgi/Activator.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/MongoDocumentStore.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/MongoMK.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/MongoMicroKernelService.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentCache.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentNodeStoreService.java

Added: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/jmx/CacheStatsMBean.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/jmx/CacheStatsMBean.java?rev=1497267&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/jmx/CacheStatsMBean.java
(added)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/jmx/CacheStatsMBean.java
Thu Jun 27 09:45:22 2013
@@ -0,0 +1,118 @@
+package org.apache.jackrabbit.oak.api.jmx;
+
+public interface CacheStatsMBean {
+    String TYPE = "CacheStats";
+
+    /**
+     * Returns the number of times {@link com.google.common.cache.Cache} lookup methods have
returned either a cached or
+     * uncached value. This is defined as {@code getHitCount + getMissCount}.
+     */
+    long getRequestCount();
+
+    /**
+     * Returns the number of times {@link com.google.common.cache.Cache} lookup methods have
returned a cached value.
+     */
+    long getHitCount();
+
+    /**
+     * Returns the ratio of cache requests which were hits. This is defined as
+     * {@code getHitCount / getRequestCount}, or {@code 1.0} when {@code getRequestCount
== 0}.
+     * Note that {@code getHitRate + getMissRate =~ 1.0}.
+     */
+    double getHitRate();
+    /**
+     * Returns the number of times {@link com.google.common.cache.Cache} lookup methods have
returned an uncached (newly
+     * loaded) value, or null. Multiple concurrent calls to {@link com.google.common.cache.Cache}
lookup methods on an absent
+     * value can result in multiple misses, all returning the results of a single cache load
+     * operation.
+     */
+    long getMissCount();
+
+    /**
+     * Returns the ratio of cache requests which were misses. This is defined as
+     * {@code getMissCount / getRequestCount}, or {@code 0.0} when {@code getRequestCount
== 0}.
+     * Note that {@code getHitRate + getMissRate =~ 1.0}. Cache misses include all requests
which
+     * weren't cache hits, including requests which resulted in either successful or failed
loading
+     * attempts, and requests which waited for other threads to finish loading. It is thus
the case
+     * that {@code getMissCount >= getLoadSuccessCount + getLoadExceptionCount}. Multiple
+     * concurrent misses for the same key will result in a single load operation.
+     */
+    double getMissRate();
+
+    /**
+     * Returns the total number of times that {@link com.google.common.cache.Cache} lookup
methods attempted to load new
+     * values. This includes both successful load operations, as well as those that threw
+     * exceptions. This is defined as {@code getLoadSuccessCount + getLoadExceptionCount}.
+     */
+    long getLoadCount();
+
+    /**
+     * Returns the number of times {@link com.google.common.cache.Cache} lookup methods have
successfully loaded a new value.
+     * This is always incremented in conjunction with {@link #getMissCount}, though {@code
getMissCount}
+     * is also incremented when an exception is encountered during cache loading (see
+     * {@link #getLoadExceptionCount}). Multiple concurrent misses for the same key will
result in a
+     * single load operation.
+     */
+    long getLoadSuccessCount();
+
+    /**
+     * Returns the number of times {@link com.google.common.cache.Cache} lookup methods threw
an exception while loading a
+     * new value. This is always incremented in conjunction with {@code getMissCount}, though
+     * {@code getMissCount} is also incremented when cache loading completes successfully
(see
+     * {@link #getLoadSuccessCount}). Multiple concurrent misses for the same key will result
in a
+     * single load operation.
+     */
+    long getLoadExceptionCount();
+
+    /**
+     * Returns the ratio of cache loading attempts which threw exceptions. This is defined
as
+     * {@code getLoadExceptionCount / (getLoadSuccessCount + getLoadExceptionCount)}, or
+     * {@code 0.0} when {@code getLoadSuccessCount + getLoadExceptionCount == 0}.
+     */
+    double getLoadExceptionRate();
+
+    /**
+     * Returns the total number of nanoseconds the cache has spent loading new values. This
can be
+     * used to calculate the miss penalty. This value is increased every time
+     * {@code getLoadSuccessCount} or {@code getLoadExceptionCount} is incremented.
+     */
+    long getTotalLoadTime();
+
+    /**
+     * Returns the average time spent loading new values. This is defined as
+     * {@code getTotalLoadTime / (getLoadSuccessCount + getLoadExceptionCount)}.
+     */
+    double getAverageLoadPenalty();
+
+    /**
+     * Returns the number of times an entry has been evicted. This count does not include
manual
+     * {@linkplain com.google.common.cache.Cache#invalidate invalidations}.
+     */
+    long getEvictionCount();
+
+    /**
+     * Get the number of elements/objects in the cache.
+     * @return the number of elements
+     */
+    long getElementCount();
+
+
+    /**
+     * Total weight of the complete cache. Depending on implementation it might be the amount
+     * of RAM taken by the cache
+     * @return to weight of the cache
+     */
+    //Computing weight is costly hence its an operation
+    long estimateCurrentWeight();
+
+    /**
+     * The maximum weight of entries the cache may contain.
+     * @return  the maximum total weight of entries the cache may contain
+     */
+    long getMaxTotalWeight();
+
+    /**
+     * Gathers the stats of the cache for logging.
+     */
+    String cacheInfoAsString();
+}

Added: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/cache/CacheStats.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/cache/CacheStats.java?rev=1497267&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/cache/CacheStats.java
(added)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/cache/CacheStats.java
Thu Jun 27 09:45:22 2013
@@ -0,0 +1,160 @@
+/*
+ * 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.cache;
+
+import java.util.Map;
+
+import com.google.common.base.Objects;
+import com.google.common.cache.Cache;
+import com.google.common.cache.Weigher;
+import org.apache.jackrabbit.oak.api.jmx.CacheStatsMBean;
+
+public class CacheStats implements CacheStatsMBean{
+    private final Cache<Object,Object> cache;
+    private final Weigher weigher;
+    private final long maxWeight;
+    private final String name;
+
+    public CacheStats(Cache cache, String name, Weigher weigher, long maxWeight) {
+        this.cache = cache;
+        this.name = name;
+        this.weigher = weigher;
+        this.maxWeight = maxWeight;
+    }
+
+    @Override
+    public long getRequestCount() {
+        return stats().requestCount();
+    }
+
+    @Override
+    public long getHitCount() {
+        return stats().hitCount();
+    }
+
+    @Override
+    public double getHitRate() {
+        return stats().hitRate();
+    }
+
+    @Override
+    public long getMissCount() {
+        return stats().missCount();
+    }
+
+    @Override
+    public double getMissRate() {
+        return stats().missRate();
+    }
+
+    @Override
+    public long getLoadCount() {
+        return stats().loadCount();
+    }
+
+    @Override
+    public long getLoadSuccessCount() {
+        return stats().loadSuccessCount();
+    }
+
+    @Override
+    public long getLoadExceptionCount() {
+        return stats().loadExceptionCount();
+    }
+
+    @Override
+    public double getLoadExceptionRate() {
+        return stats().loadExceptionRate();
+    }
+
+    @Override
+    public long getTotalLoadTime() {
+        return stats().totalLoadTime();
+    }
+
+    @Override
+    public double getAverageLoadPenalty() {
+        return stats().averageLoadPenalty();
+    }
+
+    @Override
+    public long getEvictionCount() {
+        return stats().evictionCount();
+    }
+
+    @Override
+    public long getElementCount() {
+        return cache.size();
+    }
+
+    @Override
+    public long estimateCurrentWeight() {
+        if(weigher == null){
+            return -1;
+        }
+        long size = 0;
+        for(Map.Entry e : cache.asMap().entrySet()){
+            size += weigher.weigh(e.getKey(),e.getValue());
+        }
+        return size;
+    }
+
+    @Override
+    public long getMaxTotalWeight() {
+        return maxWeight;
+    }
+
+    @Override
+    public String cacheInfoAsString() {
+        return Objects.toStringHelper("CacheStats")
+                .add("hitCount", getHitCount())
+                .add("missCount", getMissCount())
+                .add("loadSuccessCount", getLoadSuccessCount())
+                .add("lLoadExceptionCount", getLoadExceptionCount())
+                .add("totalLoadTime", getTotalLoadTime())
+                .add("evictionCount", getEvictionCount())
+                .add("elementCount", getElementCount())
+                .add("totalWeight", humanReadableByteCount(estimateCurrentWeight(), true))
+                .add("maxWeight", humanReadableByteCount(getMaxTotalWeight(),true))
+                .toString();
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    private com.google.common.cache.CacheStats stats() {
+        return cache.stats();
+    }
+
+    /**
+     * Based on http://stackoverflow.com/a/3758880/1035417
+     */
+    private static String humanReadableByteCount(long bytes, boolean si) {
+        if(bytes < 0){
+            return "0";
+        }
+        int unit = si ? 1000 : 1024;
+        if (bytes < unit) return bytes + " B";
+        int exp = (int) (Math.log(bytes) / Math.log(unit));
+        String pre = (si ? "kMGTPE" : "KMGTPE").charAt(exp-1) + (si ? "" : "i");
+        return String.format("%.1f %sB", bytes / Math.pow(unit, exp), pre);
+    }
+}

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeStore.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeStore.java?rev=1497267&r1=1497266&r2=1497267&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeStore.java
(original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeStore.java
Thu Jun 27 09:45:22 2013
@@ -37,6 +37,7 @@ import org.apache.jackrabbit.oak.spi.com
 import org.apache.jackrabbit.oak.spi.state.AbstractNodeStore;
 import org.apache.jackrabbit.oak.spi.state.NodeState;
 import org.apache.jackrabbit.oak.spi.state.NodeStoreBranch;
+import org.apache.jackrabbit.oak.cache.CacheStats;
 
 import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.base.Preconditions.checkNotNull;
@@ -61,6 +62,8 @@ public class KernelNodeStore extends Abs
 
     private final LoadingCache<String, KernelNodeState> cache;
 
+    private final CacheStats cacheStats;
+
     /**
      * State of the current root node.
      */
@@ -68,14 +71,17 @@ public class KernelNodeStore extends Abs
 
     public KernelNodeStore(final MicroKernel kernel, long cacheSize) {
         this.kernel = checkNotNull(kernel);
+
+        Weigher<String, KernelNodeState> weigher = new Weigher<String, KernelNodeState>()
{
+            @Override
+            public int weigh(String key, KernelNodeState state) {
+                return state.getMemory();
+            }
+        };
         this.cache = CacheBuilder.newBuilder()
                 .maximumWeight(cacheSize)
-                .weigher(new Weigher<String, KernelNodeState>() {
-                    @Override
-                    public int weigh(String key, KernelNodeState state) {
-                        return state.getMemory();
-                    }
-                }).build(new CacheLoader<String, KernelNodeState>() {
+                .weigher(weigher)
+                .build(new CacheLoader<String, KernelNodeState>() {
                     @Override
                     public KernelNodeState load(String key) {
                         int slash = key.indexOf('/');
@@ -83,6 +89,7 @@ public class KernelNodeStore extends Abs
                         String path = key.substring(slash);
                         return new KernelNodeState(kernel, path, revision, cache);
                     }
+
                     @Override
                     public ListenableFuture<KernelNodeState> reload(
                             String key, KernelNodeState oldValue) {
@@ -95,6 +102,8 @@ public class KernelNodeStore extends Abs
                     }
                 });
 
+        cacheStats = new CacheStats(cache, "NodeStore", weigher, cacheSize);
+
         try {
             this.root = cache.get(kernel.getHeadRevision() + '/');
         } catch (Exception e) {
@@ -162,6 +171,10 @@ public class KernelNodeStore extends Abs
         }
     }
 
+    public CacheStats getCacheStats(){
+        return cacheStats;
+    }
+
     //-----------------------------------------------------------< internal >---
 
     @Nonnull

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/osgi/Activator.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/osgi/Activator.java?rev=1497267&r1=1497266&r2=1497267&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/osgi/Activator.java
(original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/osgi/Activator.java
Thu Jun 27 09:45:22 2013
@@ -25,6 +25,7 @@ import java.util.Properties;
 import org.apache.jackrabbit.mk.api.MicroKernel;
 import org.apache.jackrabbit.oak.Oak;
 import org.apache.jackrabbit.oak.api.ContentRepository;
+import org.apache.jackrabbit.oak.api.jmx.CacheStatsMBean;
 import org.apache.jackrabbit.oak.core.ContentRepositoryImpl;
 import org.apache.jackrabbit.oak.kernel.KernelNodeStore;
 import org.apache.jackrabbit.oak.osgi.OsgiRepositoryInitializer.RepositoryInitializerObserver;
@@ -32,6 +33,9 @@ import org.apache.jackrabbit.oak.securit
 import org.apache.jackrabbit.oak.spi.lifecycle.OakInitializer;
 import org.apache.jackrabbit.oak.spi.lifecycle.RepositoryInitializer;
 import org.apache.jackrabbit.oak.spi.state.NodeStore;
+import org.apache.jackrabbit.oak.spi.whiteboard.OsgiWhiteboard;
+import org.apache.jackrabbit.oak.spi.whiteboard.Registration;
+import org.apache.jackrabbit.oak.spi.whiteboard.Whiteboard;
 import org.osgi.framework.BundleActivator;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.ServiceReference;
@@ -39,13 +43,17 @@ import org.osgi.framework.ServiceRegistr
 import org.osgi.util.tracker.ServiceTracker;
 import org.osgi.util.tracker.ServiceTrackerCustomizer;
 
+import static org.apache.jackrabbit.oak.spi.whiteboard.WhiteboardUtils.registerMBean;
+
 public class Activator implements BundleActivator, ServiceTrackerCustomizer, RepositoryInitializerObserver
{
 
     private BundleContext context;
 
     private ServiceTracker microKernelTracker;
 
-    // see OAK-795 for a reason why the nodeStore tracker is disabled 
+    private Whiteboard whiteboard;
+
+    // see OAK-795 for a reason why the nodeStore tracker is disabled
     // private ServiceTracker nodeStoreTracker;
 
     private final OsgiIndexProvider indexProvider = new OsgiIndexProvider();
@@ -58,12 +66,14 @@ public class Activator implements Bundle
 
     private final Map<ServiceReference, ServiceRegistration> services = new HashMap<ServiceReference,
ServiceRegistration>();
 
+    private final List<Registration> registrations = new ArrayList<Registration>();
+
     //----------------------------------------------------< BundleActivator >---
 
     @Override
     public void start(BundleContext bundleContext) throws Exception {
         context = bundleContext;
-
+        whiteboard = new OsgiWhiteboard(bundleContext);
         indexProvider.start(bundleContext);
         indexEditorProvider.start(bundleContext);
         validatorProvider.start(bundleContext);
@@ -85,6 +95,10 @@ public class Activator implements Bundle
         indexEditorProvider.stop();
         validatorProvider.stop();
         repositoryInitializerTracker.stop();
+
+        for(Registration r : registrations){
+            r.unregister();
+        }
     }
 
     //-------------------------------------------< ServiceTrackerCustomizer >---
@@ -94,10 +108,13 @@ public class Activator implements Bundle
         Object service = context.getService(reference);
         if (service instanceof MicroKernel) {
             MicroKernel kernel = (MicroKernel) service;
+            KernelNodeStore store = new KernelNodeStore(kernel);
             services.put(reference, context.registerService(
                     NodeStore.class.getName(),
-                    new KernelNodeStore(kernel),
+                    store,
                     new Properties()));
+            registrations.add(registerMBean(whiteboard, CacheStatsMBean.class,
+                store.getCacheStats(), CacheStatsMBean.TYPE, store.getCacheStats().getName()));
         } else if (service instanceof NodeStore) {
             NodeStore store = (NodeStore) service;
             OakInitializer.initialize(store, repositoryInitializerTracker, indexEditorProvider);
@@ -106,6 +123,7 @@ public class Activator implements Bundle
                 .with(new SecurityProviderImpl())
                 .with(validatorProvider)
                 .with(indexProvider)
+                .with(whiteboard)
                 .with(indexEditorProvider);
             services.put(reference, context.registerService(
                     ContentRepository.class.getName(),

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/MongoDocumentStore.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/MongoDocumentStore.java?rev=1497267&r1=1497266&r2=1497267&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/MongoDocumentStore.java
(original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/MongoDocumentStore.java
Thu Jun 27 09:45:22 2013
@@ -30,6 +30,7 @@ import javax.annotation.Nonnull;
 import org.apache.jackrabbit.mk.api.MicroKernelException;
 import org.apache.jackrabbit.oak.plugins.mongomk.UpdateOp.Operation;
 import org.apache.jackrabbit.oak.plugins.mongomk.util.Utils;
+import org.apache.jackrabbit.oak.cache.CacheStats;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -63,6 +64,8 @@ public class MongoDocumentStore implemen
     private long timeSum;
     
     private final Cache<String, CachedDocument> nodesCache;
+    
+    private final CacheStats cacheStats;
 
     public MongoDocumentStore(DB db, MongoMK.Builder builder) {
         nodes = db.getCollection(
@@ -82,10 +85,12 @@ public class MongoDocumentStore implemen
         // TODO expire entries if the parent was changed
         nodesCache = CacheBuilder.newBuilder()
                 .weigher(builder.getWeigher())
-                //.recordStats() FIXME: OAK-863
+                .recordStats() 
                 .maximumWeight(builder.getDocumentCacheSize())
                 .build();
-        
+
+        cacheStats = new CacheStats(nodesCache, "MongoMk-Documents", builder.getWeigher(),
+                builder.getDocumentCacheSize());
     }
     
     private static long start() {
@@ -446,7 +451,11 @@ public class MongoDocumentStore implemen
         }
         nodes.getDB().getMongo().close();
     }
-    
+
+    public CacheStats getCacheStats() {
+        return cacheStats;
+    }
+
     private static void log(String message, Object... args) {
         if (LOG.isDebugEnabled()) {
             String argList = Arrays.toString(args);

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/MongoMK.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/MongoMK.java?rev=1497267&r1=1497266&r2=1497267&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/MongoMK.java
(original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/MongoMK.java
Thu Jun 27 09:45:22 2013
@@ -56,6 +56,7 @@ import org.apache.jackrabbit.oak.plugins
 import org.apache.jackrabbit.oak.plugins.mongomk.util.TimingDocumentStoreWrapper;
 import org.apache.jackrabbit.oak.plugins.mongomk.util.Utils;
 import org.apache.jackrabbit.oak.commons.PathUtils;
+import org.apache.jackrabbit.oak.cache.CacheStats;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -136,6 +137,7 @@ public class MongoMK implements MicroKer
      * Key: path@rev, value: node
      */
     private final Cache<String, Node> nodeCache;
+    private final CacheStats nodeCacheStats;
 
     /**
      * Child node cache.
@@ -143,11 +145,12 @@ public class MongoMK implements MicroKer
      * Key: path@rev, value: children
      */
     private final Cache<String, Node.Children> nodeChildrenCache;
-
+    private final CacheStats nodeChildrenCacheStats;
     /**
      * Diff cache.
      */
     private final Cache<String, String> diffCache;
+    private final CacheStats diffCacheStats;
 
     /**
      * The unsaved last revisions. This contains the parents of all changed
@@ -191,7 +194,7 @@ public class MongoMK implements MicroKer
     private final UnmergedBranches branches;
 
     private boolean stopBackground;
-    
+
     MongoMK(Builder builder) {
         DocumentStore s = builder.getDocumentStore();
         if (builder.getTiming()) {
@@ -222,20 +225,27 @@ public class MongoMK implements MicroKer
         nodeCache = CacheBuilder.newBuilder()
                         .weigher(builder.getWeigher())
                         .maximumWeight(builder.getNodeCacheSize())
-                        // .recordStats() FIXME: OAK-863
+                        .recordStats()
                         .build();
+        nodeCacheStats = new CacheStats(nodeCache, "MongoMk-Node",
+                builder.getWeigher(), builder.getNodeCacheSize());
 
         nodeChildrenCache =  CacheBuilder.newBuilder()
                         .weigher(builder.getWeigher())
-                        //.recordStats() FIXME: OAK-863
+                        .recordStats()
                         .maximumWeight(builder.getChildrenCacheSize())
                         .build();
-        
+        nodeChildrenCacheStats = new CacheStats(nodeChildrenCache, "MongoMk-NodeChildren",
+                builder.getWeigher(), builder.getNodeCacheSize());
+
         diffCache = CacheBuilder.newBuilder()
+                .recordStats()
                 .weigher(builder.getWeigher())
                 .maximumWeight(builder.getDiffCacheSize())
                 .build();
-        
+        diffCacheStats = new CacheStats(diffCache, "MongoMk-DiffCache",
+                builder.getWeigher(), builder.getNodeCacheSize());
+
         init();
         // initial reading of the revisions of other cluster nodes
         backgroundRead();
@@ -243,7 +253,7 @@ public class MongoMK implements MicroKer
         headRevision = newRevision();
         LOG.info("Initialized MongoMK with clusterNodeId: {}", clusterId);
     }
-    
+
     void init() {
         headRevision = newRevision();
         Node n = readNode("/", headRevision);
@@ -1521,7 +1531,7 @@ public class MongoMK implements MicroKer
             nodeChildrenCache.put(key, c2);
         }
     }
-    
+
     /**
      * A background thread.
      */
@@ -1555,6 +1565,18 @@ public class MongoMK implements MicroKer
         }
     }
 
+    public CacheStats getNodeCacheStats() {
+        return nodeCacheStats;
+    }
+
+    public CacheStats getNodeChildrenCacheStats() {
+        return nodeChildrenCacheStats;
+    }
+
+    public CacheStats getDiffCacheStats() {
+        return diffCacheStats;
+    }
+
     /**
      * A builder for a MongoMK instance.
      */
@@ -1676,7 +1698,7 @@ public class MongoMK implements MicroKer
             return weigher;
         }
 
-        public Builder weigher(Weigher<String, Object> weigher) {
+        public Builder withWeigher(Weigher<String, Object> weigher) {
             this.weigher = weigher;
             return this;
         }

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/MongoMicroKernelService.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/MongoMicroKernelService.java?rev=1497267&r1=1497266&r2=1497267&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/MongoMicroKernelService.java
(original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/MongoMicroKernelService.java
Thu Jun 27 09:45:22 2013
@@ -19,6 +19,8 @@
 
 package org.apache.jackrabbit.oak.plugins.mongomk;
 
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Map;
 import java.util.Properties;
 
@@ -27,7 +29,11 @@ import org.apache.felix.scr.annotations.
 import org.apache.felix.scr.annotations.ConfigurationPolicy;
 import org.apache.felix.scr.annotations.Property;
 import org.apache.jackrabbit.mk.api.MicroKernel;
+import org.apache.jackrabbit.oak.api.jmx.CacheStatsMBean;
 import org.apache.jackrabbit.oak.plugins.mongomk.util.MongoConnection;
+import org.apache.jackrabbit.oak.spi.whiteboard.OsgiWhiteboard;
+import org.apache.jackrabbit.oak.spi.whiteboard.Registration;
+import org.apache.jackrabbit.oak.spi.whiteboard.Whiteboard;
 import org.apache.sling.commons.osgi.PropertiesUtil;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.ServiceRegistration;
@@ -37,6 +43,8 @@ import org.slf4j.LoggerFactory;
 
 import com.mongodb.DB;
 
+import static org.apache.jackrabbit.oak.spi.whiteboard.WhiteboardUtils.registerMBean;
+
 /**
  * The OSGi service to start/stop a MongoMK instance.
  */
@@ -69,6 +77,7 @@ public class MongoMicroKernelService {
 
     private ServiceRegistration reg;
     private MongoMK mk;
+    private final List<Registration> registrations = new ArrayList<Registration>();
 
     @Activate
     private void activate(BundleContext context, Map<String, ?> config)
@@ -86,15 +95,59 @@ public class MongoMicroKernelService {
 
         logger.info("Connected to database {}", mongoDB);
 
-        mk = new MongoMK.Builder().memoryCacheSize(cacheSize * MB).setMongoDB(mongoDB).open();
+        mk = new MongoMK.Builder()
+                        .memoryCacheSize(cacheSize * MB)
+                        .setMongoDB(mongoDB)
+                        .open();
+
+        registerJMXBeans(mk, context);
 
-        Properties props = new Properties();
-        props.setProperty("oak.mk.type", "mongo");
-        reg = context.registerService(MicroKernel.class.getName(), mk, props);
+        reg = context.registerService(MicroKernel.class.getName(), mk, new Properties());
+    }
+
+    private void registerJMXBeans(MongoMK mk, BundleContext context) {
+        Whiteboard wb = new OsgiWhiteboard(context);
+        registrations.add(
+            registerMBean(wb,
+                    CacheStatsMBean.class,
+                    mk.getNodeCacheStats(),
+                    CacheStatsMBean.TYPE,
+                    mk.getNodeCacheStats().getName())
+        );
+        registrations.add(
+            registerMBean(wb,
+                    CacheStatsMBean.class,
+                    mk.getNodeChildrenCacheStats(),
+                    CacheStatsMBean.TYPE,
+                    mk.getNodeCacheStats().getName())
+        );
+        registrations.add(
+            registerMBean(wb,
+                    CacheStatsMBean.class,
+                    mk.getDiffCacheStats(),
+                    CacheStatsMBean.TYPE,
+                    mk.getDiffCacheStats().getName())
+        );
+
+        DocumentStore ds = mk.getDocumentStore();
+        if(ds instanceof MongoDocumentStore){
+            MongoDocumentStore mds = (MongoDocumentStore) ds;
+            registrations.add(
+                    registerMBean(wb,
+                            CacheStatsMBean.class,
+                            mds.getCacheStats(),
+                            CacheStatsMBean.TYPE,
+                            mds.getCacheStats().getName())
+            );
+        }
     }
 
     @Deactivate
     private void deactivate() {
+        for(Registration r : registrations){
+            r.unregister();
+        }
+
         if (reg != null) {
             reg.unregister();
         }

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentCache.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentCache.java?rev=1497267&r1=1497266&r2=1497267&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentCache.java
(original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentCache.java
Thu Jun 27 09:45:22 2013
@@ -22,6 +22,7 @@ import java.util.concurrent.ExecutionExc
 
 import com.google.common.cache.Cache;
 import com.google.common.cache.CacheBuilder;
+import org.apache.jackrabbit.oak.cache.CacheStats;
 
 /**
  * Combined memory and disk cache for segments.
@@ -32,6 +33,8 @@ public class SegmentCache {
 
     private final Cache<UUID, Segment> memoryCache;
 
+    private final CacheStats cacheStats;
+
     // private final Cache<UUID, File> diskCache;
 
     // private final File diskCacheDirectory;
@@ -48,6 +51,7 @@ public class SegmentCache {
 //                }).build();
         this.memoryCache = CacheBuilder.newBuilder()
                 .maximumWeight(memoryCacheSize)
+                .recordStats()
                 .weigher(Segment.WEIGHER)
 //                .removalListener(new RemovalListener<UUID, Segment>() {
 //                    @Override
@@ -57,6 +61,8 @@ public class SegmentCache {
 //                    }
 //                })
                 .build();
+
+        cacheStats = new CacheStats(memoryCache, "Segment", Segment.WEIGHER, memoryCacheSize);
     }
 
     public SegmentCache() {
@@ -80,4 +86,7 @@ public class SegmentCache {
         memoryCache.invalidate(segmentId);
     }
 
+    public CacheStats getCacheStats() {
+        return cacheStats;
+    }
 }

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentNodeStoreService.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentNodeStoreService.java?rev=1497267&r1=1497266&r2=1497267&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentNodeStoreService.java
(original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentNodeStoreService.java
Thu Jun 27 09:45:22 2013
@@ -30,16 +30,21 @@ import org.apache.felix.scr.annotations.
 import org.apache.felix.scr.annotations.Property;
 import org.apache.felix.scr.annotations.Service;
 import org.apache.jackrabbit.oak.api.Blob;
+import org.apache.jackrabbit.oak.api.jmx.CacheStatsMBean;
 import org.apache.jackrabbit.oak.plugins.segment.file.FileStore;
 import org.apache.jackrabbit.oak.plugins.segment.mongo.MongoStore;
 import org.apache.jackrabbit.oak.spi.state.AbstractNodeStore;
 import org.apache.jackrabbit.oak.spi.state.NodeState;
 import org.apache.jackrabbit.oak.spi.state.NodeStore;
 import org.apache.jackrabbit.oak.spi.state.NodeStoreBranch;
+import org.apache.jackrabbit.oak.spi.whiteboard.OsgiWhiteboard;
+import org.apache.jackrabbit.oak.spi.whiteboard.Registration;
 import org.osgi.service.component.ComponentContext;
 
 import com.mongodb.Mongo;
 
+import static org.apache.jackrabbit.oak.spi.whiteboard.WhiteboardUtils.registerMBean;
+
 @Component(policy = ConfigurationPolicy.REQUIRE)
 @Service(NodeStore.class)
 public class SegmentNodeStoreService extends AbstractNodeStore {
@@ -72,6 +77,8 @@ public class SegmentNodeStoreService ext
 
     private NodeStore delegate;
 
+    private Registration cacheStatsReg;
+
     private synchronized NodeStore getDelegate() {
         assert delegate != null : "service must be activated when used";
         return delegate;
@@ -95,7 +102,11 @@ public class SegmentNodeStoreService ext
             int cache = Integer.parseInt(String.valueOf(properties.get(CACHE)));
 
             mongo = new Mongo(host, port);
-            store = new MongoStore(mongo.getDB(db), cache * MB);
+            SegmentCache sc = new SegmentCache(cache * MB);
+            store = new MongoStore(mongo.getDB(db), sc);
+
+            cacheStatsReg = registerMBean(new OsgiWhiteboard(context.getBundleContext()),
CacheStatsMBean.class,
+                    sc.getCacheStats(), CacheStatsMBean.TYPE, sc.getCacheStats().getName());
         }
 
         delegate = new SegmentNodeStore(store);
@@ -105,6 +116,10 @@ public class SegmentNodeStoreService ext
     public synchronized void deactivate() {
         delegate = null;
 
+        if(cacheStatsReg != null){
+            cacheStatsReg.unregister();
+        }
+
         store.close();
         if (mongo != null) {
             mongo.close();



Mime
View raw message