summaryrefslogtreecommitdiff
path: root/src/mongo/db/storage/wiredtiger
diff options
context:
space:
mode:
authorEric Milkie <milkie@10gen.com>2014-12-18 13:46:06 -0500
committerEric Milkie <milkie@10gen.com>2014-12-23 09:13:14 -0500
commit67d7eadd2e0db8c66c9105903401646501aa0138 (patch)
treef7456ed07ef7a02a558d9e12d1a5eb5de6bd23a8 /src/mongo/db/storage/wiredtiger
parent0ba73576bbe465097c825ba946f561c267465a88 (diff)
downloadmongo-67d7eadd2e0db8c66c9105903401646501aa0138.tar.gz
SERVER-16367 Add versioning info to collections
Diffstat (limited to 'src/mongo/db/storage/wiredtiger')
-rw-r--r--src/mongo/db/storage/wiredtiger/wiredtiger_index.cpp11
-rw-r--r--src/mongo/db/storage/wiredtiger/wiredtiger_index_test.cpp27
-rw-r--r--src/mongo/db/storage/wiredtiger/wiredtiger_record_store.cpp72
-rw-r--r--src/mongo/db/storage/wiredtiger/wiredtiger_record_store_test.cpp25
-rw-r--r--src/mongo/db/storage/wiredtiger/wiredtiger_util.cpp136
-rw-r--r--src/mongo/db/storage/wiredtiger/wiredtiger_util.h28
-rw-r--r--src/mongo/db/storage/wiredtiger/wiredtiger_util_test.cpp177
7 files changed, 437 insertions, 39 deletions
diff --git a/src/mongo/db/storage/wiredtiger/wiredtiger_index.cpp b/src/mongo/db/storage/wiredtiger/wiredtiger_index.cpp
index 88442a40711..2e389ea316a 100644
--- a/src/mongo/db/storage/wiredtiger/wiredtiger_index.cpp
+++ b/src/mongo/db/storage/wiredtiger/wiredtiger_index.cpp
@@ -400,6 +400,17 @@ namespace {
}
invariant(output);
+
+ {
+ BSONObjBuilder metadata(output->subobjStart("metadata"));
+ Status status = WiredTigerUtil::getApplicationMetadata(txn, uri(), &metadata);
+ if (!status.isOK()) {
+ metadata.append("error", "unable to retrieve metadata");
+ metadata.append("code", static_cast<int>(status.code()));
+ metadata.append("reason", status.reason());
+ }
+ }
+
WiredTigerSession* session = WiredTigerRecoveryUnit::get(txn)->getSession();
WT_SESSION* s = session->getSession();
Status status = WiredTigerUtil::exportTableToBSON(s, "statistics:" + uri(),
diff --git a/src/mongo/db/storage/wiredtiger/wiredtiger_index_test.cpp b/src/mongo/db/storage/wiredtiger/wiredtiger_index_test.cpp
index c2a128688f5..10e4a5524ac 100644
--- a/src/mongo/db/storage/wiredtiger/wiredtiger_index_test.cpp
+++ b/src/mongo/db/storage/wiredtiger/wiredtiger_index_test.cpp
@@ -30,6 +30,9 @@
#include "mongo/platform/basic.h"
+#include <boost/scoped_ptr.hpp>
+
+#include "mongo/bson/bsonobjbuilder.h"
#include "mongo/db/catalog/index_catalog_entry.h"
#include "mongo/db/index/index_descriptor.h"
#include "mongo/db/json.h"
@@ -141,4 +144,26 @@ namespace mongo {
ASSERT_NOT_EQUALS(std::string::npos, config.find("abc=def"));
}
-}
+ TEST(WiredTigerIndexTest, FullValidateMetadata) {
+ MyHarnessHelper harnessHelper;
+ boost::scoped_ptr<SortedDataInterface> sorted(harnessHelper.newSortedDataInterface(false));
+ boost::scoped_ptr<OperationContext> opCtx(harnessHelper.newOperationContext());
+
+ long long numKeys = 0;
+ BSONObjBuilder bob;
+ sorted->fullValidate(opCtx.get(), true, &numKeys, &bob);
+ BSONObj obj = bob.obj();
+
+ BSONElement metadataElement = obj.getField("metadata");
+ ASSERT_TRUE(metadataElement.isABSONObj());
+ BSONObj metadata = metadataElement.Obj();
+
+ BSONElement versionElement = metadata.getField("formatVersion");
+ ASSERT_TRUE(versionElement.isNumber());
+
+ BSONElement infoObjElement = metadata.getField("infoObj");
+ ASSERT_EQUALS(mongo::String, infoObjElement.type());
+ ASSERT_STRING_CONTAINS(infoObjElement.String(), "test.wt");
+ }
+
+} // namespace mongo
diff --git a/src/mongo/db/storage/wiredtiger/wiredtiger_record_store.cpp b/src/mongo/db/storage/wiredtiger/wiredtiger_record_store.cpp
index 37510238447..8530da8fbd3 100644
--- a/src/mongo/db/storage/wiredtiger/wiredtiger_record_store.cpp
+++ b/src/mongo/db/storage/wiredtiger/wiredtiger_record_store.cpp
@@ -56,43 +56,19 @@
namespace mongo {
namespace {
- bool shouldUseOplogHack(OperationContext* opCtx, const std::string& uri) {
- WiredTigerCursor curwrap("metadata:", WiredTigerSession::kMetadataCursorId, opCtx);
- WT_CURSOR* c = curwrap.get();
- c->set_key(c, uri.c_str());
- int ret = c->search(c);
- if (ret == WT_NOTFOUND)
- return false;
- invariantWTOK(ret);
-
- const char* config = NULL;
- c->get_value(c, &config);
- invariant(config);
+ static const int kMinimumRecordStoreVersion = 1;
+ static const int kCurrentRecordStoreVersion = 1; // New record stores use this by default.
+ static const int kMaximumRecordStoreVersion = 1;
+ BOOST_STATIC_ASSERT(kCurrentRecordStoreVersion >= kMinimumRecordStoreVersion);
+ BOOST_STATIC_ASSERT(kCurrentRecordStoreVersion <= kMaximumRecordStoreVersion);
- WiredTigerConfigParser topParser(config);
- WT_CONFIG_ITEM metadata;
- if (topParser.get("app_metadata", &metadata) != 0)
- return false;
-
- if (metadata.len == 0)
+ bool shouldUseOplogHack(OperationContext* opCtx, const std::string& uri) {
+ StatusWith<BSONObj> appMetadata = WiredTigerUtil::getApplicationMetadata(opCtx, uri);
+ if (!appMetadata.isOK()) {
return false;
-
- WiredTigerConfigParser parser(metadata);
- WT_CONFIG_ITEM keyItem;
- WT_CONFIG_ITEM value;
- while (parser.next(&keyItem, &value) == 0) {
- const StringData key(keyItem.str, keyItem.len);
- if (key == "oplogKeyExtractionVersion") {
- if (value.type == WT_CONFIG_ITEM::WT_CONFIG_ITEM_NUM && value.val == 1)
- return true;
- }
-
- // This prevents downgrades with unsupported metadata settings.
- severe() << "Unrecognized WiredTiger metadata setting: " << key << '=' << value.str;
- fassertFailedNoTrace(28548);
}
- return false;
+ return (appMetadata.getValue().getIntField("oplogKeyExtractionVersion") == 1);
}
} // namespace
@@ -155,16 +131,22 @@ namespace {
if ( NamespaceString::oplog(ns) ) {
// force file for oplog
ss << "type=file,";
- ss << "app_metadata=(oplogKeyExtractionVersion=1),";
// Tune down to 10m. See SERVER-16247
ss << "memory_page_max=10m,";
}
- else {
- // Force this to be empty since users shouldn't be allowed to change it.
- ss << "app_metadata=(),";
- }
+
+ // WARNING: No user-specified config can appear below this line. These options are required
+ // for correct behavior of the server.
ss << "key_format=q,value_format=u";
+
+ // Record store metadata
+ ss << ",app_metadata=(formatVersion=" << kCurrentRecordStoreVersion;
+ if (NamespaceString::oplog(ns)) {
+ ss << ",oplogKeyExtractionVersion=1";
+ }
+ ss << ")";
+
return StatusWith<std::string>(ss);
}
@@ -189,6 +171,11 @@ namespace {
_sizeStorer( sizeStorer ),
_sizeStorerCounter(0)
{
+ Status versionStatus = WiredTigerUtil::checkApplicationMetadataFormatVersion(
+ ctx, uri, kMinimumRecordStoreVersion, kMaximumRecordStoreVersion);
+ if (!versionStatus.isOK()) {
+ fassertFailedWithStatusNoTrace(28548, versionStatus);
+ }
if (_isCapped) {
invariant(_cappedMaxSize > 0);
@@ -714,6 +701,15 @@ namespace {
WiredTigerSession* session = WiredTigerRecoveryUnit::get(txn)->getSession();
WT_SESSION* s = session->getSession();
BSONObjBuilder bob(result->subobjStart(kWiredTigerEngineName));
+ {
+ BSONObjBuilder metadata(bob.subobjStart("metadata"));
+ Status status = WiredTigerUtil::getApplicationMetadata(txn, GetURI(), &metadata);
+ if (!status.isOK()) {
+ metadata.append("error", "unable to retrieve metadata");
+ metadata.append("code", static_cast<int>(status.code()));
+ metadata.append("reason", status.reason());
+ }
+ }
Status status = WiredTigerUtil::exportTableToBSON(s, "statistics:" + GetURI(),
"statistics=(fast)", &bob);
if (!status.isOK()) {
diff --git a/src/mongo/db/storage/wiredtiger/wiredtiger_record_store_test.cpp b/src/mongo/db/storage/wiredtiger/wiredtiger_record_store_test.cpp
index e96a3db36d3..8cba02bf02f 100644
--- a/src/mongo/db/storage/wiredtiger/wiredtiger_record_store_test.cpp
+++ b/src/mongo/db/storage/wiredtiger/wiredtiger_record_store_test.cpp
@@ -30,10 +30,12 @@
#include "mongo/platform/basic.h"
+#include <boost/scoped_ptr.hpp>
#include <sstream>
#include <string>
#include "mongo/base/string_data.h"
+#include "mongo/bson/bsonobjbuilder.h"
#include "mongo/db/concurrency/write_conflict_exception.h"
#include "mongo/db/json.h"
#include "mongo/db/operation_context_noop.h"
@@ -48,6 +50,7 @@
namespace mongo {
+ using boost::scoped_ptr;
using std::string;
using std::stringstream;
@@ -631,4 +634,26 @@ namespace mongo {
ASSERT_THROWS(rs->storageSize(opCtx.get()), UserException);
}
+ TEST(WiredTigerRecordStoreTest, AppendCustomStatsMetadata) {
+ WiredTigerHarnessHelper harnessHelper;
+ scoped_ptr<RecordStore> rs(harnessHelper.newNonCappedRecordStore("a.b"));
+
+ scoped_ptr<OperationContext> opCtx(harnessHelper.newOperationContext());
+ BSONObjBuilder builder;
+ rs->appendCustomStats(opCtx.get(), &builder, 1.0);
+ BSONObj customStats = builder.obj();
+
+ BSONElement wiredTigerElement = customStats.getField(kWiredTigerEngineName);
+ ASSERT_TRUE(wiredTigerElement.isABSONObj());
+ BSONObj wiredTiger = wiredTigerElement.Obj();
+
+ BSONElement metadataElement = wiredTiger.getField("metadata");
+ ASSERT_TRUE(metadataElement.isABSONObj());
+ BSONObj metadata = metadataElement.Obj();
+
+ BSONElement versionElement = metadata.getField("formatVersion");
+ ASSERT_TRUE(versionElement.isNumber());
+
+ }
+
} // namespace mongo
diff --git a/src/mongo/db/storage/wiredtiger/wiredtiger_util.cpp b/src/mongo/db/storage/wiredtiger/wiredtiger_util.cpp
index df65c9d4601..9131643358c 100644
--- a/src/mongo/db/storage/wiredtiger/wiredtiger_util.cpp
+++ b/src/mongo/db/storage/wiredtiger/wiredtiger_util.cpp
@@ -39,6 +39,9 @@
#include "mongo/bson/bsonobjbuilder.h"
#include "mongo/db/concurrency/write_conflict_exception.h"
+#include "mongo/db/storage/wiredtiger/wiredtiger_recovery_unit.h"
+#include "mongo/db/storage/wiredtiger/wiredtiger_session_cache.h"
+#include "mongo/platform/unordered_set.h"
#include "mongo/util/assert_util.h"
#include "mongo/util/mongoutils/str.h"
#include "mongo/util/scopeguard.h"
@@ -70,6 +73,139 @@ namespace mongo {
return Status(ErrorCodes::UnknownError, s);
}
+ StatusWith<std::string> WiredTigerUtil::getMetadata(OperationContext* opCtx,
+ const StringData& uri) {
+ invariant(opCtx);
+ WiredTigerCursor curwrap("metadata:", WiredTigerSession::kMetadataCursorId, opCtx);
+ WT_CURSOR* cursor = curwrap.get();
+ cursor->set_key(cursor, uri);
+ int ret = cursor->search(cursor);
+ if (ret == WT_NOTFOUND) {
+ return StatusWith<std::string>(ErrorCodes::NoSuchKey, str::stream()
+ << "Unable to find metadata for " << uri);
+ }
+ else if (ret != 0) {
+ return StatusWith<std::string>(wtRCToStatus(ret));
+ }
+ const char* metadata = NULL;
+ ret = cursor->get_value(cursor, &metadata);
+ if (ret != 0) {
+ return StatusWith<std::string>(wtRCToStatus(ret));
+ }
+ invariant(metadata);
+ return StatusWith<std::string>(metadata);
+ }
+
+ Status WiredTigerUtil::getApplicationMetadata(OperationContext* opCtx,
+ const StringData& uri,
+ BSONObjBuilder* bob) {
+ StatusWith<std::string> metadataResult = getMetadata(opCtx, uri);
+ if (!metadataResult.isOK()) {
+ return metadataResult.getStatus();
+ }
+ WiredTigerConfigParser topParser(metadataResult.getValue());
+ WT_CONFIG_ITEM appMetadata;
+ if (topParser.get("app_metadata", &appMetadata) != 0) {
+ Status::OK();
+ }
+ if (appMetadata.len == 0) {
+ return Status::OK();
+ }
+ if (appMetadata.type != WT_CONFIG_ITEM::WT_CONFIG_ITEM_STRUCT) {
+ return Status(ErrorCodes::FailedToParse, str::stream()
+ << "app_metadata must be a nested struct. Actual value: "
+ << StringData(appMetadata.str, appMetadata.len));
+ }
+
+ WiredTigerConfigParser parser(appMetadata);
+ WT_CONFIG_ITEM keyItem;
+ WT_CONFIG_ITEM valueItem;
+ int ret;
+ unordered_set<StringData, StringData::Hasher> keysSeen;
+ while ((ret = parser.next(&keyItem, &valueItem)) == 0) {
+ const StringData key(keyItem.str, keyItem.len);
+ if (keysSeen.count(key)) {
+ return Status(ErrorCodes::DuplicateKey, str::stream()
+ << "app_metadata must not contain duplicate keys. "
+ << "Found multiple instances of key '" << key << "'.");
+ }
+ keysSeen.insert(key);
+
+ switch (valueItem.type) {
+ case WT_CONFIG_ITEM::WT_CONFIG_ITEM_BOOL:
+ bob->appendBool(key, valueItem.val);
+ break;
+ case WT_CONFIG_ITEM::WT_CONFIG_ITEM_NUM:
+ bob->appendIntOrLL(key, valueItem.val);
+ break;
+ default:
+ bob->append(key, StringData(valueItem.str, valueItem.len));
+ break;
+ }
+ }
+ if (ret != WT_NOTFOUND) {
+ return wtRCToStatus(ret);
+ }
+
+ return Status::OK();
+ }
+
+ StatusWith<BSONObj> WiredTigerUtil::getApplicationMetadata(OperationContext* opCtx,
+ const StringData& uri) {
+ BSONObjBuilder bob;
+ Status status = getApplicationMetadata(opCtx, uri, &bob);
+ if (!status.isOK()) {
+ return StatusWith<BSONObj>(status);
+ }
+ return StatusWith<BSONObj>(bob.obj());
+ }
+
+ Status WiredTigerUtil::checkApplicationMetadataFormatVersion(OperationContext* opCtx,
+ const StringData& uri,
+ int64_t minimumVersion,
+ int64_t maximumVersion) {
+
+ StatusWith<std::string> result = getMetadata(opCtx, uri);
+ if (result.getStatus().code() == ErrorCodes::NoSuchKey) {
+ return result.getStatus();
+ }
+ invariantOK(result.getStatus());
+
+ WiredTigerConfigParser topParser(result.getValue());
+ WT_CONFIG_ITEM metadata;
+ if (topParser.get("app_metadata", &metadata) != 0)
+ return Status(ErrorCodes::UnsupportedFormat, str::stream()
+ << "application metadata for " << uri
+ << " is missing ");
+
+ WiredTigerConfigParser parser(metadata);
+
+ int64_t version = 0;
+ WT_CONFIG_ITEM versionItem;
+ if (parser.get("formatVersion", &versionItem) != 0) {
+ // If 'formatVersion' is missing, this metadata was introduced by
+ // one of the RC versions (where the format version is 1).
+ version = 1;
+ }
+ else if (versionItem.type == WT_CONFIG_ITEM::WT_CONFIG_ITEM_NUM) {
+ version = versionItem.val;
+ }
+ else {
+ return Status(ErrorCodes::UnsupportedFormat, str::stream()
+ << "'formatVersion' in application metadata for " << uri
+ << " must be a number. Current value: "
+ << StringData(versionItem.str, versionItem.len));
+ }
+
+ if (version < minimumVersion || version > maximumVersion) {
+ return Status(ErrorCodes::UnsupportedFormat, str::stream()
+ << "Application metadata for " << uri
+ << " has unsupported format version " << version);
+ }
+
+ return Status::OK();
+ }
+
// static
StatusWith<uint64_t> WiredTigerUtil::getStatisticsValue(WT_SESSION* session,
const std::string& uri,
diff --git a/src/mongo/db/storage/wiredtiger/wiredtiger_util.h b/src/mongo/db/storage/wiredtiger/wiredtiger_util.h
index b40c271a860..aeaeaa72a13 100644
--- a/src/mongo/db/storage/wiredtiger/wiredtiger_util.h
+++ b/src/mongo/db/storage/wiredtiger/wiredtiger_util.h
@@ -36,11 +36,14 @@
#include "mongo/base/disallow_copying.h"
#include "mongo/base/status.h"
#include "mongo/base/status_with.h"
+#include "mongo/bson/bsonobj.h"
#include "mongo/util/assert_util.h"
namespace mongo {
class BSONObjBuilder;
+ class OperationContext;
+ class WiredTigerConfigParser;
inline bool wt_keeptxnopen() {
return false;
@@ -97,6 +100,31 @@ namespace mongo {
BSONObjBuilder* bob);
/**
+ * Gets entire metadata string for collection/index at URI.
+ */
+ static StatusWith<std::string> getMetadata(OperationContext* opCtx,
+ const StringData& uri);
+
+ /**
+ * Reads app_metadata for collection/index at URI as a BSON document.
+ */
+ static Status getApplicationMetadata(OperationContext* opCtx,
+ const StringData& uri,
+ BSONObjBuilder* bob);
+
+ static StatusWith<BSONObj> getApplicationMetadata(OperationContext* opCtx,
+ const StringData& uri);
+
+ /**
+ * Validates formatVersion in application metadata for 'uri'.
+ * Version must be numeric and be in the range [minimumVersion, maximumVersion].
+ * URI is used in error messages only.
+ */
+ static Status checkApplicationMetadataFormatVersion(OperationContext* opCtx,
+ const StringData& uri,
+ int64_t minimumVersion,
+ int64_t maximumVersion);
+ /**
* Reads individual statistics using URI.
* List of statistics keys WT_STAT_* can be found in wiredtiger.h.
*/
diff --git a/src/mongo/db/storage/wiredtiger/wiredtiger_util_test.cpp b/src/mongo/db/storage/wiredtiger/wiredtiger_util_test.cpp
index 328c8041a2b..cffc1a01284 100644
--- a/src/mongo/db/storage/wiredtiger/wiredtiger_util_test.cpp
+++ b/src/mongo/db/storage/wiredtiger/wiredtiger_util_test.cpp
@@ -30,10 +30,12 @@
#include "mongo/platform/basic.h"
+#include <boost/scoped_ptr.hpp>
#include <sstream>
#include <string>
#include "mongo/base/string_data.h"
+#include "mongo/db/operation_context_noop.h"
#include "mongo/db/storage/wiredtiger/wiredtiger_recovery_unit.h"
#include "mongo/db/storage/wiredtiger/wiredtiger_session_cache.h"
#include "mongo/db/storage/wiredtiger/wiredtiger_util.h"
@@ -76,12 +78,187 @@ namespace mongo {
return &_sessionCache;
}
+ OperationContext* newOperationContext() {
+ return new OperationContextNoop(new WiredTigerRecoveryUnit(getSessionCache()));
+ }
+
private:
unittest::TempDir _dbpath;
WiredTigerConnection _connection;
WiredTigerSessionCache _sessionCache;
};
+ class WiredTigerUtilMetadataTest : public mongo::unittest::Test {
+ public:
+ virtual void setUp() {
+ _harnessHelper.reset(new WiredTigerUtilHarnessHelper(""));
+ _opCtx.reset(_harnessHelper->newOperationContext());
+ }
+
+ virtual void tearDown() {
+ _opCtx.reset(NULL);
+ _harnessHelper.reset(NULL);
+ }
+
+ protected:
+ const char* getURI() const {
+ return "table:mytable";
+ }
+
+ OperationContext* getOperationContext() const {
+ ASSERT(_opCtx.get());
+ return _opCtx.get();
+ }
+
+ void createSession(const char* config) {
+ WT_SESSION* wtSession =
+ WiredTigerRecoveryUnit::get(_opCtx.get())->getSession()->getSession();
+ ASSERT_OK(wtRCToStatus(wtSession->create(wtSession, getURI(), config)));
+ }
+ private:
+ boost::scoped_ptr<WiredTigerUtilHarnessHelper> _harnessHelper;
+ boost::scoped_ptr<OperationContext> _opCtx;
+ };
+
+ TEST_F(WiredTigerUtilMetadataTest, GetConfigurationStringInvalidURI) {
+ StatusWith<std::string> result =
+ WiredTigerUtil::getMetadata(getOperationContext(), getURI());
+ ASSERT_NOT_OK(result.getStatus());
+ ASSERT_EQUALS(ErrorCodes::NoSuchKey, result.getStatus().code());
+ }
+
+ TEST_F(WiredTigerUtilMetadataTest, GetConfigurationStringNull) {
+ const char* config = NULL;
+ createSession(config);
+ StatusWith<std::string> result =
+ WiredTigerUtil::getMetadata(getOperationContext(), getURI());
+ ASSERT_OK(result.getStatus());
+ ASSERT_FALSE(result.getValue().empty());
+ }
+
+ TEST_F(WiredTigerUtilMetadataTest, GetConfigurationStringSimple) {
+ const char* config = "app_metadata=(abc=123)";
+ createSession(config);
+ StatusWith<std::string> result =
+ WiredTigerUtil::getMetadata(getOperationContext(), getURI());
+ ASSERT_OK(result.getStatus());
+ ASSERT_STRING_CONTAINS(result.getValue(), config);
+ }
+
+ TEST_F(WiredTigerUtilMetadataTest, GetApplicationMetadataInvalidURI) {
+ StatusWith<BSONObj> result =
+ WiredTigerUtil::getApplicationMetadata(getOperationContext(), getURI());
+ ASSERT_NOT_OK(result.getStatus());
+ ASSERT_EQUALS(ErrorCodes::NoSuchKey, result.getStatus().code());
+ }
+
+ TEST_F(WiredTigerUtilMetadataTest, GetApplicationMetadataNull) {
+ const char* config = NULL;
+ createSession(config);
+ StatusWith<BSONObj> result =
+ WiredTigerUtil::getApplicationMetadata(getOperationContext(), getURI());
+ ASSERT_OK(result.getStatus());
+ ASSERT_TRUE(result.getValue().isEmpty());
+ }
+
+ TEST_F(WiredTigerUtilMetadataTest, GetApplicationMetadataString) {
+ const char* config = "app_metadata=\"abc\"";
+ createSession(config);
+ StatusWith<BSONObj> result =
+ WiredTigerUtil::getApplicationMetadata(getOperationContext(), getURI());
+ ASSERT_NOT_OK(result.getStatus());
+ ASSERT_EQUALS(ErrorCodes::FailedToParse, result.getStatus().code());
+ }
+
+ TEST_F(WiredTigerUtilMetadataTest, GetApplicationMetadataInvalidMetadata) {
+ const char* config = "app_metadata=(abc=def=ghi)";
+ createSession(config);
+ StatusWith<BSONObj> result =
+ WiredTigerUtil::getApplicationMetadata(getOperationContext(), getURI());
+ ASSERT_NOT_OK(result.getStatus());
+ ASSERT_EQUALS(ErrorCodes::BadValue, result.getStatus().code());
+ }
+
+ TEST_F(WiredTigerUtilMetadataTest, GetApplicationMetadataDuplicateKeys) {
+ const char* config = "app_metadata=(abc=123,abc=456)";
+ createSession(config);
+ StatusWith<BSONObj> result =
+ WiredTigerUtil::getApplicationMetadata(getOperationContext(), getURI());
+ ASSERT_NOT_OK(result.getStatus());
+ ASSERT_EQUALS(ErrorCodes::DuplicateKey, result.getStatus().code());
+ }
+
+ TEST_F(WiredTigerUtilMetadataTest, GetApplicationMetadataTypes) {
+ const char* config = "app_metadata=(stringkey=\"abc\",boolkey1=true,boolkey2=false,"
+ "idkey=def,numkey=123,"
+ "structkey=(k1=v2,k2=v2))";
+ createSession(config);
+ StatusWith<BSONObj> result =
+ WiredTigerUtil::getApplicationMetadata(getOperationContext(), getURI());
+ ASSERT_OK(result.getStatus());
+ const BSONObj& obj = result.getValue();
+
+ BSONElement stringElement = obj.getField("stringkey");
+ ASSERT_EQUALS(mongo::String, stringElement.type());
+ ASSERT_EQUALS("abc", stringElement.String());
+
+ BSONElement boolElement1 = obj.getField("boolkey1");
+ ASSERT_TRUE(boolElement1.isBoolean());
+ ASSERT_TRUE(boolElement1.boolean());
+
+ BSONElement boolElement2 = obj.getField("boolkey2");
+ ASSERT_TRUE(boolElement2.isBoolean());
+ ASSERT_FALSE(boolElement2.boolean());
+
+ BSONElement identifierElement = obj.getField("idkey");
+ ASSERT_EQUALS(mongo::String, identifierElement.type());
+ ASSERT_EQUALS("def", identifierElement.String());
+
+ BSONElement numberElement = obj.getField("numkey");
+ ASSERT_TRUE(numberElement.isNumber());
+ ASSERT_EQUALS(123, numberElement.numberInt());
+
+ BSONElement structElement = obj.getField("structkey");
+ ASSERT_EQUALS(mongo::String, structElement.type());
+ ASSERT_EQUALS("(k1=v2,k2=v2)", structElement.String());
+ }
+
+ TEST_F(WiredTigerUtilMetadataTest, CheckApplicationMetadataFormatVersionMissingKey) {
+ createSession("app_metadata=(abc=123)");
+ ASSERT_OK(WiredTigerUtil::checkApplicationMetadataFormatVersion(getOperationContext(),
+ getURI(),
+ 1,
+ 1));
+ ASSERT_NOT_OK(WiredTigerUtil::checkApplicationMetadataFormatVersion(getOperationContext(),
+ getURI(),
+ 2,
+ 2));
+ }
+
+ TEST_F(WiredTigerUtilMetadataTest, CheckApplicationMetadataFormatVersionString) {
+ createSession("app_metadata=(formatVersion=\"bar\")");
+ ASSERT_NOT_OK(WiredTigerUtil::checkApplicationMetadataFormatVersion(getOperationContext(),
+ getURI(),
+ 1,
+ 1));
+ }
+
+ TEST_F(WiredTigerUtilMetadataTest, CheckApplicationMetadataFormatVersionNumber) {
+ createSession("app_metadata=(formatVersion=2)");
+ ASSERT_OK(WiredTigerUtil::checkApplicationMetadataFormatVersion(getOperationContext(),
+ getURI(),
+ 2,
+ 3));
+ ASSERT_NOT_OK(WiredTigerUtil::checkApplicationMetadataFormatVersion(getOperationContext(),
+ getURI(),
+ 1,
+ 1));
+ ASSERT_NOT_OK(WiredTigerUtil::checkApplicationMetadataFormatVersion(getOperationContext(),
+ getURI(),
+ 3,
+ 3));
+ }
+
TEST(WiredTigerUtilTest, GetStatisticsValueMissingTable) {
WiredTigerUtilHarnessHelper harnessHelper("statistics=(all)");
WiredTigerRecoveryUnit recoveryUnit(harnessHelper.getSessionCache());