summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJamie Heppenstall <jamie.heppenstall@mongodb.com>2019-06-17 14:42:54 -0400
committerJamie Heppenstall <jamie.heppenstall@mongodb.com>2019-07-12 16:59:06 -0400
commit6e02a4d34bd972e6755bb5f71a5b26f69fe2cfb0 (patch)
tree1a68aa771c357aceb88686004b4f2e730afa17d2
parent75e47b701d34c9ef7beb0482121ac8b62d2d4991 (diff)
downloadmongo-6e02a4d34bd972e6755bb5f71a5b26f69fe2cfb0.tar.gz
SERVER-41658 Convert ShardCollectionType into an IDL type
-rw-r--r--src/mongo/bson/bsonobj.cpp4
-rw-r--r--src/mongo/bson/bsonobj.h3
-rw-r--r--src/mongo/db/keypattern.h15
-rw-r--r--src/mongo/db/keypattern.idl42
-rw-r--r--src/mongo/db/s/migration_source_manager.cpp12
-rw-r--r--src/mongo/db/s/shard_metadata_util.cpp31
-rw-r--r--src/mongo/db/s/shard_metadata_util_test.cpp44
-rw-r--r--src/mongo/db/s/shard_server_catalog_cache_loader.cpp30
-rw-r--r--src/mongo/db/s/shard_server_op_observer.cpp8
-rw-r--r--src/mongo/idl/basic_types.idl8
-rw-r--r--src/mongo/s/SConscript3
-rw-r--r--src/mongo/s/catalog/type_shard_collection.cpp218
-rw-r--r--src/mongo/s/catalog/type_shard_collection.h188
-rw-r--r--src/mongo/s/catalog/type_shard_collection.idl113
-rw-r--r--src/mongo/s/catalog/type_shard_collection_test.cpp155
-rw-r--r--src/mongo/s/chunk_version.cpp4
-rw-r--r--src/mongo/s/chunk_version.h16
-rw-r--r--src/mongo/s/chunk_version.idl8
-rw-r--r--src/mongo/s/shard_key_pattern_test.cpp2
-rw-r--r--src/mongo/util/uuid.h1
20 files changed, 387 insertions, 518 deletions
diff --git a/src/mongo/bson/bsonobj.cpp b/src/mongo/bson/bsonobj.cpp
index 57bbd59969b..cecc98f299c 100644
--- a/src/mongo/bson/bsonobj.cpp
+++ b/src/mongo/bson/bsonobj.cpp
@@ -110,6 +110,10 @@ BSONObj BSONObj::getOwned() const {
return copy();
}
+BSONObj BSONObj::getOwned(const BSONObj& obj) {
+ return obj.getOwned();
+}
+
std::string BSONObj::jsonString(JsonStringFormat format, int pretty, bool isArray) const {
std::stringstream s;
BSONObj::jsonStringStream(format, pretty, isArray, s);
diff --git a/src/mongo/bson/bsonobj.h b/src/mongo/bson/bsonobj.h
index 68354bb462b..9cefccb7d78 100644
--- a/src/mongo/bson/bsonobj.h
+++ b/src/mongo/bson/bsonobj.h
@@ -240,6 +240,9 @@ public:
*/
BSONObj getOwned() const;
+ /** Returns an owned copy of the given BSON object. */
+ static BSONObj getOwned(const BSONObj& obj);
+
/** @return a new full (and owned) copy of the object. */
BSONObj copy() const;
diff --git a/src/mongo/db/keypattern.h b/src/mongo/db/keypattern.h
index d87bc8632c5..ac31301b7f2 100644
--- a/src/mongo/db/keypattern.h
+++ b/src/mongo/db/keypattern.h
@@ -29,6 +29,7 @@
#pragma once
+#include "mongo/base/status.h"
#include "mongo/base/string_data.h"
#include "mongo/bson/util/builder.h"
#include "mongo/db/jsobj.h"
@@ -68,10 +69,20 @@ public:
static bool isHashedKeyPattern(const BSONObj& pattern);
/**
- * Constructs a new key pattern based on a BSON document
+ * Constructs a new key pattern based on a BSON document.
+ * Used as an interface to the IDL parser.
+ */
+ static KeyPattern fromBSON(const BSONObj& pattern) {
+ return KeyPattern(pattern.getOwned());
+ }
+
+ /**
+ * Constructs a new key pattern based on a BSON document.
*/
KeyPattern(const BSONObj& pattern);
+ explicit KeyPattern() = default;
+
/**
* Returns a BSON representation of this KeyPattern.
*/
@@ -80,7 +91,7 @@ public:
}
/**
- * Returns a string representation of this KeyPattern
+ * Returns a string representation of this KeyPattern.
*/
std::string toString() const {
return str::stream() << *this;
diff --git a/src/mongo/db/keypattern.idl b/src/mongo/db/keypattern.idl
new file mode 100644
index 00000000000..158c742faab
--- /dev/null
+++ b/src/mongo/db/keypattern.idl
@@ -0,0 +1,42 @@
+# Copyright (C) 2019-present MongoDB, Inc.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the Server Side Public License, version 1,
+# as published by MongoDB, Inc.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# Server Side Public License for more details.
+#
+# You should have received a copy of the Server Side Public License
+# along with this program. If not, see
+# <http://www.mongodb.com/licensing/server-side-public-license>.
+#
+# As a special exception, the copyright holders give permission to link the
+# code of portions of this program with the OpenSSL library under certain
+# conditions as described in each individual source file and distribute
+# linked combinations including the program with the OpenSSL library. You
+# must comply with the Server Side Public License in all respects for
+# all of the code used other than as permitted herein. If you modify file(s)
+# with this exception, you may extend this exception to your version of the
+# file(s), but you are not obligated to do so. If you do not wish to do so,
+# delete this exception statement from your version. If you delete this
+# exception statement from all source files in the program, then also delete
+# it in the license file.
+#
+
+# KeyPattern IDL type definition
+
+global:
+ cpp_namespace: "mongo"
+ cpp_includes:
+ - "mongo/db/keypattern.h"
+
+types:
+ KeyPattern:
+ bson_serialization_type: object
+ description: An expression describing a transformation of a document into a document key.
+ cpp_type: KeyPattern
+ serializer: KeyPattern::toBSON
+ deserializer: KeyPattern::fromBSON
diff --git a/src/mongo/db/s/migration_source_manager.cpp b/src/mongo/db/s/migration_source_manager.cpp
index 4e9fb2fd0ff..ccd90364e31 100644
--- a/src/mongo/db/s/migration_source_manager.cpp
+++ b/src/mongo/db/s/migration_source_manager.cpp
@@ -342,12 +342,12 @@ Status MigrationSourceManager::enterCriticalSection(OperationContext* opCtx) {
// time inclusive of the migration config commit update from accessing secondary data.
// Note: this write must occur after the critSec flag is set, to ensure the secondary refresh
// will stall behind the flag.
- Status signalStatus =
- updateShardCollectionsEntry(opCtx,
- BSON(ShardCollectionType::ns() << getNss().ns()),
- BSONObj(),
- BSON(ShardCollectionType::enterCriticalSectionCounter() << 1),
- false /*upsert*/);
+ Status signalStatus = updateShardCollectionsEntry(
+ opCtx,
+ BSON(ShardCollectionType::kNssFieldName << getNss().ns()),
+ BSONObj(),
+ BSON(ShardCollectionType::kEnterCriticalSectionCounterFieldName << 1),
+ false /*upsert*/);
if (!signalStatus.isOK()) {
return {
ErrorCodes::OperationFailed,
diff --git a/src/mongo/db/s/shard_metadata_util.cpp b/src/mongo/db/s/shard_metadata_util.cpp
index 59b6a5562f3..627f955fd67 100644
--- a/src/mongo/db/s/shard_metadata_util.cpp
+++ b/src/mongo/db/s/shard_metadata_util.cpp
@@ -94,12 +94,12 @@ Status unsetPersistedRefreshFlags(OperationContext* opCtx,
const ChunkVersion& refreshedVersion) {
// Set 'refreshing' to false and update the last refreshed collection version.
BSONObjBuilder updateBuilder;
- updateBuilder.append(ShardCollectionType::refreshing(), false);
- updateBuilder.appendTimestamp(ShardCollectionType::lastRefreshedCollectionVersion(),
+ updateBuilder.append(ShardCollectionType::kRefreshingFieldName, false);
+ updateBuilder.appendTimestamp(ShardCollectionType::kLastRefreshedCollectionVersionFieldName,
refreshedVersion.toLong());
return updateShardCollectionsEntry(opCtx,
- BSON(ShardCollectionType::ns() << nss.ns()),
+ BSON(ShardCollectionType::kNssFieldName << nss.ns()),
updateBuilder.obj(),
BSONObj(),
false /*upsert*/);
@@ -114,14 +114,14 @@ StatusWith<RefreshState> getPersistedRefreshFlags(OperationContext* opCtx,
ShardCollectionType entry = statusWithCollectionEntry.getValue();
// Ensure the results have not been incorrectly set somehow.
- if (entry.hasRefreshing()) {
+ if (entry.getRefreshing()) {
// If 'refreshing' is present and false, a refresh must have occurred (otherwise the field
// would never have been added to the document) and there should always be a refresh
// version.
- invariant(entry.getRefreshing() ? true : entry.hasLastRefreshedCollectionVersion());
+ invariant(*entry.getRefreshing() ? true : !!entry.getLastRefreshedCollectionVersion());
} else {
// If 'refreshing' is not present, no refresh version should exist.
- invariant(!entry.hasLastRefreshedCollectionVersion());
+ invariant(!entry.getLastRefreshedCollectionVersion());
}
return RefreshState{entry.getEpoch(),
@@ -129,16 +129,16 @@ StatusWith<RefreshState> getPersistedRefreshFlags(OperationContext* opCtx,
// refresh has started, but no chunks have ever yet been applied, around
// which these flags are set. So default to refreshing true because the
// chunk metadata is being updated and is not yet ready to be read.
- entry.hasRefreshing() ? entry.getRefreshing() : true,
- entry.hasLastRefreshedCollectionVersion()
- ? entry.getLastRefreshedCollectionVersion()
+ entry.getRefreshing() ? *entry.getRefreshing() : true,
+ entry.getLastRefreshedCollectionVersion()
+ ? *entry.getLastRefreshedCollectionVersion()
: ChunkVersion(0, 0, entry.getEpoch())};
}
StatusWith<ShardCollectionType> readShardCollectionsEntry(OperationContext* opCtx,
const NamespaceString& nss) {
- Query fullQuery(BSON(ShardCollectionType::ns() << nss.ns()));
+ Query fullQuery(BSON(ShardCollectionType::kNssFieldName << nss.ns()));
try {
DBDirectClient client(opCtx);
@@ -158,12 +158,7 @@ StatusWith<ShardCollectionType> readShardCollectionsEntry(OperationContext* opCt
}
BSONObj document = cursor->nextSafe();
- auto statusWithCollectionEntry = ShardCollectionType::fromBSON(document);
- if (!statusWithCollectionEntry.isOK()) {
- return statusWithCollectionEntry.getStatus();
- }
-
- return statusWithCollectionEntry.getValue();
+ return ShardCollectionType::fromBSON(document);
} catch (const DBException& ex) {
return ex.toStatus(str::stream() << "Failed to read the '" << nss.ns()
<< "' entry locally from config.collections");
@@ -212,7 +207,7 @@ Status updateShardCollectionsEntry(OperationContext* opCtx,
if (upsert) {
// If upserting, this should be an update from the config server that does not have shard
// refresh / migration inc signal information.
- invariant(!update.hasField(ShardCollectionType::lastRefreshedCollectionVersion()));
+ invariant(!update.hasField(ShardCollectionType::kLastRefreshedCollectionVersionFieldName));
invariant(inc.isEmpty());
}
@@ -411,7 +406,7 @@ Status dropChunksAndDeleteCollectionsEntry(OperationContext* opCtx, const Namesp
write_ops::Delete deleteOp(NamespaceString::kShardConfigCollectionsNamespace);
deleteOp.setDeletes({[&] {
write_ops::DeleteOpEntry entry;
- entry.setQ(BSON(ShardCollectionType::ns << nss.ns()));
+ entry.setQ(BSON(ShardCollectionType::kNssFieldName << nss.ns()));
entry.setMulti(true);
return entry;
}()});
diff --git a/src/mongo/db/s/shard_metadata_util_test.cpp b/src/mongo/db/s/shard_metadata_util_test.cpp
index 3776b6e89e9..86bf071f3ac 100644
--- a/src/mongo/db/s/shard_metadata_util_test.cpp
+++ b/src/mongo/db/s/shard_metadata_util_test.cpp
@@ -44,11 +44,12 @@
namespace mongo {
namespace {
+using namespace shardmetadatautil;
+
using std::string;
using std::unique_ptr;
using std::vector;
using unittest::assertGet;
-using namespace shardmetadatautil;
const NamespaceString kNss = NamespaceString("test.foo");
const NamespaceString kChunkMetadataNss = NamespaceString("config.cache.chunks.test.foo");
@@ -61,22 +62,23 @@ struct ShardMetadataUtilTest : public ShardServerTestFixture {
*/
ShardCollectionType setUpCollection() {
BSONObjBuilder builder;
- builder.append(ShardCollectionType::ns(), kNss.ns());
- uuid.appendToBuilder(&builder, ShardCollectionType::uuid());
- builder.append(ShardCollectionType::epoch(), maxCollVersion.epoch());
- builder.append(ShardCollectionType::keyPattern(), keyPattern.toBSON());
- builder.append(ShardCollectionType::defaultCollation(), defaultCollation);
- builder.append(ShardCollectionType::unique(), kUnique);
+ builder.append(ShardCollectionType::kNssFieldName, kNss.ns());
+ builder.append(ShardCollectionType::kEpochFieldName, maxCollVersion.epoch());
+ builder.append(ShardCollectionType::kKeyPatternFieldName, keyPattern.toBSON());
+ builder.append(ShardCollectionType::kDefaultCollationFieldName, defaultCollation);
+ builder.append(ShardCollectionType::kUniqueFieldName, kUnique);
+
ShardCollectionType shardCollectionType =
assertGet(ShardCollectionType::fromBSON(builder.obj()));
-
+ shardCollectionType.setUuid(uuid);
shardCollectionType.setRefreshing(true);
ASSERT_OK(updateShardCollectionsEntry(operationContext(),
- BSON(ShardCollectionType::ns(kNss.ns())),
+ BSON(ShardCollectionType::kNssFieldName << kNss.ns()),
shardCollectionType.toBSON(),
BSONObj(),
true /*upsert*/));
+
return shardCollectionType;
}
@@ -175,8 +177,8 @@ TEST_F(ShardMetadataUtilTest, UpdateAndReadCollectionsEntry) {
ShardCollectionType readShardCollectionType =
assertGet(readShardCollectionsEntry(operationContext(), kNss));
- ASSERT_TRUE(readShardCollectionType.getUUID());
- ASSERT_EQUALS(*updateShardCollectionType.getUUID(), *readShardCollectionType.getUUID());
+ ASSERT(readShardCollectionType.getUuid());
+ ASSERT_EQUALS(*updateShardCollectionType.getUuid(), *readShardCollectionType.getUuid());
ASSERT_EQUALS(updateShardCollectionType.getNss(), readShardCollectionType.getNss());
ASSERT_EQUALS(updateShardCollectionType.getEpoch(), readShardCollectionType.getEpoch());
ASSERT_BSONOBJ_EQ(updateShardCollectionType.getKeyPattern().toBSON(),
@@ -184,12 +186,12 @@ TEST_F(ShardMetadataUtilTest, UpdateAndReadCollectionsEntry) {
ASSERT_BSONOBJ_EQ(updateShardCollectionType.getDefaultCollation(),
readShardCollectionType.getDefaultCollation());
ASSERT_EQUALS(updateShardCollectionType.getUnique(), readShardCollectionType.getUnique());
- ASSERT_EQUALS(updateShardCollectionType.hasRefreshing(),
- readShardCollectionType.hasRefreshing());
+ ASSERT_EQUALS(*updateShardCollectionType.getRefreshing(),
+ *readShardCollectionType.getRefreshing());
// Refresh fields should not have been set.
- ASSERT(!updateShardCollectionType.hasLastRefreshedCollectionVersion());
- ASSERT(!readShardCollectionType.hasLastRefreshedCollectionVersion());
+ ASSERT(!updateShardCollectionType.getLastRefreshedCollectionVersion());
+ ASSERT(!readShardCollectionType.getLastRefreshedCollectionVersion());
}
TEST_F(ShardMetadataUtilTest, PersistedRefreshSignalStartAndFinish) {
@@ -198,19 +200,19 @@ TEST_F(ShardMetadataUtilTest, PersistedRefreshSignalStartAndFinish) {
ShardCollectionType shardCollectionsEntry =
assertGet(readShardCollectionsEntry(operationContext(), kNss));
- ASSERT_EQUALS(*shardCollectionsEntry.getUUID(), uuid);
+ ASSERT_EQUALS(*shardCollectionsEntry.getUuid(), uuid);
ASSERT_EQUALS(shardCollectionsEntry.getNss().ns(), kNss.ns());
ASSERT_EQUALS(shardCollectionsEntry.getEpoch(), maxCollVersion.epoch());
ASSERT_BSONOBJ_EQ(shardCollectionsEntry.getKeyPattern().toBSON(), keyPattern.toBSON());
ASSERT_BSONOBJ_EQ(shardCollectionsEntry.getDefaultCollation(), defaultCollation);
ASSERT_EQUALS(shardCollectionsEntry.getUnique(), kUnique);
- ASSERT_EQUALS(shardCollectionsEntry.getRefreshing(), true);
- ASSERT(!shardCollectionsEntry.hasLastRefreshedCollectionVersion());
+ ASSERT_EQUALS(*shardCollectionsEntry.getRefreshing(), true);
+ ASSERT(!shardCollectionsEntry.getLastRefreshedCollectionVersion());
// Signal refresh start again to make sure nothing changes
ASSERT_OK(updateShardCollectionsEntry(operationContext(),
- BSON(ShardCollectionType::ns() << kNss.ns()),
- BSON(ShardCollectionType::refreshing() << true),
+ BSON(ShardCollectionType::kNssFieldName << kNss.ns()),
+ BSON(ShardCollectionType::kRefreshingFieldName << true),
BSONObj(),
false));
@@ -259,7 +261,7 @@ TEST_F(ShardMetadataUtilTest, WriteAndReadChunks) {
boost::none,
maxCollVersion.epoch()));
- ASSERT_TRUE(readChunks.size() == 1);
+ ASSERT(readChunks.size() == 1);
ASSERT_BSONOBJ_EQ(chunks.back().toShardBSON(), readChunks.front().toShardBSON());
}
diff --git a/src/mongo/db/s/shard_server_catalog_cache_loader.cpp b/src/mongo/db/s/shard_server_catalog_cache_loader.cpp
index 7a87d9c9ed0..81142fd65ef 100644
--- a/src/mongo/db/s/shard_server_catalog_cache_loader.cpp
+++ b/src/mongo/db/s/shard_server_catalog_cache_loader.cpp
@@ -85,21 +85,23 @@ Status persistCollectionAndChangedChunks(OperationContext* opCtx,
const NamespaceString& nss,
const CollectionAndChangedChunks& collAndChunks) {
// Update the collections collection entry for 'nss' in case there are any new updates.
- ShardCollectionType update = ShardCollectionType(nss,
- collAndChunks.uuid,
- collAndChunks.epoch,
- collAndChunks.shardKeyPattern,
- collAndChunks.defaultCollation,
- collAndChunks.shardKeyIsUnique);
+ ShardCollectionType update = ShardCollectionType(
+ nss, collAndChunks.epoch, collAndChunks.shardKeyPattern, collAndChunks.shardKeyIsUnique);
+
+ update.setUuid(collAndChunks.uuid);
+ if (!collAndChunks.defaultCollation.isEmpty()) {
+ update.setDefaultCollation(collAndChunks.defaultCollation.getOwned());
+ }
// Mark the chunk metadata as refreshing, so that secondaries are aware of refresh.
update.setRefreshing(true);
- Status status = updateShardCollectionsEntry(opCtx,
- BSON(ShardCollectionType::ns() << nss.ns()),
- update.toBSON(),
- BSONObj(),
- true /*upsert*/);
+ Status status =
+ updateShardCollectionsEntry(opCtx,
+ BSON(ShardCollectionType::kNssFieldName << nss.ns()),
+ update.toBSON(),
+ BSONObj(),
+ true /*upsert*/);
if (!status.isOK()) {
return status;
}
@@ -211,7 +213,7 @@ CollectionAndChangedChunks getPersistedMetadataSinceVersion(OperationContext* op
auto changedChunks = uassertStatusOK(
readShardChunks(opCtx, nss, diff.query, diff.sort, boost::none, startingVersion.epoch()));
- return CollectionAndChangedChunks{shardCollectionEntry.getUUID(),
+ return CollectionAndChangedChunks{shardCollectionEntry.getUuid(),
shardCollectionEntry.getEpoch(),
shardCollectionEntry.getKeyPattern().toBSON(),
shardCollectionEntry.getDefaultCollation(),
@@ -1040,7 +1042,7 @@ void ShardServerCatalogCacheLoader::_updatePersistedCollAndChunksMetadata(
}
uassertStatusOKWithContext(
- persistCollectionAndChangedChunks(opCtx, nss, task.collectionAndChangedChunks.get()),
+ persistCollectionAndChangedChunks(opCtx, nss, *task.collectionAndChangedChunks),
str::stream() << "Failed to update the persisted chunk metadata for collection '"
<< nss.ns()
<< "' from '"
@@ -1271,7 +1273,7 @@ ShardServerCatalogCacheLoader::CollAndChunkTaskList::getEnqueuedMetadataForTerm(
} else {
if (task.collectionAndChangedChunks->epoch != collAndChunks.epoch) {
// An epoch change should reset the metadata and start from the new.
- collAndChunks = task.collectionAndChangedChunks.get();
+ collAndChunks = *task.collectionAndChangedChunks;
} else {
// Epochs match, so the new results should be appended.
diff --git a/src/mongo/db/s/shard_server_op_observer.cpp b/src/mongo/db/s/shard_server_op_observer.cpp
index 9969d9c9f30..aa1ec89d5ec 100644
--- a/src/mongo/db/s/shard_server_op_observer.cpp
+++ b/src/mongo/db/s/shard_server_op_observer.cpp
@@ -133,7 +133,7 @@ void onConfigDeleteInvalidateCachedCollectionMetadataAndNotify(OperationContext*
// Extract which collection entry is being deleted from the _id field.
std::string deletedCollection;
fassert(40479,
- bsonExtractStringField(query, ShardCollectionType::ns.name(), &deletedCollection));
+ bsonExtractStringField(query, ShardCollectionType::kNssFieldName, &deletedCollection));
const NamespaceString deletedNss(deletedCollection);
// Need the WUOW to retain the lock for CollectionVersionLogOpHandler::commit().
@@ -263,7 +263,7 @@ void ShardServerOpObserver::onUpdate(OperationContext* opCtx, const OplogUpdateE
std::string coll;
fassert(40477,
bsonExtractStringField(
- args.updateArgs.criteria, ShardCollectionType::ns.name(), &coll));
+ args.updateArgs.criteria, ShardCollectionType::kNssFieldName, &coll));
return NamespaceString(coll);
}());
@@ -277,13 +277,13 @@ void ShardServerOpObserver::onUpdate(OperationContext* opCtx, const OplogUpdateE
// Need the WUOW to retain the lock for CollectionVersionLogOpHandler::commit()
AutoGetCollection autoColl(opCtx, updatedNss, MODE_IX);
- if (setField.hasField(ShardCollectionType::refreshing.name()) &&
+ if (setField.hasField(ShardCollectionType::kLastRefreshedCollectionVersionFieldName) &&
!setField.getBoolField("refreshing")) {
opCtx->recoveryUnit()->registerChange(
new CollectionVersionLogOpHandler(opCtx, updatedNss));
}
- if (setField.hasField(ShardCollectionType::enterCriticalSectionCounter.name())) {
+ if (setField.hasField(ShardCollectionType::kEnterCriticalSectionCounterFieldName)) {
// Force subsequent uses of the namespace to refresh the filtering metadata so they
// can synchronize with any work happening on the primary (e.g., migration critical
// section).
diff --git a/src/mongo/idl/basic_types.idl b/src/mongo/idl/basic_types.idl
index 7005fdc4bc3..7ebee57fb3f 100644
--- a/src/mongo/idl/basic_types.idl
+++ b/src/mongo/idl/basic_types.idl
@@ -136,9 +136,15 @@ types:
object:
bson_serialization_type: object
- description: "A BSONObj without custom deserialization or serialization"
+ description: "An unowned BSONObj without custom deserialization or serialization"
cpp_type: "mongo::BSONObj"
+ object_owned:
+ bson_serialization_type: object
+ description: "An owned BSONObj"
+ cpp_type: "mongo::BSONObj"
+ deserializer: "BSONObj::getOwned"
+
date:
bson_serialization_type: date
description: "A BSON UTC DateTime"
diff --git a/src/mongo/s/SConscript b/src/mongo/s/SConscript
index aac39f39858..8a8b8c6692d 100644
--- a/src/mongo/s/SConscript
+++ b/src/mongo/s/SConscript
@@ -174,6 +174,7 @@ env.Library(
'stale_exception.cpp',
'would_change_owning_shard_exception.cpp',
env.Idlc('catalog/type_chunk_base.idl')[0],
+ env.Idlc('catalog/type_shard_collection.idl')[0],
env.Idlc('chunk_version.idl')[0],
env.Idlc('database_version.idl')[0],
env.Idlc('request_types/clone_catalog_data.idl')[0],
@@ -285,7 +286,6 @@ env.Library(
],
)
-
# This library contains sharding functionality used by both mongod and mongos
env.Library(
target='grid',
@@ -446,6 +446,7 @@ env.CppUnitTest(
'$BUILD_DIR/mongo/db/auth/authmocks',
'$BUILD_DIR/mongo/db/query/query_test_service_context',
'$BUILD_DIR/mongo/db/service_context_test_fixture',
+ '$BUILD_DIR/mongo/db/s/sharding_runtime_d',
'$BUILD_DIR/mongo/dbtests/mocklib',
'$BUILD_DIR/mongo/s/catalog/sharding_catalog_client_mock',
'$BUILD_DIR/mongo/util/net/network',
diff --git a/src/mongo/s/catalog/type_shard_collection.cpp b/src/mongo/s/catalog/type_shard_collection.cpp
index 354eec5262f..bc8b3576ee1 100644
--- a/src/mongo/s/catalog/type_shard_collection.cpp
+++ b/src/mongo/s/catalog/type_shard_collection.cpp
@@ -27,214 +27,46 @@
* it in the license file.
*/
-#include "mongo/platform/basic.h"
-
#include "mongo/s/catalog/type_shard_collection.h"
-#include "mongo/base/status_with.h"
-#include "mongo/bson/bsonobj.h"
-#include "mongo/bson/bsonobjbuilder.h"
-#include "mongo/bson/util/bson_extract.h"
-#include "mongo/s/catalog/type_collection.h"
-#include "mongo/util/assert_util.h"
-
namespace mongo {
-const BSONField<std::string> ShardCollectionType::ns("_id");
-const BSONField<UUID> ShardCollectionType::uuid("uuid");
-const BSONField<OID> ShardCollectionType::epoch("epoch");
-const BSONField<BSONObj> ShardCollectionType::keyPattern("key");
-const BSONField<BSONObj> ShardCollectionType::defaultCollation("defaultCollation");
-const BSONField<bool> ShardCollectionType::unique("unique");
-const BSONField<bool> ShardCollectionType::refreshing("refreshing");
-const BSONField<Date_t> ShardCollectionType::lastRefreshedCollectionVersion(
- "lastRefreshedCollectionVersion");
-const BSONField<int> ShardCollectionType::enterCriticalSectionCounter(
- "enterCriticalSectionCounter");
-
-ShardCollectionType::ShardCollectionType(NamespaceString nss,
- boost::optional<UUID> uuid,
- OID epoch,
- const KeyPattern& keyPattern,
- const BSONObj& defaultCollation,
- bool unique)
- : _nss(std::move(nss)),
- _uuid(uuid),
- _epoch(std::move(epoch)),
- _keyPattern(keyPattern.toBSON()),
- _defaultCollation(defaultCollation.getOwned()),
- _unique(unique) {}
+ShardCollectionType::ShardCollectionType(const BSONObj& obj) {
+ ShardCollectionTypeBase::parseProtected(IDLParserErrorContext("ShardCollectionType"), obj);
-StatusWith<ShardCollectionType> ShardCollectionType::fromBSON(const BSONObj& source) {
+ uassert(ErrorCodes::ShardKeyNotFound,
+ str::stream() << "Empty shard key. Failed to parse: " << obj.toString(),
+ !getKeyPattern().toBSON().isEmpty());
- NamespaceString nss;
- {
- std::string ns;
- Status status = bsonExtractStringField(source, ShardCollectionType::ns.name(), &ns);
- if (!status.isOK()) {
- return status;
- }
- nss = NamespaceString{ns};
- }
-
- boost::optional<UUID> uuid;
- {
- BSONElement uuidElem;
- Status status = bsonExtractTypedField(
- source, ShardCollectionType::uuid.name(), BSONType::BinData, &uuidElem);
- if (status.isOK()) {
- auto uuidWith = UUID::parse(uuidElem);
- if (!uuidWith.isOK())
- return uuidWith.getStatus();
- uuid = uuidWith.getValue();
- } else if (status == ErrorCodes::NoSuchKey) {
- // The field is not set, which is okay.
- } else {
- return status;
- }
- }
-
- OID epoch;
- {
- BSONElement oidElem;
- Status status = bsonExtractTypedField(
- source, ShardCollectionType::epoch.name(), BSONType::jstOID, &oidElem);
- if (!status.isOK())
- return status;
- epoch = oidElem.OID();
- }
-
- BSONElement collKeyPattern;
- Status status = bsonExtractTypedField(
- source, ShardCollectionType::keyPattern.name(), Object, &collKeyPattern);
- if (!status.isOK()) {
- return status;
- }
- BSONObj obj = collKeyPattern.Obj();
- if (obj.isEmpty()) {
- return Status(ErrorCodes::ShardKeyNotFound,
- str::stream() << "Empty shard key. Failed to parse: " << source.toString());
- }
- KeyPattern pattern(obj.getOwned());
-
- BSONObj collation;
- {
- BSONElement defaultCollation;
- Status status = bsonExtractTypedField(
- source, ShardCollectionType::defaultCollation.name(), Object, &defaultCollation);
- if (status.isOK()) {
- BSONObj obj = defaultCollation.Obj();
- if (obj.isEmpty()) {
- return Status(ErrorCodes::BadValue, "empty defaultCollation");
- }
-
- collation = obj.getOwned();
- } else if (status != ErrorCodes::NoSuchKey) {
- return status;
- }
- }
-
- bool unique;
- {
- Status status =
- bsonExtractBooleanField(source, ShardCollectionType::unique.name(), &unique);
- if (!status.isOK()) {
- return status;
- }
- }
-
- ShardCollectionType shardCollectionType(
- std::move(nss), uuid, std::move(epoch), pattern, collation, unique);
-
- // Below are optional fields.
-
- {
- bool refreshing;
- Status status =
- bsonExtractBooleanField(source, ShardCollectionType::refreshing.name(), &refreshing);
- if (status.isOK()) {
- shardCollectionType.setRefreshing(refreshing);
- } else if (status == ErrorCodes::NoSuchKey) {
- // The field is not set yet, which is okay.
- } else {
- return status;
- }
+ // Last refreshed collection version is stored as a timestamp in the BSON representation of
+ // shard collection type for legacy reasons. We therefore explicitly convert this timestamp, if
+ // it exists, into a chunk version.
+ if (getLastRefreshedCollectionVersion()) {
+ ChunkVersion version = *getLastRefreshedCollectionVersion();
+ setLastRefreshedCollectionVersion(
+ ChunkVersion(version.majorVersion(), version.minorVersion(), getEpoch()));
}
+}
- {
- if (!source[lastRefreshedCollectionVersion.name()].eoo()) {
- auto statusWithLastRefreshedCollectionVersion =
- ChunkVersion::parseLegacyWithField(source, lastRefreshedCollectionVersion());
- if (!statusWithLastRefreshedCollectionVersion.isOK()) {
- return statusWithLastRefreshedCollectionVersion.getStatus();
- }
- auto version = std::move(statusWithLastRefreshedCollectionVersion.getValue());
- shardCollectionType.setLastRefreshedCollectionVersion(
- ChunkVersion(version.majorVersion(), version.minorVersion(), epoch));
- }
+StatusWith<ShardCollectionType> ShardCollectionType::fromBSON(const BSONObj& obj) {
+ try {
+ return ShardCollectionType(obj);
+ } catch (const DBException& ex) {
+ return ex.toStatus();
}
-
- return shardCollectionType;
}
BSONObj ShardCollectionType::toBSON() const {
- BSONObjBuilder builder;
+ BSONObj obj = ShardCollectionTypeBase::toBSON();
- builder.append(ns.name(), _nss.ns());
- if (_uuid) {
- _uuid->appendToBuilder(&builder, uuid.name());
+ // Default collation is not included in the BSON representation of shard collection type, and
+ // thus persisted to disk, if it is empty. We therefore explicitly remove default collation from
+ // obj, if it is empty.
+ if (getDefaultCollation().isEmpty()) {
+ obj = obj.removeField(kDefaultCollationFieldName);
}
- builder.append(epoch.name(), _epoch);
- builder.append(keyPattern.name(), _keyPattern.toBSON());
-
- if (!_defaultCollation.isEmpty()) {
- builder.append(defaultCollation.name(), _defaultCollation);
- }
-
- builder.append(unique.name(), _unique);
-
- if (_refreshing) {
- builder.append(refreshing.name(), _refreshing.get());
- }
- if (_lastRefreshedCollectionVersion) {
- builder.appendTimestamp(lastRefreshedCollectionVersion.name(),
- _lastRefreshedCollectionVersion->toLong());
- }
-
- return builder.obj();
-}
-
-std::string ShardCollectionType::toString() const {
- return toBSON().toString();
-}
-
-void ShardCollectionType::setUUID(UUID uuid) {
- _uuid = uuid;
-}
-
-void ShardCollectionType::setNss(NamespaceString nss) {
- invariant(nss.isValid());
- _nss = std::move(nss);
-}
-
-void ShardCollectionType::setEpoch(OID epoch) {
- invariant(epoch.isSet());
- _epoch = std::move(epoch);
-}
-
-void ShardCollectionType::setKeyPattern(const KeyPattern& keyPattern) {
- invariant(!keyPattern.toBSON().isEmpty());
- _keyPattern = keyPattern;
-}
-
-bool ShardCollectionType::getRefreshing() const {
- invariant(_refreshing);
- return _refreshing.get();
-}
-const ChunkVersion& ShardCollectionType::getLastRefreshedCollectionVersion() const {
- invariant(_lastRefreshedCollectionVersion);
- return _lastRefreshedCollectionVersion.get();
+ return obj;
}
} // namespace mongo
diff --git a/src/mongo/s/catalog/type_shard_collection.h b/src/mongo/s/catalog/type_shard_collection.h
index 42d54052f07..95ec62e7775 100644
--- a/src/mongo/s/catalog/type_shard_collection.h
+++ b/src/mongo/s/catalog/type_shard_collection.h
@@ -29,158 +29,58 @@
#pragma once
-#include <boost/optional.hpp>
-#include <string>
-
-#include "mongo/db/jsobj.h"
-#include "mongo/db/keypattern.h"
-#include "mongo/db/namespace_string.h"
-#include "mongo/s/chunk_version.h"
-#include "mongo/util/uuid.h"
+#include "mongo/s/catalog/type_shard_collection_gen.h"
namespace mongo {
-class CollectionType;
-class Status;
-template <typename T>
-class StatusWith;
-
-/**
- * This class represents the layout and contents of documents contained in the shard server's
- * config.collections collection. All manipulation of documents coming from that collection should
- * be done with this class.
- *
- * Expected shard server config.collections collection format:
- * {
- * "_id" : "foo.bar",
- * "uuid" : UUID, // optional in 3.6
- * "epoch" : ObjectId("58b6fd76132358839e409e47"), // will remove when UUID becomes available
- * "key" : {
- * "_id" : 1
- * },
- * "defaultCollation" : {
- * "locale" : "fr_CA"
- * },
- * "unique" : false,
- * "refreshing" : true, // optional
- * "lastRefreshedCollectionVersion" : Timestamp(1, 0), // optional
- * "enterCriticalSectionCounter" : 4 // optional
- * }
- *
- * enterCriticalSectionCounter is currently just an OpObserver signal, thus otherwise ignored here.
- */
-class ShardCollectionType {
+class ShardCollectionType : private ShardCollectionTypeBase {
public:
- static const BSONField<std::string> ns; // "_id"
- static const BSONField<UUID> uuid;
- static const BSONField<OID> epoch;
- static const BSONField<BSONObj> keyPattern;
- static const BSONField<BSONObj> defaultCollation;
- static const BSONField<bool> unique;
- static const BSONField<bool> refreshing;
- static const BSONField<Date_t> lastRefreshedCollectionVersion;
- static const BSONField<int> enterCriticalSectionCounter;
-
- ShardCollectionType(NamespaceString nss,
- boost::optional<UUID> uuid,
- OID epoch,
- const KeyPattern& keyPattern,
- const BSONObj& defaultCollation,
- bool unique);
-
- /**
- * Constructs a new ShardCollectionType object from BSON. Also does validation of the contents.
- */
- static StatusWith<ShardCollectionType> fromBSON(const BSONObj& source);
-
- /**
- * Returns the BSON representation of this shard collection type object.
- */
- BSONObj toBSON() const;
-
- /**
- * Returns a std::string representation of the current internal state.
- */
- std::string toString() const;
-
- const NamespaceString& getNss() const {
- return _nss;
+ // Make field names accessible.
+ using ShardCollectionTypeBase::kDefaultCollationFieldName;
+ using ShardCollectionTypeBase::kEnterCriticalSectionCounterFieldName;
+ using ShardCollectionTypeBase::kEpochFieldName;
+ using ShardCollectionTypeBase::kKeyPatternFieldName;
+ using ShardCollectionTypeBase::kLastRefreshedCollectionVersionFieldName;
+ using ShardCollectionTypeBase::kNssFieldName;
+ using ShardCollectionTypeBase::kRefreshingFieldName;
+ using ShardCollectionTypeBase::kUniqueFieldName;
+ using ShardCollectionTypeBase::kUuidFieldName;
+
+ // Make getters and setters accessible.
+ using ShardCollectionTypeBase::getNss;
+ using ShardCollectionTypeBase::setNss;
+ using ShardCollectionTypeBase::getUuid;
+ using ShardCollectionTypeBase::setUuid;
+ using ShardCollectionTypeBase::getEpoch;
+ using ShardCollectionTypeBase::setEpoch;
+ using ShardCollectionTypeBase::getKeyPattern;
+ using ShardCollectionTypeBase::setKeyPattern;
+ using ShardCollectionTypeBase::getDefaultCollation;
+ using ShardCollectionTypeBase::setDefaultCollation;
+ using ShardCollectionTypeBase::getUnique;
+ using ShardCollectionTypeBase::setUnique;
+ using ShardCollectionTypeBase::getRefreshing;
+ using ShardCollectionTypeBase::setRefreshing;
+ using ShardCollectionTypeBase::getLastRefreshedCollectionVersion;
+ using ShardCollectionTypeBase::setLastRefreshedCollectionVersion;
+ using ShardCollectionTypeBase::getEnterCriticalSectionCounter;
+ using ShardCollectionTypeBase::setEnterCriticalSectionCounter;
+
+ ShardCollectionType() : ShardCollectionTypeBase() {}
+
+ ShardCollectionType(NamespaceString nss, OID epoch, KeyPattern keyPattern, bool unique)
+ : ShardCollectionTypeBase(std::move(nss), std::move(epoch), std::move(keyPattern), unique) {
}
- void setNss(NamespaceString nss);
- const boost::optional<UUID> getUUID() const {
- return _uuid;
- }
- void setUUID(UUID uuid);
+ explicit ShardCollectionType(const BSONObj& obj);
- const OID& getEpoch() const {
- return _epoch;
- }
- void setEpoch(OID epoch);
+ // A wrapper around the IDL generated 'ShardCollectionTypeBase::parse' to ensure backwards
+ // compatibility.
+ static StatusWith<ShardCollectionType> fromBSON(const BSONObj& obj);
- const KeyPattern& getKeyPattern() const {
- return _keyPattern;
- }
- void setKeyPattern(const KeyPattern& keyPattern);
-
- const BSONObj& getDefaultCollation() const {
- return _defaultCollation;
- }
- void setDefaultCollation(const BSONObj& collation) {
- _defaultCollation = collation.getOwned();
- }
-
- bool getUnique() const {
- return _unique;
- }
- void setUnique(bool unique) {
- _unique = unique;
- }
-
- bool hasRefreshing() const {
- return _refreshing.is_initialized();
- }
- bool getRefreshing() const;
- void setRefreshing(bool refreshing) {
- _refreshing = refreshing;
- }
-
- bool hasLastRefreshedCollectionVersion() const {
- return _lastRefreshedCollectionVersion.is_initialized();
- }
- const ChunkVersion& getLastRefreshedCollectionVersion() const;
- void setLastRefreshedCollectionVersion(const ChunkVersion& version) {
- _lastRefreshedCollectionVersion = version;
- }
-
-private:
- // The full namespace (with the database prefix).
- NamespaceString _nss;
-
- // The UUID of the collection, if known.
- boost::optional<UUID> _uuid;
-
- // Uniquely identifies this instance of the collection, in case of drop/create.
- OID _epoch;
-
- // Sharding key. If collection is dropped, this is no longer required.
- KeyPattern _keyPattern;
-
- // Optional collection default collation. If empty, implies simple collation.
- BSONObj _defaultCollation;
-
- // Uniqueness of the sharding key.
- bool _unique;
-
- // Refresh fields set by primaries and used by shard secondaries to safely refresh chunk
- // metadata. '_refreshing' indicates whether the chunks collection is currently being updated,
- // which means read results won't provide a complete view of the chunk metadata.
- // '_lastRefreshedCollectionVersion' indicates the collection version of the last complete chunk
- // metadata refresh, and is used to indicate a refresh occurred if the value is different than
- // when the caller last checked -- because 'refreshing' will be false both before and after a
- // refresh occurs.
- boost::optional<bool> _refreshing{boost::none};
- boost::optional<ChunkVersion> _lastRefreshedCollectionVersion{boost::none};
+ // A wrapper around the IDL generated 'ShardCollectionTypeBase::toBSON' to ensure backwards
+ // compatibility.
+ BSONObj toBSON() const;
};
} // namespace mongo
diff --git a/src/mongo/s/catalog/type_shard_collection.idl b/src/mongo/s/catalog/type_shard_collection.idl
new file mode 100644
index 00000000000..fadbebe7d4d
--- /dev/null
+++ b/src/mongo/s/catalog/type_shard_collection.idl
@@ -0,0 +1,113 @@
+# Copyright (C) 2019-present MongoDB, Inc.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the Server Side Public License, version 1,
+# as published by MongoDB, Inc.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# Server Side Public License for more details.
+#
+# You should have received a copy of the Server Side Public License
+# along with this program. If not, see
+# <http://www.mongodb.com/licensing/server-side-public-license>.
+#
+# As a special exception, the copyright holders give permission to link the
+# code of portions of this program with the OpenSSL library under certain
+# conditions as described in each individual source file and distribute
+# linked combinations including the program with the OpenSSL library. You
+# must comply with the Server Side Public License in all respects for
+# all of the code used other than as permitted herein. If you modify file(s)
+# with this exception, you may extend this exception to your version of the
+# file(s), but you are not obligated to do so. If you do not wish to do so,
+# delete this exception statement from your version. If you delete this
+# exception statement from all source files in the program, then also delete
+# it in the license file.
+#
+
+# ShardCollectionType type
+#
+# This type represents the layout and contents of documents contained in the shard server's
+# config.collections collection. All manipulation of documents coming from that collection should
+# be done with this class.
+#
+# Expected shard server config.collections collection format:
+# {
+# "_id" : "foo.bar",
+# "uuid" : UUID, // optional in 3.6
+# "epoch" : ObjectId("58b6fd76132358839e409e47"), // will remove when UUID becomes available
+# "key" : {
+# "_id" : 1
+# },
+# "defaultCollation" : {
+# "locale" : "fr_CA"
+# },
+# "unique" : false,
+# "refreshing" : true, // optional
+# "lastRefreshedCollectionVersion" : Timestamp(1, 0), // optional
+# "enterCriticalSectionCounter" : 4 // optional
+# }
+#
+
+global:
+ cpp_namespace: "mongo"
+
+imports:
+ - "mongo/idl/basic_types.idl"
+ - "mongo/db/keypattern.idl"
+ - "mongo/s/chunk_version.idl"
+
+structs:
+ ShardCollectionTypeBase:
+ description: "Represents the layout and contents of documents contained in the shard
+ server's config.collections collection."
+ fields:
+ _id:
+ cpp_name: nss
+ type: namespacestring
+ description: "The full namespace (with the database prefix)."
+ optional: false
+ uuid:
+ type: uuid
+ description: "The UUID of the collection, if known."
+ optional: true
+ epoch:
+ type: objectid
+ description: "Uniquely identifies this instance of the collection, in case of
+ drop/create."
+ optional: false
+ key:
+ cpp_name: keyPattern
+ type: KeyPattern
+ description: "Sharding key. If collection is dropped, this is no longer required."
+ optional: false
+ defaultCollation:
+ type: object_owned
+ default: BSONObj()
+ description: "Optional collection default collation. If empty, implies simple
+ collation."
+ optional: false
+ unique:
+ type: bool
+ description: "Uniqueness of the sharding key."
+ optional: false
+ refreshing:
+ type: bool
+ description: "Set by primaries and used by shard secondaries to safely refresh chunk
+ metadata. Indicates whether the chunks collection is current being
+ updated, which means read results won't provide a complete view of the
+ chunk metadata."
+ optional: true
+ lastRefreshedCollectionVersion:
+ type: ChunkVersionLegacy
+ description: "Set by primaries and used by shard secondaries to safely refresh chunk
+ metadata. Indicates the collection version of the last complete chunk
+ metadata refresh, and is used to indicate if a refresh occurred if the
+ value is different than when the caller last checked -- because
+ 'refreshing' will be false both before and after a refresh occurs."
+ optional: true
+ enterCriticalSectionCounter:
+ type: int
+ description: "Currently just an OpObserver signal, thus otherwise ignored."
+ optional: true
diff --git a/src/mongo/s/catalog/type_shard_collection_test.cpp b/src/mongo/s/catalog/type_shard_collection_test.cpp
index 85e3f5636cb..bde4643c186 100644
--- a/src/mongo/s/catalog/type_shard_collection_test.cpp
+++ b/src/mongo/s/catalog/type_shard_collection_test.cpp
@@ -29,11 +29,10 @@
#include "mongo/platform/basic.h"
+#include "mongo/db/s/shard_metadata_util.h"
#include "mongo/s/catalog/type_shard_collection.h"
-#include "mongo/base/status_with.h"
#include "mongo/bson/oid.h"
-#include "mongo/s/catalog/type_collection.h"
#include "mongo/unittest/unittest.h"
#include "mongo/util/time_support.h"
@@ -47,133 +46,63 @@ const BSONObj kKeyPattern = BSON("a" << 1);
const BSONObj kDefaultCollation = BSON("locale"
<< "fr_CA");
-TEST(ShardCollectionType, ToFromBSON) {
- const OID epoch = OID::gen();
- const UUID uuid = UUID::gen();
- const ChunkVersion lastRefreshedCollectionVersion(2, 0, epoch);
-
+TEST(ShardCollectionType, FromBSONEmptyShardKeyFails) {
BSONObjBuilder builder;
- builder.append(ShardCollectionType::ns.name(), kNss.ns());
- uuid.appendToBuilder(&builder, ShardCollectionType::uuid.name());
- builder.append(ShardCollectionType::epoch(), epoch);
- builder.append(ShardCollectionType::keyPattern.name(), kKeyPattern);
- builder.append(ShardCollectionType::defaultCollation(), kDefaultCollation);
- builder.append(ShardCollectionType::unique(), true);
- builder.append(ShardCollectionType::refreshing(), false);
- builder.appendTimestamp(ShardCollectionType::lastRefreshedCollectionVersion(),
- lastRefreshedCollectionVersion.toLong());
- BSONObj obj = builder.obj();
-
- ShardCollectionType shardCollectionType = assertGet(ShardCollectionType::fromBSON(obj));
-
- ASSERT_EQUALS(shardCollectionType.getNss(), kNss);
- ASSERT(shardCollectionType.getUUID());
- ASSERT_EQUALS(*shardCollectionType.getUUID(), uuid);
- ASSERT_EQUALS(shardCollectionType.getEpoch(), epoch);
- ASSERT_BSONOBJ_EQ(shardCollectionType.getKeyPattern().toBSON(), kKeyPattern);
- ASSERT_BSONOBJ_EQ(shardCollectionType.getDefaultCollation(), kDefaultCollation);
- ASSERT_EQUALS(shardCollectionType.getUnique(), true);
- ASSERT_EQUALS(shardCollectionType.getRefreshing(), false);
- ASSERT_EQUALS(shardCollectionType.getLastRefreshedCollectionVersion(),
- lastRefreshedCollectionVersion);
-
- ASSERT_BSONOBJ_EQ(obj, shardCollectionType.toBSON());
+ builder.append(ShardCollectionType::kNssFieldName, kNss.ns());
+ builder.append(ShardCollectionType::kEpochFieldName, OID::gen());
+ builder.append(ShardCollectionType::kKeyPatternFieldName, BSONObj());
+ builder.append(ShardCollectionType::kUniqueFieldName, true);
+
+ StatusWith<ShardCollectionType> status = ShardCollectionType::fromBSON(builder.obj());
+ ASSERT_EQ(status.getStatus().code(), ErrorCodes::ShardKeyNotFound);
}
-TEST(ShardCollectionType, ToFromShardBSONWithoutOptionals) {
- const OID epoch = OID::gen();
+TEST(ShardCollectionType, FromBSONEpochMatchesLastRefreshedCollectionVersionWhenBSONTimestamp) {
+ OID epoch = OID::gen();
BSONObjBuilder builder;
- builder.append(ShardCollectionType::ns.name(), kNss.ns());
- builder.append(ShardCollectionType::epoch(), epoch);
- builder.append(ShardCollectionType::keyPattern.name(), kKeyPattern);
- builder.append(ShardCollectionType::defaultCollation(), kDefaultCollation);
- builder.append(ShardCollectionType::unique(), true);
- BSONObj obj = builder.obj();
-
- ShardCollectionType shardCollectionType = assertGet(ShardCollectionType::fromBSON(obj));
-
- ASSERT_EQUALS(shardCollectionType.getNss(), kNss);
- ASSERT_EQUALS(shardCollectionType.getEpoch(), epoch);
- ASSERT_BSONOBJ_EQ(shardCollectionType.getKeyPattern().toBSON(), kKeyPattern);
- ASSERT_BSONOBJ_EQ(shardCollectionType.getDefaultCollation(), kDefaultCollation);
- ASSERT_EQUALS(shardCollectionType.getUnique(), true);
- ASSERT_FALSE(shardCollectionType.hasRefreshing());
- ASSERT_FALSE(shardCollectionType.hasLastRefreshedCollectionVersion());
-
- ASSERT_BSONOBJ_EQ(obj, shardCollectionType.toBSON());
-}
+ builder.append(ShardCollectionType::kNssFieldName, kNss.ns());
+ builder.append(ShardCollectionType::kEpochFieldName, epoch);
+ builder.append(ShardCollectionType::kKeyPatternFieldName, kKeyPattern);
+ builder.append(ShardCollectionType::kUniqueFieldName, true);
+ builder.append(ShardCollectionType::kLastRefreshedCollectionVersionFieldName, Timestamp());
-TEST(ShardCollectionType, FromEmptyBSON) {
- StatusWith<ShardCollectionType> status = ShardCollectionType::fromBSON(BSONObj());
- ASSERT_FALSE(status.isOK());
-}
+ ShardCollectionType shardCollType = assertGet(ShardCollectionType::fromBSON(builder.obj()));
-TEST(ShardCollectionType, FromBSONNoUUIDIsOK) {
- BSONObjBuilder builder;
- builder.append(ShardCollectionType::ns.name(), kNss.ns());
- builder.append(ShardCollectionType::epoch(), OID::gen());
- builder.append(ShardCollectionType::keyPattern(), kKeyPattern);
- builder.append(ShardCollectionType::unique(), true);
- StatusWith<ShardCollectionType> status = ShardCollectionType::fromBSON(builder.obj());
- ASSERT_OK(status.getStatus());
- ASSERT_FALSE(status.getValue().getUUID());
+ ASSERT_EQ(epoch, shardCollType.getLastRefreshedCollectionVersion()->epoch());
}
-TEST(ShardCollectionType, FromBSONNoNSFails) {
- BSONObjBuilder builder;
- UUID::gen().appendToBuilder(&builder, ShardCollectionType::uuid.name());
- builder.append(ShardCollectionType::epoch(), OID::gen());
- builder.append(ShardCollectionType::keyPattern(), kKeyPattern);
- builder.append(ShardCollectionType::unique(), true);
- StatusWith<ShardCollectionType> status = ShardCollectionType::fromBSON(builder.obj());
- ASSERT_EQUALS(status.getStatus().code(), ErrorCodes::NoSuchKey);
- ASSERT_STRING_CONTAINS(status.getStatus().reason(), ShardCollectionType::ns());
-}
+TEST(ShardCollectionType, FromBSONEpochMatchesLastRefreshedCollectionVersionWhenDate) {
+ OID epoch = OID::gen();
-TEST(ShardCollectionType, FromBSONNoEpochFails) {
BSONObjBuilder builder;
- builder.append(ShardCollectionType::ns.name(), kNss.ns());
- UUID::gen().appendToBuilder(&builder, ShardCollectionType::uuid.name());
- builder.append(ShardCollectionType::keyPattern(), kKeyPattern);
- builder.append(ShardCollectionType::unique(), true);
- StatusWith<ShardCollectionType> status = ShardCollectionType::fromBSON(builder.obj());
- ASSERT_EQUALS(status.getStatus().code(), ErrorCodes::NoSuchKey);
- ASSERT_STRING_CONTAINS(status.getStatus().reason(), ShardCollectionType::epoch());
-}
+ builder.append(ShardCollectionType::kNssFieldName, kNss.ns());
+ builder.append(ShardCollectionType::kEpochFieldName, epoch);
+ builder.append(ShardCollectionType::kKeyPatternFieldName, kKeyPattern);
+ builder.append(ShardCollectionType::kUniqueFieldName, true);
+ builder.append(ShardCollectionType::kLastRefreshedCollectionVersionFieldName, Date_t());
-TEST(ShardCollectionType, FromBSONNoShardKeyFails) {
- BSONObjBuilder builder;
- builder.append(ShardCollectionType::ns.name(), kNss.ns());
- UUID::gen().appendToBuilder(&builder, ShardCollectionType::uuid.name());
- builder.append(ShardCollectionType::epoch(), OID::gen());
- builder.append(ShardCollectionType::unique(), true);
- StatusWith<ShardCollectionType> status = ShardCollectionType::fromBSON(builder.obj());
- ASSERT_EQUALS(status.getStatus().code(), ErrorCodes::NoSuchKey);
- ASSERT_STRING_CONTAINS(status.getStatus().reason(), ShardCollectionType::keyPattern());
-}
+ ShardCollectionType shardCollType = assertGet(ShardCollectionType::fromBSON(builder.obj()));
-TEST(ShardCollectionType, FromBSONNoUniqueFails) {
- BSONObjBuilder builder;
- builder.append(ShardCollectionType::ns.name(), kNss.ns());
- UUID::gen().appendToBuilder(&builder, ShardCollectionType::uuid.name());
- builder.append(ShardCollectionType::epoch(), OID::gen());
- builder.append(ShardCollectionType::keyPattern.name(), kKeyPattern);
- builder.append(ShardCollectionType::defaultCollation(), kDefaultCollation);
- StatusWith<ShardCollectionType> status = ShardCollectionType::fromBSON(builder.obj());
- ASSERT_EQUALS(status.getStatus().code(), ErrorCodes::NoSuchKey);
- ASSERT_STRING_CONTAINS(status.getStatus().reason(), ShardCollectionType::unique());
+ ASSERT_EQ(epoch, shardCollType.getLastRefreshedCollectionVersion()->epoch());
}
-TEST(ShardCollectionType, FromBSONNoDefaultCollationIsOK) {
- BSONObjBuilder builder;
- builder.append(ShardCollectionType::ns.name(), kNss.ns());
- UUID::gen().appendToBuilder(&builder, ShardCollectionType::uuid.name());
- builder.append(ShardCollectionType::epoch(), OID::gen());
- builder.append(ShardCollectionType::keyPattern.name(), kKeyPattern);
- builder.append(ShardCollectionType::unique(), true);
+TEST(ShardCollectionType, ToBSONEmptyDefaultCollationNotIncluded) {
+ ShardCollectionType shardCollType;
+ shardCollType.setNss(kNss);
+ shardCollType.setEpoch(OID::gen());
+ shardCollType.setKeyPattern(kKeyPattern);
+ shardCollType.setUnique(true);
+
+ shardCollType.setDefaultCollation(BSONObj());
+ BSONObj obj = shardCollType.toBSON();
+
+ ASSERT_FALSE(obj.hasField(ShardCollectionType::kDefaultCollationFieldName));
+
+ shardCollType.setDefaultCollation(kDefaultCollation);
+ obj = shardCollType.toBSON();
- assertGet(ShardCollectionType::fromBSON(builder.obj()));
+ ASSERT_TRUE(obj.hasField(ShardCollectionType::kDefaultCollationFieldName));
}
} // namespace
diff --git a/src/mongo/s/chunk_version.cpp b/src/mongo/s/chunk_version.cpp
index 62edcdb6404..3f25d474a4a 100644
--- a/src/mongo/s/chunk_version.cpp
+++ b/src/mongo/s/chunk_version.cpp
@@ -131,6 +131,10 @@ BSONObj ChunkVersion::toBSON() const {
return b.arr();
}
+void ChunkVersion::legacyToBSON(StringData field, BSONObjBuilder* out) const {
+ out->appendTimestamp(field, this->toLong());
+}
+
std::string ChunkVersion::toString() const {
return str::stream() << majorVersion() << "|" << minorVersion() << "||" << _epoch;
}
diff --git a/src/mongo/s/chunk_version.h b/src/mongo/s/chunk_version.h
index a0d7f09c1db..a77272d8f03 100644
--- a/src/mongo/s/chunk_version.h
+++ b/src/mongo/s/chunk_version.h
@@ -86,6 +86,16 @@ public:
}
/**
+ * NOTE: This format should not be used. Use fromBSONThrowing instead.
+ *
+ * A throwing version of 'parseLegacyWithField' to resolve a compatibility issue with the
+ * ShardCollectionType IDL type.
+ */
+ static ChunkVersion legacyFromBSONThrowing(const BSONElement& element) {
+ return uassertStatusOK(parseLegacyWithField(element.wrap(), element.fieldNameStringData()));
+ }
+
+ /**
* NOTE: This format is being phased out. Use parseWithField instead.
*
* Parses the BSON formatted by appendLegacyWithField. If the field is missing, returns
@@ -218,6 +228,12 @@ public:
void appendLegacyWithField(BSONObjBuilder* out, StringData field) const;
BSONObj toBSON() const;
+
+ /**
+ * NOTE: This format serializes chunk version as a timestamp (without the epoch) for
+ * legacy reasons.
+ */
+ void legacyToBSON(StringData field, BSONObjBuilder* builder) const;
std::string toString() const;
private:
diff --git a/src/mongo/s/chunk_version.idl b/src/mongo/s/chunk_version.idl
index 887767855ae..ee33893468b 100644
--- a/src/mongo/s/chunk_version.idl
+++ b/src/mongo/s/chunk_version.idl
@@ -40,3 +40,11 @@ types:
cpp_type: ChunkVersion
serializer: ChunkVersion::toBSON
deserializer: ChunkVersion::fromBSONThrowing
+
+ ChunkVersionLegacy:
+ bson_serialization_type: any
+ description: An object representing a chunk version for a collection. Ignores the epoch
+ component in the chunk version for legacy reasons.
+ cpp_type: ChunkVersion
+ serializer: ChunkVersion::legacyToBSON
+ deserializer: ChunkVersion::legacyFromBSONThrowing
diff --git a/src/mongo/s/shard_key_pattern_test.cpp b/src/mongo/s/shard_key_pattern_test.cpp
index 15a38fcee11..808ccfbe419 100644
--- a/src/mongo/s/shard_key_pattern_test.cpp
+++ b/src/mongo/s/shard_key_pattern_test.cpp
@@ -48,7 +48,7 @@ TEST(ShardKeyPattern, SingleFieldShardKeyPatternsValidityCheck) {
ShardKeyPattern(BSON("a"
<< "hashed"));
- ASSERT_THROWS(ShardKeyPattern({}), DBException);
+ ASSERT_THROWS(ShardKeyPattern(BSONObj()), DBException);
ASSERT_THROWS(ShardKeyPattern(BSON("a" << -1)), DBException);
ASSERT_THROWS(ShardKeyPattern(BSON("a" << -1.0)), DBException);
ASSERT_THROWS(ShardKeyPattern(BSON("a"
diff --git a/src/mongo/util/uuid.h b/src/mongo/util/uuid.h
index 69e72d479fe..2553e6383f2 100644
--- a/src/mongo/util/uuid.h
+++ b/src/mongo/util/uuid.h
@@ -78,6 +78,7 @@ class UUID {
friend class repl::OplogEntryBase;
friend class repl::DurableReplOperation;
friend class ResumeTokenInternal;
+ friend class ShardCollectionTypeBase;
friend class VoteCommitIndexBuild;
public: