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 re...@apache.org on 2017/12/13 14:33:46 UTC

svn commit: r1818025 - in /jackrabbit/oak/trunk/oak-store-document/src: main/java/org/apache/jackrabbit/oak/plugins/document/rdb/ test/java/org/apache/jackrabbit/oak/plugins/document/rdb/

Author: reschke
Date: Wed Dec 13 14:33:45 2017
New Revision: 1818025

URL: http://svn.apache.org/viewvc?rev=1818025&view=rev
Log:
OAK-7029: RDBDocumentStore.getStats() implementation

generic impl plus special cases for PostgreSQL, DB2, and Oracle

Modified:
    jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/rdb/RDBDocumentStore.java
    jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/rdb/RDBDocumentStoreDB.java
    jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/rdb/RDBDocumentStoreTest.java

Modified: jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/rdb/RDBDocumentStore.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/rdb/RDBDocumentStore.java?rev=1818025&r1=1818024&r2=1818025&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/rdb/RDBDocumentStore.java (original)
+++ jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/rdb/RDBDocumentStore.java Wed Dec 13 14:33:45 2017
@@ -647,15 +647,19 @@ public class RDBDocumentStore implements
      */
     static class RDBTableMetaData {
 
+        private final String catalog;
         private final String name;
         private boolean idIsBinary = false;
         private boolean hasVersion = false;
         private boolean hasSplitDocs = false;
         private int dataLimitInOctets = 16384;
+        private String schemaInfo = "";
+        private String indexInfo = "";
         private Set<String> columnOnlyProperties = Collections.unmodifiableSet(COLUMNPROPERTIES);
         private Set<String> columnProperties = Collections.unmodifiableSet(COLUMNPROPERTIES);
 
-        public RDBTableMetaData(String name) {
+        public RDBTableMetaData(@CheckForNull String catalog, @Nonnull String name) {
+            this.catalog = catalog == null ? "" : catalog;
             this.name = name;
         }
 
@@ -663,6 +667,10 @@ public class RDBDocumentStore implements
             return this.dataLimitInOctets;
         }
 
+        public String getCatalog() {
+            return this.catalog;
+        }
+
         public Set<String> getColumnProperties() {
             return this.columnProperties;
         }
@@ -671,10 +679,18 @@ public class RDBDocumentStore implements
             return this.columnOnlyProperties;
         }
 
+        public String getIndexInfo() {
+            return this.indexInfo;
+        }
+
         public String getName() {
             return this.name;
         }
 
+        public String getSchemaInfo() {
+            return this.schemaInfo;
+        }
+
         public boolean isIdBinary() {
             return this.idIsBinary;
         }
@@ -703,6 +719,14 @@ public class RDBDocumentStore implements
         public void setDataLimitInOctets(int dataLimitInOctets) {
             this.dataLimitInOctets = dataLimitInOctets;
         }
+
+        public void setSchemaInfo(String schemaInfo) {
+            this.schemaInfo = schemaInfo;
+        }
+
+        public void setIndexInfo(String indexInfo) {
+            this.indexInfo = indexInfo;
+        }
     }
 
     private final Map<Collection<? extends Document>, RDBTableMetaData> tableMeta = new HashMap<Collection<? extends Document>, RDBTableMetaData>();
@@ -783,8 +807,32 @@ public class RDBDocumentStore implements
     @Nonnull
     @Override
     public Map<String, String> getStats() {
-        // TODO: OAK-7029
-        return Collections.emptyMap();
+        ImmutableMap.Builder<String, String> builder = ImmutableMap.builder();
+        tableMeta.forEach((k, v) -> toMapBuilder(builder, k, v));
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("statistics obtained: " + builder.toString());
+        }
+        return builder.build();
+    }
+
+    private <T extends Document> void toMapBuilder(ImmutableMap.Builder<String, String> builder, Collection<T> collection, RDBTableMetaData meta) {
+        String prefix = collection.toString();
+        builder.put(prefix + ".ns", meta.getCatalog() + "." + meta.getName());
+        builder.put(prefix + ".schemaInfo", meta.getSchemaInfo());
+        builder.put(prefix + ".indexInfo", meta.getIndexInfo());
+        if (Collection.CLUSTER_NODES.equals(collection)) {
+            builder.put(prefix + ".updates", getCnStats());
+        }
+        // live data
+        Map<String, String> map = this.dbInfo.getAdditionalStatistics(this.ch, meta.getCatalog(), meta.getName());
+        map.forEach((k, v) -> builder.put(prefix + "." + k, v));
+        try {
+            long c = queryCount(collection, null, null, Collections.emptyList(), Collections.emptyList());
+            builder.put(prefix + ".count", Long.toString(c));
+        }
+        catch (DocumentStoreException ex) {
+            LOG.debug("getting entry count for " + prefix, ex);
+        }
     }
 
     // implementation
@@ -864,23 +912,31 @@ public class RDBDocumentStore implements
 
     private void initialize(DataSource ds, DocumentNodeStoreBuilder<?> builder, RDBOptions options) throws Exception {
         this.stats = builder.getDocumentStoreStatsCollector();
+
+        this.callStack = LOG.isDebugEnabled() ? new Exception("call stack of RDBDocumentStore creation") : null;
+
+        this.ch = new RDBConnectionHandler(ds);
+        Connection con = this.ch.getRWConnection();
+        String catalog = con.getCatalog();
+        DatabaseMetaData md = con.getMetaData();
+        if (null == catalog) {
+            // Oracle
+            catalog = md.getUserName();
+        }
+
         this.tableMeta.put(Collection.NODES,
-                new RDBTableMetaData(createTableName(options.getTablePrefix(), TABLEMAP.get(Collection.NODES))));
+                new RDBTableMetaData(catalog, createTableName(options.getTablePrefix(), TABLEMAP.get(Collection.NODES))));
         this.tableMeta.put(Collection.CLUSTER_NODES,
-                new RDBTableMetaData(createTableName(options.getTablePrefix(), TABLEMAP.get(Collection.CLUSTER_NODES))));
+                new RDBTableMetaData(catalog, createTableName(options.getTablePrefix(), TABLEMAP.get(Collection.CLUSTER_NODES))));
         this.tableMeta.put(Collection.JOURNAL,
-                new RDBTableMetaData(createTableName(options.getTablePrefix(), TABLEMAP.get(Collection.JOURNAL))));
+                new RDBTableMetaData(catalog, createTableName(options.getTablePrefix(), TABLEMAP.get(Collection.JOURNAL))));
         this.tableMeta.put(Collection.SETTINGS,
-                new RDBTableMetaData(createTableName(options.getTablePrefix(), TABLEMAP.get(Collection.SETTINGS))));
+                new RDBTableMetaData(catalog, createTableName(options.getTablePrefix(), TABLEMAP.get(Collection.SETTINGS))));
 
-        this.ch = new RDBConnectionHandler(ds);
-        this.callStack = LOG.isDebugEnabled() ? new Exception("call stack of RDBDocumentStore creation") : null;
 
         this.locks = new StripedNodeDocumentLocks();
         this.nodesCache = builder.buildNodeDocumentCache(this, locks);
 
-        Connection con = this.ch.getRWConnection();
-
         int isolation = con.getTransactionIsolation();
         String isolationDiags = RDBJDBCTools.isolationLevelToString(isolation);
         if (isolation != Connection.TRANSACTION_READ_COMMITTED) {
@@ -890,7 +946,6 @@ public class RDBDocumentStore implements
                     + " - check datasource configuration");
         }
 
-        DatabaseMetaData md = con.getMetaData();
         String dbDesc = String.format("%s %s (%d.%d)", md.getDatabaseProductName(), md.getDatabaseProductVersion(),
                 md.getDatabaseMajorVersion(), md.getDatabaseMinorVersion()).replaceAll("[\r\n\t]", " ").trim();
         String driverDesc = String.format("%s %s (%d.%d)", md.getDriverName(), md.getDriverVersion(), md.getDriverMajorVersion(),
@@ -926,21 +981,27 @@ public class RDBDocumentStore implements
 
         List<String> tablesCreated = new ArrayList<String>();
         List<String> tablesPresent = new ArrayList<String>();
-        StringBuilder tableDiags = new StringBuilder();
         try {
             createTableFor(con, Collection.CLUSTER_NODES, this.tableMeta.get(Collection.CLUSTER_NODES), tablesCreated,
-                    tablesPresent, tableDiags, options.getInitialSchema(), options.getUpgradeToSchema());
+                    tablesPresent, options.getInitialSchema(), options.getUpgradeToSchema());
             createTableFor(con, Collection.NODES, this.tableMeta.get(Collection.NODES), tablesCreated, tablesPresent,
-                    tableDiags, options.getInitialSchema(), options.getUpgradeToSchema());
+                    options.getInitialSchema(), options.getUpgradeToSchema());
             createTableFor(con, Collection.SETTINGS, this.tableMeta.get(Collection.SETTINGS), tablesCreated, tablesPresent,
-                    tableDiags, options.getInitialSchema(), options.getUpgradeToSchema());
+                    options.getInitialSchema(), options.getUpgradeToSchema());
             createTableFor(con, Collection.JOURNAL, this.tableMeta.get(Collection.JOURNAL), tablesCreated, tablesPresent,
-                    tableDiags, options.getInitialSchema(), options.getUpgradeToSchema());
+                    options.getInitialSchema(), options.getUpgradeToSchema());
         } finally {
             con.commit();
             con.close();
         }
 
+        StringBuilder tableDiags = new StringBuilder();
+        RDBTableMetaData nodesMeta = this.tableMeta.get(Collection.NODES);
+        tableDiags.append(nodesMeta.getSchemaInfo());
+        if (!nodesMeta.getIndexInfo().isEmpty()) {
+            tableDiags.append(" /* ").append(nodesMeta.getIndexInfo()).append(" */");
+        }
+
         if (options.isDropTablesOnClose()) {
             tablesToBeDropped.addAll(tablesCreated);
         }
@@ -1054,9 +1115,6 @@ public class RDBDocumentStore implements
                     sb.append(" ").append(index.getValue().get("type"));
                 }
             }
-            if (sb.length() != 0) {
-                sb.insert(0, "/* ").append(" */");
-            }
             return sb.toString();
         } catch (SQLException ex) {
             // well it was best-effort
@@ -1097,8 +1155,7 @@ public class RDBDocumentStore implements
     }
 
     private void createTableFor(Connection con, Collection<? extends Document> col, RDBTableMetaData tmd, List<String> tablesCreated,
-            List<String> tablesPresent, StringBuilder overallDiagnostics, int initialSchema, int upgradeToSchema) throws SQLException {
-        StringBuilder diagnostics = new StringBuilder(); 
+            List<String> tablesPresent, int initialSchema, int upgradeToSchema) throws SQLException {
 
         String dbname = this.dbInfo.toString();
         if (con.getMetaData().getURL() != null) {
@@ -1153,14 +1210,10 @@ public class RDBDocumentStore implements
                 LOG.info(message);
             }
 
-            if (col == Collection.NODES) {
-                String tableInfo = RDBJDBCTools.dumpResultSetMeta(met);
-                diagnostics.append(tableInfo);
-                String indexInfo = dumpIndexData(con.getMetaData(), met, tableName);
-                if (!indexInfo.isEmpty()) {
-                    diagnostics.append(" ").append(indexInfo);
-                }
-            }
+            String tableInfo = RDBJDBCTools.dumpResultSetMeta(met);
+            tmd.setSchemaInfo(tableInfo);
+            String indexInfo = dumpIndexData(con.getMetaData(), met, tableName);
+            tmd.setIndexInfo(indexInfo);
 
             closeResultSet(checkResultSet);
             boolean dbWasChanged = false;
@@ -1176,8 +1229,7 @@ public class RDBDocumentStore implements
             tablesPresent.add(tableName);
 
             if (dbWasChanged) {
-                diagnostics.setLength(0);
-                getTableMetaData(con, col, tmd, diagnostics);
+                getTableMetaData(con, col, tmd);
             }
         } catch (SQLException ex) {
             // table does not appear to exist
@@ -1206,8 +1258,7 @@ public class RDBDocumentStore implements
 
                 tablesCreated.add(tableName);
 
-                diagnostics.setLength(0);
-                getTableMetaData(con, col, tmd, diagnostics);
+                getTableMetaData(con, col, tmd);
             }
             catch (SQLException ex2) {
                 LOG.error("Failed to create table " + tableName + " in " + dbname, ex2);
@@ -1219,8 +1270,6 @@ public class RDBDocumentStore implements
             closeStatement(checkStatement);
             closeStatement(creatStatement);
         }
-
-        overallDiagnostics.append(diagnostics);
     }
 
     private boolean upgradeTable(Connection con, String tableName, int level) throws SQLException {
@@ -1247,8 +1296,7 @@ public class RDBDocumentStore implements
         return wasChanged;
     }
     
-    private static void getTableMetaData(Connection con, Collection<? extends Document> col, RDBTableMetaData tmd,
-            StringBuilder diagnostics) throws SQLException {
+    private static void getTableMetaData(Connection con, Collection<? extends Document> col, RDBTableMetaData tmd) throws SQLException {
         Statement checkStatement = null;
         ResultSet checkResultSet = null;
 
@@ -1260,14 +1308,10 @@ public class RDBDocumentStore implements
             ResultSetMetaData met = checkResultSet.getMetaData();
             obtainFlagsFromResultSetMeta(met, tmd);
 
-            if (col == Collection.NODES) {
-                String tableInfo = RDBJDBCTools.dumpResultSetMeta(met);
-                diagnostics.append(tableInfo);
-                String indexInfo = dumpIndexData(con.getMetaData(), met, tmd.getName());
-                if (!indexInfo.isEmpty()) {
-                    diagnostics.append(" ").append(indexInfo);
-                }
-            }
+            String tableInfo = RDBJDBCTools.dumpResultSetMeta(met);
+            tmd.setSchemaInfo(tableInfo);
+            String indexInfo = dumpIndexData(con.getMetaData(), met, tmd.getName());
+            tmd.setIndexInfo(indexInfo);
         } finally {
             closeResultSet(checkResultSet);
             closeStatement(checkStatement);

Modified: jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/rdb/RDBDocumentStoreDB.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/rdb/RDBDocumentStoreDB.java?rev=1818025&r1=1818024&r2=1818025&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/rdb/RDBDocumentStoreDB.java (original)
+++ jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/rdb/RDBDocumentStoreDB.java Wed Dec 13 14:33:45 2017
@@ -30,7 +30,10 @@ import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
+import java.util.SortedSet;
+import java.util.TreeSet;
 
 import javax.annotation.Nonnull;
 
@@ -143,6 +146,68 @@ public enum RDBDocumentStoreDB {
             }
             return result.toString();
         }
+
+        @Override
+        public Map<String, String> getAdditionalStatistics(RDBConnectionHandler ch, String catalog, String tableName) {
+            Map<String, String> result = new HashMap<String, String>();
+            Connection con = null;
+            PreparedStatement stmt = null;
+            ResultSet rs = null;
+            SortedSet<String> indexNames = Collections.emptySortedSet();
+
+            // get index names
+            try {
+                SortedSet<String> in = new TreeSet<String>();
+                con = ch.getROConnection();
+                stmt = con.prepareStatement("SELECT indexname FROM pg_indexes WHERE tablename=?");
+                stmt.setString(1, tableName.toLowerCase(Locale.ENGLISH));
+                rs = stmt.executeQuery();
+                while (rs.next()) {
+                    in.add(rs.getString(1));
+                }
+                con.commit();
+                indexNames = in;
+            } catch (SQLException ex) {
+                LOG.debug("while getting diagnostics", ex);
+            } finally {
+                closeResultSet(rs);
+                closeStatement(stmt);
+                ch.closeConnection(con);
+            }
+
+            // table data
+            try {
+                StringBuilder query = new StringBuilder("SELECT pg_total_relation_size(?), pg_table_size(?), pg_indexes_size(?)");
+                indexNames.forEach(name -> query.append(", pg_relation_size(?)"));
+                con = ch.getROConnection();
+                stmt = con.prepareStatement(query.toString());
+                int i = 1;
+                stmt.setString(i++, tableName);
+                stmt.setString(i++, tableName);
+                stmt.setString(i++, tableName);
+                for(String name : indexNames) {
+                    stmt.setString(i++, name);
+                }
+                rs = stmt.executeQuery();
+                while (rs.next()) {
+                    i = 1;
+                    result.put("storageSize", rs.getString(i++));
+                    result.put("size", rs.getString(i++));
+                    result.put("totalIndexSize", rs.getString(i++));
+                    for (String name : indexNames) {
+                        result.put("indexSizes." + name, rs.getString(i++));
+                    }
+                }
+                con.commit();
+            } catch (SQLException ex) {
+                LOG.debug("while getting diagnostics", ex);
+            } finally {
+                closeResultSet(rs);
+                closeStatement(stmt);
+                ch.closeConnection(con);
+            }
+            return result;
+        }
     },
 
     DB2("DB2") {
@@ -218,6 +283,66 @@ public enum RDBDocumentStoreDB {
             }
             return result.toString();
         }
+
+        @Override
+        public Map<String, String> getAdditionalStatistics(RDBConnectionHandler ch, String catalog, String tableName) {
+
+            Map<String, String> result = new HashMap<String, String>();
+
+            Connection con = null;
+            PreparedStatement stmt = null;
+            ResultSet rs = null;
+
+            // table data
+            String tableStats = System.getProperty(SYSPROP_PREFIX + ".TABLE_STATS",
+                    "card npages mpages fpages overflow pctfree avgrowsize stats_time");
+
+            try {
+                con = ch.getROConnection();
+                stmt = con.prepareStatement("SELECT * FROM syscat.tables WHERE tabschema=? and tabname=?");
+                stmt.setString(1, catalog.toUpperCase(Locale.ENGLISH));
+                stmt.setString(2, tableName.toUpperCase(Locale.ENGLISH));
+                rs = stmt.executeQuery();
+                while (rs.next()) {
+                    String data = extractFields(rs, tableStats);
+                    result.put("_data", data);
+                }
+                con.commit();
+            } catch (SQLException ex) {
+                ex.printStackTrace();
+                LOG.debug("while getting diagnostics", ex);
+            } finally {
+                closeResultSet(rs);
+                closeStatement(stmt);
+                ch.closeConnection(con);
+            }
+
+            // index data
+            String indexStats = System.getProperty(SYSPROP_PREFIX + ".INDEX_STATS",
+                    "indextype colnames pctfree clusterratio nleaf nlevels fullkeycard density indcard numrids numrids_deleted avgleafkeysize avgnleafkeysize remarks stats_time");
+
+            try {
+                con = ch.getROConnection();
+                stmt = con.prepareStatement("SELECT * FROM syscat.indexes WHERE tabschema=? and tabname=?");
+                stmt.setString(1, catalog.toUpperCase(Locale.ENGLISH));
+                stmt.setString(2, tableName.toUpperCase(Locale.ENGLISH));
+                rs = stmt.executeQuery();
+                while (rs.next()) {
+                    String index = rs.getString("indname");
+                    String data = extractFields(rs, indexStats);
+                    result.put("index." + index + "._data", data);
+                }
+                con.commit();
+            } catch (SQLException ex) {
+                LOG.debug("while getting diagnostics", ex);
+            } finally {
+                closeResultSet(rs);
+                closeStatement(stmt);
+                ch.closeConnection(con);
+            }
+
+            return result;
+        }
     },
 
     ORACLE("Oracle") {
@@ -275,6 +400,63 @@ public enum RDBDocumentStoreDB {
         }
 
         @Override
+        public Map<String, String> getAdditionalStatistics(RDBConnectionHandler ch, String catalog, String tableName) {
+
+            Map<String, String> result = new HashMap<String, String>();
+
+            Connection con = null;
+            PreparedStatement stmt = null;
+            ResultSet rs = null;
+
+            // table data
+            String tableStats = System.getProperty(SYSPROP_PREFIX + ".TABLE_STATS",
+                    "num_rows blocks avg_row_len sample_size last_analyzed");
+
+            try {
+                con = ch.getROConnection();
+                stmt = con.prepareStatement("SELECT * FROM user_tables WHERE table_name=?");
+                stmt.setString(1, tableName.toUpperCase(Locale.ENGLISH));
+                rs = stmt.executeQuery();
+                while (rs.next()) {
+                    String data = extractFields(rs, tableStats);
+                    result.put("_data", data.toString());
+                }
+                con.commit();
+            } catch (SQLException ex) {
+                LOG.debug("while getting diagnostics", ex);
+            } finally {
+                closeResultSet(rs);
+                closeStatement(stmt);
+                ch.closeConnection(con);
+            }
+
+            // index data
+            String indexStats = System.getProperty(SYSPROP_PREFIX + ".INDEX_STATS",
+                    "blevel leaf_blocks distinct_keys avg_leaf_blocks_per_key avg_data_blocks_per_key clustering_factor num_rows sample_size last_analyzed");
+
+            try {
+                con = ch.getROConnection();
+                stmt = con.prepareStatement("SELECT * FROM user_indexes WHERE table_name=?");
+                stmt.setString(1, tableName.toUpperCase(Locale.ENGLISH));
+                rs = stmt.executeQuery();
+                while (rs.next()) {
+                    String index = rs.getString("index_name");
+                    String data = extractFields(rs, indexStats);
+                    result.put("index." + index + "._data", data);
+                }
+                con.commit();
+            } catch (SQLException ex) {
+                LOG.debug("while getting diagnostics", ex);
+            } finally {
+                closeResultSet(rs);
+                closeStatement(stmt);
+                ch.closeConnection(con);
+            }
+
+            return result;
+        }
+
+        @Override
         public String getSmallintType() {
             return "number";
         }
@@ -441,9 +623,10 @@ public enum RDBDocumentStoreDB {
 
     private static final Logger LOG = LoggerFactory.getLogger(RDBDocumentStoreDB.class);
 
+    private static final String SYSPROP_PREFIX = "org.apache.jackrabbit.oak.plugins.document.rdb.RDBDocumentStore";
+
     // whether to create indices
-    private static final String CREATEINDEX = System.getProperty(
-            "org.apache.jackrabbit.oak.plugins.document.rdb.RDBDocumentStore.CREATEINDEX", "");
+    private static final String CREATEINDEX = System.getProperty(SYSPROP_PREFIX + ".CREATEINDEX", "");
 
     public enum FETCHFIRSTSYNTAX {
         FETCHFIRST, LIMIT, TOP
@@ -543,6 +726,10 @@ public enum RDBDocumentStoreDB {
         return "";
     }
 
+    public Map<String, String> getAdditionalStatistics(RDBConnectionHandler ch, String catalog, String tableName) {
+        return Collections.emptyMap();
+    }
+
     public String getSmallintType() {
         return "smallint";
     }
@@ -575,6 +762,21 @@ public enum RDBDocumentStoreDB {
 
     protected String description;
 
+    protected String extractFields(ResultSet rs, String indexStats) throws SQLException {
+        StringBuilder data = new StringBuilder();
+        for (String f : indexStats.split(" ")) {
+            String fn = f.trim();
+            if (!fn.isEmpty()) {
+                if (data.length() != 0) {
+                    data.append(", ");
+                }
+                String v = rs.getString(fn);
+                data.append(fn).append(": ").append(v == null ? v : v.trim());
+            }
+        }
+        return data.toString();
+    }
+
     private RDBDocumentStoreDB(String description) {
         this.description = description;
     }

Modified: jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/rdb/RDBDocumentStoreTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/rdb/RDBDocumentStoreTest.java?rev=1818025&r1=1818024&r2=1818025&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/rdb/RDBDocumentStoreTest.java (original)
+++ jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/rdb/RDBDocumentStoreTest.java Wed Dec 13 14:33:45 2017
@@ -16,7 +16,9 @@
  */
 package org.apache.jackrabbit.oak.plugins.document.rdb;
 
+import static org.hamcrest.Matchers.hasItem;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
 import static org.junit.Assert.assertTrue;
 
 import java.io.Closeable;
@@ -24,6 +26,7 @@ import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
+import java.util.Map;
 
 import org.apache.jackrabbit.oak.plugins.document.AbstractDocumentStoreTest;
 import org.apache.jackrabbit.oak.plugins.document.Collection;
@@ -118,4 +121,20 @@ public class RDBDocumentStoreTest extend
             Utils.closeIfCloseable(it);
         }
     }
+
+    @Test
+    public void testRDBStats() {
+        if (ds instanceof RDBDocumentStore) {
+            Map<String, String> info = ds.getStats();
+            assertThat(info.keySet(), hasItem("nodes.ns"));
+            assertThat(info.keySet(), hasItem("clusterNodes.ns"));
+            assertThat(info.keySet(), hasItem("journal.ns"));
+            assertThat(info.keySet(), hasItem("settings.ns"));
+            assertThat(info.keySet(), hasItem("nodes.count"));
+            assertThat(info.keySet(), hasItem("clusterNodes.count"));
+            assertThat(info.keySet(), hasItem("journal.count"));
+            assertThat(info.keySet(), hasItem("settings.count"));
+            // info.forEach((k, v) -> System.err.println(k +": " + v));
+        }
+    }
 }