summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Ernst <daniel.ernst@mongodb.com>2020-01-10 15:18:58 +0000
committerevergreen <evergreen@mongodb.com>2020-01-10 15:18:58 +0000
commit989d23805572e6db103b64f3de76ffa7359a00cd (patch)
treeb86621f6eff35ae806980340adae5c167f4d8247
parent8261ac76bdd469bd937c061f6ec4fb213b1298f0 (diff)
downloadmongo-989d23805572e6db103b64f3de76ffa7359a00cd.tar.gz
SERVER-42037 Add freeListSize collection stat with scale support
-rw-r--r--jstests/noPassthroughWithMongod/free_storage_size.js43
-rw-r--r--src/mongo/db/stats/storage_stats.cpp5
-rw-r--r--src/mongo/db/storage/record_store.h9
-rw-r--r--src/mongo/db/storage/wiredtiger/wiredtiger_record_store.cpp12
-rw-r--r--src/mongo/db/storage/wiredtiger/wiredtiger_record_store.h2
5 files changed, 71 insertions, 0 deletions
diff --git a/jstests/noPassthroughWithMongod/free_storage_size.js b/jstests/noPassthroughWithMongod/free_storage_size.js
new file mode 100644
index 00000000000..7526e91ea04
--- /dev/null
+++ b/jstests/noPassthroughWithMongod/free_storage_size.js
@@ -0,0 +1,43 @@
+/**
+ * Tests that db.collection.stats().freeStorageSize is a non-zero value after records are
+ * inserted and then some deleted.
+ *
+ * @tags: [
+ * # freeStorageSize is currently only supported by WT.
+ * requires_wiredtiger
+ * ]
+ */
+
+(function() {
+"use strict";
+
+const forceCheckpoint = () => {
+ assert.commandWorked(db.fsyncLock());
+ assert.commandWorked(db.fsyncUnlock());
+};
+
+const dbName = "freeStorageSizeTest";
+const collName = "foo";
+const testDB = db.getSiblingDB(dbName);
+const coll = testDB.getCollection(collName);
+
+const kDocsToInsert = 150;
+const kDocsToRemove = kDocsToInsert / 2;
+
+// Insert docs.
+for (let i = 0; i < kDocsToInsert; i++) {
+ assert.commandWorked(coll.insert({a: i}));
+}
+
+forceCheckpoint();
+
+// Remove docs to free up space.
+assert.commandWorked(coll.remove({a: {$lt: kDocsToRemove}}));
+
+forceCheckpoint();
+
+// Check that freeStorageSize is non-zero.
+let collStats = assert.commandWorked(testDB.runCommand({collStats: collName}));
+assert(collStats.hasOwnProperty("freeStorageSize"), tojson(collStats));
+assert.gt(collStats.freeStorageSize, 0);
+})();
diff --git a/src/mongo/db/stats/storage_stats.cpp b/src/mongo/db/stats/storage_stats.cpp
index 63e5540fdaf..dff609e2afa 100644
--- a/src/mongo/db/stats/storage_stats.cpp
+++ b/src/mongo/db/stats/storage_stats.cpp
@@ -85,6 +85,11 @@ Status appendCollectionStorageStats(OperationContext* opCtx,
static_cast<long long>(recordStore->storageSize(opCtx, result, verbose ? 1 : 0));
result->appendNumber("storageSize", storageSize / scale);
+ auto freeStorageSize = static_cast<long long>(recordStore->freeStorageSize(opCtx));
+ if (freeStorageSize != 0) {
+ result->appendNumber("freeStorageSize", freeStorageSize / scale);
+ }
+
recordStore->appendCustomStats(opCtx, result, scale);
IndexCatalog* indexCatalog = collection->getIndexCatalog();
diff --git a/src/mongo/db/storage/record_store.h b/src/mongo/db/storage/record_store.h
index 5bf95d6cb36..e549507f5a7 100644
--- a/src/mongo/db/storage/record_store.h
+++ b/src/mongo/db/storage/record_store.h
@@ -254,6 +254,15 @@ public:
BSONObjBuilder* extraInfo = nullptr,
int infoLevel = 0) const = 0;
+ /**
+ * @return file bytes available for reuse
+ * A return value of zero can mean either no bytes are available, or that the real value is
+ * unknown.
+ */
+ virtual int64_t freeStorageSize(OperationContext* opCtx) const {
+ return 0;
+ }
+
// CRUD related
/**
diff --git a/src/mongo/db/storage/wiredtiger/wiredtiger_record_store.cpp b/src/mongo/db/storage/wiredtiger/wiredtiger_record_store.cpp
index e1d49b5a2ce..6388ef65ead 100644
--- a/src/mongo/db/storage/wiredtiger/wiredtiger_record_store.cpp
+++ b/src/mongo/db/storage/wiredtiger/wiredtiger_record_store.cpp
@@ -872,6 +872,18 @@ int64_t WiredTigerRecordStore::storageSize(OperationContext* opCtx,
return size;
}
+int64_t WiredTigerRecordStore::freeStorageSize(OperationContext* opCtx) const {
+ invariant(opCtx->lockState()->isReadLocked());
+
+ WiredTigerSession* session = WiredTigerRecoveryUnit::get(opCtx)->getSessionNoTxn();
+ auto result = WiredTigerUtil::getStatisticsValue(session->getSession(),
+ "statistics:" + getURI(),
+ "statistics=(fast)",
+ WT_STAT_DSRC_BLOCK_REUSE_BYTES);
+ uassertStatusOK(result.getStatus());
+ return result.getValue();
+}
+
// Retrieve the value from a positioned cursor.
RecordData WiredTigerRecordStore::_getData(const WiredTigerCursor& cursor) const {
WT_ITEM value;
diff --git a/src/mongo/db/storage/wiredtiger/wiredtiger_record_store.h b/src/mongo/db/storage/wiredtiger/wiredtiger_record_store.h
index 30985dcd465..a7f67537583 100644
--- a/src/mongo/db/storage/wiredtiger/wiredtiger_record_store.h
+++ b/src/mongo/db/storage/wiredtiger/wiredtiger_record_store.h
@@ -137,6 +137,8 @@ public:
BSONObjBuilder* extraInfo = nullptr,
int infoLevel = 0) const;
+ virtual int64_t freeStorageSize(OperationContext* opCtx) const;
+
// CRUD related
virtual bool findRecord(OperationContext* opCtx, const RecordId& id, RecordData* out) const;