Index: oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentStoreStatsCollector.java
===================================================================
--- oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentStoreStatsCollector.java	(revision 1724776)
+++ oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentStoreStatsCollector.java	(working copy)
@@ -28,53 +28,53 @@
      * @param collection the collection
      * @param key collection key which is found
      */
-    void doneFindCached(Collection collection, String key);
+    void doneFindCached(Collection<? extends Document> collection, String key);
 
     /**
-     * Called when a document with given key is looked from remote store
-     *  @param timeTakenNanos watch for determining time taken
+     * Called when a document with given key is read from remote store
+     * @param timeTakenNanos time taken
      * @param collection the collection
      * @param key collection key
      * @param docFound true if document is found
      * @param isSlaveOk true if find was performed against a secondary instance
      */
-    void doneFindUncached(long timeTakenNanos, Collection collection, String key, boolean docFound, boolean isSlaveOk);
+    void doneFindUncached(long timeTakenNanos, Collection<? extends Document> collection, String key, boolean docFound, boolean isSlaveOk);
 
     /**
      * Called when query with given parameters is performed
-     * @param timeTakenNanos watch for determining time taken
+     * @param timeTakenNanos time taken
      * @param collection the collection
      * @param fromKey the start value (excluding)
      * @param toKey the end value (excluding)
-     * @param indexedProperty true if indexProperty was specified
+     * @param indexedProperty true if indexedProperty was specified
      * @param resultSize number of documents found for given query
-     * @param lockTime time in millis to acquire any lock. If no lock was required then its -1
+     * @param lockTime time in millis to acquire any lock ({@code -1} if no lock was required)
      * @param isSlaveOk true if find was performed against a secondary instance
      */
-    void doneQuery(long timeTakenNanos, Collection collection, String fromKey, String toKey,
+    void doneQuery(long timeTakenNanos, Collection<? extends Document> collection, String fromKey, String toKey,
                    boolean indexedProperty, int resultSize, long lockTime, boolean isSlaveOk);
 
     /**
      * Called when a document is created in the given collection
-     * @param timeTakenNanos watch for determining time taken
+     * @param timeTakenNanos time taken
      * @param collection the collection
-     * @param ids list of ids which were sent for creation
+     * @param ids list of ids request to be created
      * @param insertSuccess true if the insert was successful
      */
-    void doneCreate(long timeTakenNanos, Collection collection, List<String> ids, boolean insertSuccess);
+    void doneCreate(long timeTakenNanos, Collection<? extends Document> collection, List<String> ids, boolean insertSuccess);
 
     /**
      * Called when a given updated has modified multiple documents
-     *  @param timeTakenNanos watch for determining time taken
+     * @param timeTakenNanos time taken
      * @param collection the collection
      * @param updateCount number of updates performed
      */
-    void doneUpdate(long timeTakenNanos, Collection collection, int updateCount);
+    void doneUpdate(long timeTakenNanos, Collection<? extends Document> collection, int updateCount);
 
     /**
      * Called when a update operation was completed which affected single
      * document.
-     * @param timeTakenNanos watch for determining time taken
+     * @param timeTakenNanos time taken
      * @param collection the collection
      * @param key collection which got updated or inserted
      * @param newEntry true if the document was newly created due to given operation
@@ -81,6 +81,6 @@
      * @param success true if the update was success
      * @param retryCount number of retries done to get the update
      */
-    void doneFindAndModify(long timeTakenNanos, Collection collection, String key,
+    void doneFindAndModify(long timeTakenNanos, Collection<? extends Document> collection, String key,
                            boolean newEntry, boolean success, int retryCount);
 }
Index: oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/rdb/RDBDocumentStore.java
===================================================================
--- oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/rdb/RDBDocumentStore.java	(revision 1724776)
+++ oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/rdb/RDBDocumentStore.java	(working copy)
@@ -52,6 +52,7 @@
 import java.util.concurrent.Callable;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
 import java.util.concurrent.locks.Lock;
 import java.util.zip.Deflater;
 import java.util.zip.GZIPOutputStream;
@@ -60,6 +61,7 @@
 import javax.annotation.Nonnull;
 import javax.sql.DataSource;
 
+import com.google.common.base.Stopwatch;
 import org.apache.jackrabbit.oak.cache.CacheStats;
 import org.apache.jackrabbit.oak.plugins.document.Collection;
 import org.apache.jackrabbit.oak.plugins.document.Document;
@@ -66,6 +68,7 @@
 import org.apache.jackrabbit.oak.plugins.document.DocumentMK;
 import org.apache.jackrabbit.oak.plugins.document.DocumentStore;
 import org.apache.jackrabbit.oak.plugins.document.DocumentStoreException;
+import org.apache.jackrabbit.oak.plugins.document.DocumentStoreStatsCollector;
 import org.apache.jackrabbit.oak.plugins.document.NodeDocument;
 import org.apache.jackrabbit.oak.plugins.document.UpdateOp;
 import org.apache.jackrabbit.oak.plugins.document.UpdateOp.Condition;
@@ -696,6 +699,8 @@
 
     private Map<String, String> metadata;
 
+    private DocumentStoreStatsCollector stats;
+
     // set of supported indexed properties
     private static final Set<String> INDEXEDPROPERTIES = new HashSet<String>(Arrays.asList(new String[] { MODIFIED,
             NodeDocument.HAS_BINARY_FLAG, NodeDocument.DELETED_ONCE }));
@@ -712,7 +717,7 @@
     private final RDBDocumentSerializer ser = new RDBDocumentSerializer(this, COLUMNPROPERTIES);
 
     private void initialize(DataSource ds, DocumentMK.Builder builder, RDBOptions options) throws Exception {
-
+        this.stats = builder.getDocumentStoreStatsCollector();
         this.tableMeta.put(Collection.NODES,
                 new RDBTableMetaData(createTableName(options.getTablePrefix(), TABLEMAP.get(Collection.NODES))));
         this.tableMeta.put(Collection.CLUSTER_NODES,
@@ -1057,6 +1062,7 @@
                     long lastCheckTime = doc.getLastCheckTime();
                     if (lastCheckTime != 0) {
                         if (maxCacheAge == Integer.MAX_VALUE || System.currentTimeMillis() - lastCheckTime < maxCacheAge) {
+                            stats.doneFindCached(Collection.NODES, id);
                             return castAsT(unwrap(doc));
                         }
                     }
@@ -1109,12 +1115,16 @@
 
     @CheckForNull
     private <T extends Document> boolean internalCreate(Collection<T> collection, List<UpdateOp> updates) {
+        final Stopwatch watch = startWatch();
+        List<String> ids = new ArrayList<String>(updates.size());
+        boolean success = true;
         try {
-            boolean success = true;
+
             // try up to CHUNKSIZE ops in one transaction
             for (List<UpdateOp> chunks : Lists.partition(updates, CHUNKSIZE)) {
                 List<T> docs = new ArrayList<T>();
                 for (UpdateOp update : chunks) {
+                    ids.add(update.getId());
                     maintainUpdateStats(collection, update.getId());
                     UpdateUtils.assertUnconditional(update);
                     T doc = collection.newDocument(this);
@@ -1139,6 +1149,8 @@
             return success;
         } catch (DocumentStoreException ex) {
             return false;
+        } finally {
+            stats.doneCreate(watch.elapsed(TimeUnit.NANOSECONDS), collection, ids, success);
         }
     }
 
@@ -1160,10 +1172,12 @@
             addUpdateCounters(update);
             UpdateUtils.applyChanges(doc, update);
             try {
+                Stopwatch watch = startWatch();
                 insertDocuments(collection, Collections.singletonList(doc));
                 if (collection == Collection.NODES) {
                     nodesCache.putIfAbsent((NodeDocument) doc);
                 }
+                stats.doneFindAndModify(watch.elapsed(TimeUnit.NANOSECONDS), collection, update.getId(), true, true, 0);
                 return oldDoc;
             } catch (DocumentStoreException ex) {
                 // may have failed due to a race condition; try update instead
@@ -1202,10 +1216,11 @@
             addUpdateCounters(update);
             T doc = createNewDocument(collection, oldDoc, update);
             Lock l = locks.acquire(update.getId());
+            final Stopwatch watch = startWatch();
+            boolean success = false;
+            int retries = maxRetries;
             try {
-                boolean success = false;
 
-                int retries = maxRetries;
                 while (!success && retries > 0) {
                     long lastmodcount = modcountOf(oldDoc);
                     success = updateDocument(collection, doc, update, lastmodcount);
@@ -1249,6 +1264,9 @@
                 return oldDoc;
             } finally {
                 l.unlock();
+                int numOfAttempts = maxRetries - retries - 1;
+                stats.doneFindAndModify(watch.elapsed(TimeUnit.NANOSECONDS), collection,
+                        update.getId(), false, success, numOfAttempts);
             }
         }
     }
@@ -1306,9 +1324,13 @@
                 RDBTableMetaData tmd = getTable(collection);
                 boolean success = false;
                 try {
+                    Stopwatch watch = startWatch();
                     connection = this.ch.getRWConnection();
                     success = db.batchedAppendingUpdate(connection, tmd, chunkedIds, modified, modifiedIsConditional, appendData);
                     connection.commit();
+                    //Internally 'db' would make multiple calls and number of those
+                    //remote calls would not be captured
+                    stats.doneUpdate(watch.elapsed(TimeUnit.NANOSECONDS), collection, chunkedIds.size());
                 } catch (SQLException ex) {
                     success = false;
                     this.ch.rollbackConnection(connection);
@@ -1423,6 +1445,9 @@
                 throw new DocumentStoreException(message);
             }
         }
+
+        final Stopwatch watch = startWatch();
+        int resultSize = 0;
         try {
             long now = System.currentTimeMillis();
             QueryContext qp = null;
@@ -1443,6 +1468,7 @@
                 T doc = runThroughCache(collection, row, now, qp);
                 result.add(doc);
             }
+            resultSize = result.size();
             if (qp != null) {
                 qp.dispose();
             }
@@ -1453,6 +1479,8 @@
         } finally {
             qmap.remove(Thread.currentThread());
             this.ch.closeConnection(connection);
+            stats.doneQuery(watch.elapsed(TimeUnit.NANOSECONDS), collection, fromKey, toKey,
+                    !conditions.isEmpty(), resultSize, -1, false);
         }
     }
 
@@ -1470,6 +1498,8 @@
     private <T extends Document> T readDocumentUncached(Collection<T> collection, String id, NodeDocument cachedDoc) {
         Connection connection = null;
         RDBTableMetaData tmd = getTable(collection);
+        final Stopwatch watch = startWatch();
+        boolean docFound = true;
         try {
             long lastmodcount = -1;
             if (cachedDoc != null) {
@@ -1479,6 +1509,7 @@
             RDBRow row = db.read(connection, tmd, id, lastmodcount);
             connection.commit();
             if (row == null) {
+                docFound = false;
                 return null;
             } else {
                 if (lastmodcount == row.getModcount()) {
@@ -1493,6 +1524,7 @@
             throw new DocumentStoreException(ex);
         } finally {
             this.ch.closeConnection(connection);
+            stats.doneFindUncached(watch.elapsed(TimeUnit.NANOSECONDS), collection, id, docFound, false);
         }
     }
 
@@ -1762,6 +1794,10 @@
         // ignored
     }
 
+    public void setStatsCollector(DocumentStoreStatsCollector stats) {
+        this.stats = stats;
+    }
+
     @SuppressWarnings("unchecked")
     private static <T extends Document> T castAsT(NodeDocument doc) {
         return (T) doc;
@@ -1883,6 +1919,10 @@
         }
     }
 
+    private Stopwatch startWatch() {
+        return Stopwatch.createStarted();
+    }
+
     protected NodeDocumentCache getNodeDocumentCache() {
         return nodesCache;
     }
Index: oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentStoreStatsIT.java
===================================================================
--- oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentStoreStatsIT.java	(revision 1724776)
+++ oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentStoreStatsIT.java	(working copy)
@@ -24,7 +24,9 @@
 import java.util.List;
 import java.util.UUID;
 
+import org.apache.jackrabbit.oak.plugins.document.memory.MemoryDocumentStore;
 import org.apache.jackrabbit.oak.plugins.document.mongo.MongoDocumentStore;
+import org.apache.jackrabbit.oak.plugins.document.rdb.RDBDocumentStore;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -32,7 +34,7 @@
 
 import static java.util.Collections.singletonList;
 import static org.junit.Assert.assertTrue;
-import static org.junit.Assume.assumeTrue;
+import static org.junit.Assume.assumeFalse;
 import static org.mockito.Matchers.anyInt;
 import static org.mockito.Matchers.anyLong;
 import static org.mockito.Matchers.eq;
@@ -52,7 +54,7 @@
 
     @Before
     public void checkSupportedStores() throws Exception{
-        assumeTrue(ds instanceof MongoDocumentStore);
+        assumeFalse(ds instanceof MemoryDocumentStore);
     }
 
     @Test
@@ -151,5 +153,8 @@
         if (ds instanceof MongoDocumentStore){
             ((MongoDocumentStore) ds).setStatsCollector(stats);
         }
+        if (ds instanceof RDBDocumentStore){
+            ((RDBDocumentStore) ds).setStatsCollector(stats);
+        }
     }
 }
