summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLouis Williams <louis.williams@mongodb.com>2019-10-15 14:56:49 +0000
committerevergreen <evergreen@mongodb.com>2019-10-15 14:56:49 +0000
commitd6e3ae804ce3e2aee2b91cce8de01f83cb3274ee (patch)
tree18716160ad2f114a509d220dda885927c461fdff
parent2b9354fd6fddc70aecfcaf3dc53593df203248b8 (diff)
downloadmongo-d6e3ae804ce3e2aee2b91cce8de01f83cb3274ee.tar.gz
SERVER-25025 Make startup faster with many WT collections
This makes two major improvements: (1) WiredTiger "metadata:create" cursors are very expensive; only use these when absolutely necessary, and use standard "metadata:" cursors everywhere else. In 3.6, this lowers startup calls to "metadata:create" from 3 to 0 per table. (2) No longer open a cursor for every WiredTiger collection at startup. Instead, lazily open cursors to initialize RecordIDs for inserts. (cherry picked from commit ba9670e4c6d3aa62db20501317457af99049570c) (cherry picked from commit 186d70b2c3043d0b1867c170ba7a6bc7eb25556f) (cherry picked from commit 056a6188574e852528f71ce7ce27c5f5dc912aa9)
-rw-r--r--src/mongo/db/storage/wiredtiger/wiredtiger_index.cpp2
-rw-r--r--src/mongo/db/storage/wiredtiger/wiredtiger_kv_engine.cpp6
-rw-r--r--src/mongo/db/storage/wiredtiger/wiredtiger_prefixed_record_store_test.cpp10
-rw-r--r--src/mongo/db/storage/wiredtiger/wiredtiger_record_store.cpp72
-rw-r--r--src/mongo/db/storage/wiredtiger/wiredtiger_record_store.h34
-rw-r--r--src/mongo/db/storage/wiredtiger/wiredtiger_session_cache.cpp2
-rw-r--r--src/mongo/db/storage/wiredtiger/wiredtiger_session_cache.h11
-rw-r--r--src/mongo/db/storage/wiredtiger/wiredtiger_size_storer.cpp6
-rw-r--r--src/mongo/db/storage/wiredtiger/wiredtiger_size_storer.h3
-rw-r--r--src/mongo/db/storage/wiredtiger/wiredtiger_standard_record_store_test.cpp12
-rw-r--r--src/mongo/db/storage/wiredtiger/wiredtiger_util.cpp57
-rw-r--r--src/mongo/db/storage/wiredtiger/wiredtiger_util.h13
-rw-r--r--src/mongo/db/storage/wiredtiger/wiredtiger_util_test.cpp25
13 files changed, 190 insertions, 63 deletions
diff --git a/src/mongo/db/storage/wiredtiger/wiredtiger_index.cpp b/src/mongo/db/storage/wiredtiger/wiredtiger_index.cpp
index daab45ab421..ebd7cede944 100644
--- a/src/mongo/db/storage/wiredtiger/wiredtiger_index.cpp
+++ b/src/mongo/db/storage/wiredtiger/wiredtiger_index.cpp
@@ -367,7 +367,7 @@ bool WiredTigerIndex::appendCustomStats(OperationContext* opCtx,
}
std::string type, sourceURI;
WiredTigerUtil::fetchTypeAndSourceURI(opCtx, _uri, &type, &sourceURI);
- StatusWith<std::string> metadataResult = WiredTigerUtil::getMetadata(opCtx, sourceURI);
+ StatusWith<std::string> metadataResult = WiredTigerUtil::getMetadataCreate(opCtx, sourceURI);
StringData creationStringName("creationString");
if (!metadataResult.isOK()) {
BSONObjBuilder creationString(output->subobjStart(creationStringName));
diff --git a/src/mongo/db/storage/wiredtiger/wiredtiger_kv_engine.cpp b/src/mongo/db/storage/wiredtiger/wiredtiger_kv_engine.cpp
index bee770385b5..08695a978a0 100644
--- a/src/mongo/db/storage/wiredtiger/wiredtiger_kv_engine.cpp
+++ b/src/mongo/db/storage/wiredtiger/wiredtiger_kv_engine.cpp
@@ -997,8 +997,9 @@ bool WiredTigerKVEngine::hasIdent(OperationContext* opCtx, StringData ident) con
bool WiredTigerKVEngine::_hasUri(WT_SESSION* session, const std::string& uri) const {
// can't use WiredTigerCursor since this is called from constructor.
- WT_CURSOR* c = NULL;
- int ret = session->open_cursor(session, "metadata:", NULL, NULL, &c);
+ WT_CURSOR* c = nullptr;
+ // No need for a metadata:create cursor, since it gathers extra information and is slower.
+ int ret = session->open_cursor(session, "metadata:", nullptr, nullptr, &c);
if (ret == ENOENT)
return false;
invariantWTOK(ret);
@@ -1011,6 +1012,7 @@ bool WiredTigerKVEngine::_hasUri(WT_SESSION* session, const std::string& uri) co
std::vector<std::string> WiredTigerKVEngine::getAllIdents(OperationContext* opCtx) const {
std::vector<std::string> all;
int ret;
+ // No need for a metadata:create cursor, since it gathers extra information and is slower.
WiredTigerCursor cursor("metadata:", WiredTigerSession::kMetadataTableId, false, opCtx);
WT_CURSOR* c = cursor.get();
if (!c)
diff --git a/src/mongo/db/storage/wiredtiger/wiredtiger_prefixed_record_store_test.cpp b/src/mongo/db/storage/wiredtiger/wiredtiger_prefixed_record_store_test.cpp
index 48ef200aed5..4863e31b8e8 100644
--- a/src/mongo/db/storage/wiredtiger/wiredtiger_prefixed_record_store_test.cpp
+++ b/src/mongo/db/storage/wiredtiger/wiredtiger_prefixed_record_store_test.cpp
@@ -166,6 +166,16 @@ public:
auto ret =
stdx::make_unique<PrefixedWiredTigerRecordStore>(_engine.get(), &opCtx, params, prefix);
+
+ // Opening this reverse cursor is not normally required, however the call to
+ // postConstructorInit depends on existing open transaction that is not reading at the oplog
+ // visibility timestamp (i.e. using a reverse cursor). This is here to comply with that
+ // assumption to make the test pass, but would otherwise not be an issue in a normal
+ // circumstances, because the WiredTigerOplogManager does this already.
+ {
+ std::unique_ptr<SeekableRecordCursor> cursor =
+ ret->getCursor(&opCtx, /*forward=*/false);
+ }
ret->postConstructorInit(&opCtx);
return std::move(ret);
}
diff --git a/src/mongo/db/storage/wiredtiger/wiredtiger_record_store.cpp b/src/mongo/db/storage/wiredtiger/wiredtiger_record_store.cpp
index 58a655038c2..3ead7a72deb 100644
--- a/src/mongo/db/storage/wiredtiger/wiredtiger_record_store.cpp
+++ b/src/mongo/db/storage/wiredtiger/wiredtiger_record_store.cpp
@@ -650,6 +650,12 @@ WiredTigerRecordStore::WiredTigerRecordStore(WiredTigerKVEngine* kvEngine,
if (_isOplog) {
checkOplogFormatVersion(ctx, _uri);
}
+
+ // If no SizeStorer is in use, start counting at zero. In practice, this will only ever be the
+ // the case for unit tests, where persistent size information is not required. If a RecordStore
+ // needs persistent size information, we require it to use a SizeStorer.
+ _sizeInfo = _sizeStorer ? _sizeStorer->load(_uri)
+ : std::make_shared<WiredTigerSizeStorer::SizeInfo>(0, 0);
}
WiredTigerRecordStore::~WiredTigerRecordStore() {
@@ -671,37 +677,6 @@ WiredTigerRecordStore::~WiredTigerRecordStore() {
}
void WiredTigerRecordStore::postConstructorInit(OperationContext* opCtx) {
- // Find the largest RecordId currently in use and estimate the number of records.
- std::unique_ptr<SeekableRecordCursor> cursor = getCursor(opCtx, /*forward=*/false);
- _sizeInfo =
- _sizeStorer ? _sizeStorer->load(_uri) : std::make_shared<WiredTigerSizeStorer::SizeInfo>();
-
- if (auto record = cursor->next()) {
- int64_t max = record->id.repr();
- _nextIdNum.store(1 + max);
-
- if (!_sizeStorer) {
- LOG(1) << "Doing scan of collection " << ns() << " to get size and count info";
-
- int64_t numRecords = 0;
- int64_t dataSize = 0;
- do {
- numRecords++;
- dataSize += record->data.size();
- } while ((record = cursor->next()));
- _sizeInfo->numRecords.store(numRecords);
- _sizeInfo->dataSize.store(dataSize);
- }
- } else {
- _sizeInfo->dataSize.store(0);
- _sizeInfo->numRecords.store(0);
- // Need to start at 1 so we are always higher than RecordId::min()
- _nextIdNum.store(1);
- }
-
- if (_sizeStorer)
- _sizeStorer->store(_uri, _sizeInfo);
-
if (WiredTigerKVEngine::initRsOplogBackgroundThread(ns())) {
_oplogStones = std::make_shared<OplogStones>(opCtx, this);
}
@@ -1129,10 +1104,8 @@ Status WiredTigerRecordStore::_insertRecords(OperationContext* opCtx,
if (!status.isOK())
return status.getStatus();
record.id = status.getValue();
- } else if (_isCapped) {
- record.id = _nextId();
} else {
- record.id = _nextId();
+ record.id = _nextId(opCtx);
}
dassert(record.id > highestId);
highestId = record.id;
@@ -1492,7 +1465,7 @@ void WiredTigerRecordStore::appendCustomStats(OperationContext* opCtx,
std::string type, sourceURI;
WiredTigerUtil::fetchTypeAndSourceURI(opCtx, _uri, &type, &sourceURI);
- StatusWith<std::string> metadataResult = WiredTigerUtil::getMetadata(opCtx, sourceURI);
+ StatusWith<std::string> metadataResult = WiredTigerUtil::getMetadataCreate(opCtx, sourceURI);
StringData creationStringName("creationString");
if (!metadataResult.isOK()) {
BSONObjBuilder creationString(bob.subobjStart(creationStringName));
@@ -1568,8 +1541,35 @@ void WiredTigerRecordStore::updateStatsAfterRepair(OperationContext* opCtx,
_sizeStorer->store(_uri, _sizeInfo);
}
-RecordId WiredTigerRecordStore::_nextId() {
+void WiredTigerRecordStore::_initNextIdIfNeeded(OperationContext* opCtx) {
+ // In the normal case, this will already be initialized, so use a weak load. Since this value
+ // will only change from 0 to a positive integer, the only risk is reading an outdated value, 0,
+ // and having to take the mutex.
+ if (_nextIdNum.loadRelaxed() > 0) {
+ return;
+ }
+
+ // Only one thread needs to do this.
+ stdx::lock_guard<stdx::mutex> lk(_initNextIdMutex);
+ if (_nextIdNum.load() > 0) {
+ return;
+ }
+
+ // Need to start at 1 so we are always higher than RecordId::min()
+ int64_t nextId = 1;
+
+ // Find the largest RecordId currently in use.
+ std::unique_ptr<SeekableRecordCursor> cursor = getCursor(opCtx, /*forward=*/false);
+ if (auto record = cursor->next()) {
+ nextId = record->id.repr() + 1;
+ }
+
+ _nextIdNum.store(nextId);
+}
+
+RecordId WiredTigerRecordStore::_nextId(OperationContext* opCtx) {
invariant(!_isOplog);
+ _initNextIdIfNeeded(opCtx);
RecordId out = RecordId(_nextIdNum.fetchAndAdd(1));
invariant(out.isNormal());
return out;
diff --git a/src/mongo/db/storage/wiredtiger/wiredtiger_record_store.h b/src/mongo/db/storage/wiredtiger/wiredtiger_record_store.h
index e2e46eaf9bf..75dbe9c46ba 100644
--- a/src/mongo/db/storage/wiredtiger/wiredtiger_record_store.h
+++ b/src/mongo/db/storage/wiredtiger/wiredtiger_record_store.h
@@ -292,9 +292,33 @@ private:
const Timestamp* timestamps,
size_t nRecords);
- RecordId _nextId();
- void _setId(RecordId id);
+ RecordId _nextId(OperationContext* opCtx);
bool cappedAndNeedDelete() const;
+
+ /**
+ * Initialize the largest known RecordId if it is not already. This is designed to be called
+ * immediately before operations that may need this Recordid. This is to support lazily
+ * initializing the value instead of all at once during startup.
+ */
+ void _initNextIdIfNeeded(OperationContext* opCtx);
+
+ /**
+ * Adjusts the record count and data size metadata for this record store, respectively. These
+ * functions consult the SizeRecoveryState to determine whether or not to actually change the
+ * size metadata if the server is undergoing recovery.
+ *
+ * For most record stores, we will not update the size metadata during recovery, as we trust
+ * that the values in the SizeStorer are accurate with respect to the end state of recovery.
+ * However, there are two exceptions:
+ *
+ * 1. When a record store is created as part of the recovery process. The SizeStorer will have
+ * no information about that newly-created ident.
+ * 2. When a record store is created at startup but constains no records as of the stable
+ * checkpoint timestamp. In this scenario, we will assume that the record store has a size
+ * of zero and will discard all cached size metadata. This assumption is incorrect if there
+ * are pending writes to this ident as part of the recovery process, and so we must
+ * always adjust size metadata for these idents.
+ */
void _changeNumRecords(OperationContext* opCtx, int64_t diff);
void _increaseDataSize(OperationContext* opCtx, int64_t amount);
RecordData _getData(const WiredTigerCursor& cursor) const;
@@ -327,7 +351,9 @@ private:
int _cappedDeleteCheckCount;
mutable stdx::timed_mutex _cappedDeleterMutex;
- AtomicInt64 _nextIdNum;
+ // Protects initialization of the _nextIdNum.
+ mutable stdx::mutex _initNextIdMutex;
+ AtomicInt64 _nextIdNum{0};
WiredTigerSizeStorer* _sizeStorer; // not owned, can be NULL
std::shared_ptr<WiredTigerSizeStorer::SizeInfo> _sizeInfo;
@@ -492,4 +518,4 @@ MONGO_FP_FORWARD_DECLARE(WTWriteConflictExceptionForReads);
// will not be considered durable until deactivated. It is unspecified whether writes that commit
// before activation will become visible while active.
MONGO_FP_FORWARD_DECLARE(WTPausePrimaryOplogDurabilityLoop);
-}
+} // namespace mongo
diff --git a/src/mongo/db/storage/wiredtiger/wiredtiger_session_cache.cpp b/src/mongo/db/storage/wiredtiger/wiredtiger_session_cache.cpp
index 6f66fb173c9..91165588423 100644
--- a/src/mongo/db/storage/wiredtiger/wiredtiger_session_cache.cpp
+++ b/src/mongo/db/storage/wiredtiger/wiredtiger_session_cache.cpp
@@ -200,7 +200,7 @@ void WiredTigerSession::closeCursorsForQueuedDrops(WiredTigerKVEngine* engine) {
}
namespace {
-AtomicUInt64 nextTableId(1);
+AtomicUInt64 nextTableId(WiredTigerSession::kLastTableId);
}
// static
uint64_t WiredTigerSession::genTableId() {
diff --git a/src/mongo/db/storage/wiredtiger/wiredtiger_session_cache.h b/src/mongo/db/storage/wiredtiger/wiredtiger_session_cache.h
index e3e96db52ec..da7bed61dcf 100644
--- a/src/mongo/db/storage/wiredtiger/wiredtiger_session_cache.h
+++ b/src/mongo/db/storage/wiredtiger/wiredtiger_session_cache.h
@@ -120,9 +120,16 @@ public:
static uint64_t genTableId();
/**
- * For "metadata:" cursors. Guaranteed never to collide with genTableId() ids.
+ * For special cursors. Guaranteed never to collide with genTableId() ids.
*/
- static const uint64_t kMetadataTableId = 0;
+ enum TableId {
+ /* For "metadata:" cursors */
+ kMetadataTableId,
+ /* For "metadata:create" cursors */
+ kMetadataCreateTableId,
+ /* The start of non-special table ids for genTableId() */
+ kLastTableId
+ };
void setIdleExpireTime(Date_t idleExpireTime) {
_idleExpireTime = idleExpireTime;
diff --git a/src/mongo/db/storage/wiredtiger/wiredtiger_size_storer.cpp b/src/mongo/db/storage/wiredtiger/wiredtiger_size_storer.cpp
index ea497acb993..6c98e866b11 100644
--- a/src/mongo/db/storage/wiredtiger/wiredtiger_size_storer.cpp
+++ b/src/mongo/db/storage/wiredtiger/wiredtiger_size_storer.cpp
@@ -125,10 +125,8 @@ std::shared_ptr<WiredTigerSizeStorer::SizeInfo> WiredTigerSizeStorer::load(Strin
BSONObj data(reinterpret_cast<const char*>(value.data));
LOG(2) << "WiredTigerSizeStorer::load " << uri << " -> " << redact(data);
- auto result = std::make_shared<SizeInfo>();
- result->numRecords.store(data["numRecords"].safeNumberLong());
- result->dataSize.store(data["dataSize"].safeNumberLong());
- return result;
+ return std::make_shared<SizeInfo>(data["numRecords"].safeNumberLong(),
+ data["dataSize"].safeNumberLong());
}
void WiredTigerSizeStorer::flush(bool syncToDisk) {
diff --git a/src/mongo/db/storage/wiredtiger/wiredtiger_size_storer.h b/src/mongo/db/storage/wiredtiger/wiredtiger_size_storer.h
index 21450c2847d..7089edf795b 100644
--- a/src/mongo/db/storage/wiredtiger/wiredtiger_size_storer.h
+++ b/src/mongo/db/storage/wiredtiger/wiredtiger_size_storer.h
@@ -65,6 +65,9 @@ public:
* SizeInfo.
*/
struct SizeInfo {
+ SizeInfo() = default;
+ SizeInfo(long long records, long long size) : numRecords(records), dataSize(size) {}
+
~SizeInfo() {
invariant(!_dirty.load());
}
diff --git a/src/mongo/db/storage/wiredtiger/wiredtiger_standard_record_store_test.cpp b/src/mongo/db/storage/wiredtiger/wiredtiger_standard_record_store_test.cpp
index 0266a38c900..fde88b0a8d9 100644
--- a/src/mongo/db/storage/wiredtiger/wiredtiger_standard_record_store_test.cpp
+++ b/src/mongo/db/storage/wiredtiger/wiredtiger_standard_record_store_test.cpp
@@ -62,9 +62,9 @@
namespace mongo {
namespace {
-using std::unique_ptr;
using std::string;
using std::stringstream;
+using std::unique_ptr;
class WiredTigerHarnessHelper final : public RecordStoreHarnessHelper {
public:
@@ -169,6 +169,16 @@ public:
params.sizeStorer = nullptr;
auto ret = stdx::make_unique<StandardWiredTigerRecordStore>(&_engine, &opCtx, params);
+
+ // Opening this reverse cursor is not normally required, however the call to
+ // postConstructorInit depends on existing open transaction that is not reading at the oplog
+ // visibility timestamp (i.e. using a reverse cursor). This is here to comply with that
+ // assumption to make the test pass, but would otherwise not be an issue in a normal
+ // circumstances, because the WiredTigerOplogManager does this already.
+ {
+ std::unique_ptr<SeekableRecordCursor> cursor =
+ ret->getCursor(&opCtx, /*forward=*/false);
+ }
ret->postConstructorInit(&opCtx);
return std::move(ret);
}
diff --git a/src/mongo/db/storage/wiredtiger/wiredtiger_util.cpp b/src/mongo/db/storage/wiredtiger/wiredtiger_util.cpp
index 0c93f27698c..4962b4ea37a 100644
--- a/src/mongo/db/storage/wiredtiger/wiredtiger_util.cpp
+++ b/src/mongo/db/storage/wiredtiger/wiredtiger_util.cpp
@@ -96,7 +96,7 @@ void WiredTigerUtil::fetchTypeAndSourceURI(OperationContext* opCtx,
const size_t colon = tableUri.find(':');
invariant(colon != string::npos);
colgroupUri += tableUri.substr(colon);
- StatusWith<std::string> colgroupResult = getMetadata(opCtx, colgroupUri);
+ StatusWith<std::string> colgroupResult = getMetadataCreate(opCtx, colgroupUri);
invariantOK(colgroupResult.getStatus());
WiredTigerConfigParser parser(colgroupResult.getValue());
@@ -111,16 +111,8 @@ void WiredTigerUtil::fetchTypeAndSourceURI(OperationContext* opCtx,
*source = std::string(sourceItem.str, sourceItem.len);
}
-StatusWith<std::string> WiredTigerUtil::getMetadata(OperationContext* opCtx, StringData uri) {
- invariant(opCtx);
-
- auto session = WiredTigerRecoveryUnit::get(opCtx)->getSessionNoTxn();
- WT_CURSOR* cursor =
- session->getCursor("metadata:create", WiredTigerSession::kMetadataTableId, false);
- invariant(cursor);
- auto releaser =
- MakeGuard([&] { session->releaseCursor(WiredTigerSession::kMetadataTableId, cursor); });
-
+namespace {
+StatusWith<std::string> _getMetadata(WT_CURSOR* cursor, StringData uri) {
std::string strUri = uri.toString();
cursor->set_key(cursor, strUri.c_str());
int ret = cursor->search(cursor);
@@ -138,6 +130,49 @@ StatusWith<std::string> WiredTigerUtil::getMetadata(OperationContext* opCtx, Str
invariant(metadata);
return StatusWith<std::string>(metadata);
}
+} // namespace
+
+StatusWith<std::string> WiredTigerUtil::getMetadataCreate(WT_SESSION* session, StringData uri) {
+ WT_CURSOR* cursor;
+ invariantWTOK(session->open_cursor(session, "metadata:create", nullptr, "", &cursor));
+ invariant(cursor);
+ ON_BLOCK_EXIT([cursor] { invariantWTOK(cursor->close(cursor)); });
+
+ return _getMetadata(cursor, uri);
+}
+
+StatusWith<std::string> WiredTigerUtil::getMetadataCreate(OperationContext* opCtx, StringData uri) {
+ invariant(opCtx);
+
+ auto session = WiredTigerRecoveryUnit::get(opCtx)->getSessionNoTxn();
+ WT_CURSOR* cursor =
+ session->getCursor("metadata:create", WiredTigerSession::kMetadataCreateTableId, false);
+
+ auto releaser = MakeGuard(
+ [&] { session->releaseCursor(WiredTigerSession::kMetadataCreateTableId, cursor); });
+
+ return _getMetadata(cursor, uri);
+}
+
+StatusWith<std::string> WiredTigerUtil::getMetadata(WT_SESSION* session, StringData uri) {
+ WT_CURSOR* cursor;
+ invariantWTOK(session->open_cursor(session, "metadata:", nullptr, "", &cursor));
+ invariant(cursor);
+ ON_BLOCK_EXIT([cursor] { invariantWTOK(cursor->close(cursor)); });
+
+ return _getMetadata(cursor, uri);
+}
+
+StatusWith<std::string> WiredTigerUtil::getMetadata(OperationContext* opCtx, StringData uri) {
+ invariant(opCtx);
+
+ auto session = WiredTigerRecoveryUnit::get(opCtx)->getSessionNoTxn();
+ WT_CURSOR* cursor = session->getCursor("metadata:", WiredTigerSession::kMetadataTableId, false);
+ auto releaser =
+ MakeGuard([&] { session->releaseCursor(WiredTigerSession::kMetadataTableId, cursor); });
+
+ return _getMetadata(cursor, uri);
+}
Status WiredTigerUtil::getApplicationMetadata(OperationContext* opCtx,
StringData uri,
diff --git a/src/mongo/db/storage/wiredtiger/wiredtiger_util.h b/src/mongo/db/storage/wiredtiger/wiredtiger_util.h
index dd8e7f73884..f3f92b26f06 100644
--- a/src/mongo/db/storage/wiredtiger/wiredtiger_util.h
+++ b/src/mongo/db/storage/wiredtiger/wiredtiger_util.h
@@ -139,9 +139,20 @@ public:
BSONObjBuilder* bob);
/**
- * Gets entire metadata string for collection/index at URI.
+ * Gets the creation metadata string for a collection or index at a given URI. Accepts an
+ * OperationContext or session.
+ *
+ * This returns more information, but is slower than getMetadata().
+ */
+ static StatusWith<std::string> getMetadataCreate(OperationContext* opCtx, StringData uri);
+ static StatusWith<std::string> getMetadataCreate(WT_SESSION* session, StringData uri);
+
+ /**
+ * Gets the entire metadata string for collection or index at URI. Accepts an OperationContext
+ * or session.
*/
static StatusWith<std::string> getMetadata(OperationContext* opCtx, StringData uri);
+ static StatusWith<std::string> getMetadata(WT_SESSION* session, StringData uri);
/**
* Reads app_metadata for collection/index at URI as a BSON document.
diff --git a/src/mongo/db/storage/wiredtiger/wiredtiger_util_test.cpp b/src/mongo/db/storage/wiredtiger/wiredtiger_util_test.cpp
index 6ce4ee1402b..966ad9cff4a 100644
--- a/src/mongo/db/storage/wiredtiger/wiredtiger_util_test.cpp
+++ b/src/mongo/db/storage/wiredtiger/wiredtiger_util_test.cpp
@@ -139,6 +139,31 @@ private:
std::unique_ptr<OperationContext> _opCtx;
};
+TEST_F(WiredTigerUtilMetadataTest, GetMetadataCreateInvalid) {
+ StatusWith<std::string> result =
+ WiredTigerUtil::getMetadataCreate(getOperationContext(), getURI());
+ ASSERT_NOT_OK(result.getStatus());
+ ASSERT_EQUALS(ErrorCodes::NoSuchKey, result.getStatus().code());
+}
+
+TEST_F(WiredTigerUtilMetadataTest, GetMetadataCreateNull) {
+ const char* config = nullptr;
+ createSession(config);
+ StatusWith<std::string> result =
+ WiredTigerUtil::getMetadataCreate(getOperationContext(), getURI());
+ ASSERT_OK(result.getStatus());
+ ASSERT_FALSE(result.getValue().empty());
+}
+
+TEST_F(WiredTigerUtilMetadataTest, GetMetadataCreateStringSimple) {
+ const char* config = "app_metadata=(abc=123)";
+ createSession(config);
+ StatusWith<std::string> result =
+ WiredTigerUtil::getMetadataCreate(getOperationContext(), getURI());
+ ASSERT_OK(result.getStatus());
+ ASSERT_STRING_CONTAINS(result.getValue(), config);
+}
+
TEST_F(WiredTigerUtilMetadataTest, GetConfigurationStringInvalidURI) {
StatusWith<std::string> result = WiredTigerUtil::getMetadata(getOperationContext(), getURI());
ASSERT_NOT_OK(result.getStatus());