summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMarcos José Grillo Ramírez <marcos.grillo@mongodb.com>2020-08-11 13:05:23 +0200
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2020-08-12 18:50:50 +0000
commit741bbb63dc64f3ed4bc65883f5fd05fabbea6409 (patch)
tree29ffa48e4812d7baf388c8fdc90287b816f486ad /src
parent3813db066fdfc4a7ace1047aee8bc286caf0b443 (diff)
downloadmongo-741bbb63dc64f3ed4bc65883f5fd05fabbea6409.tar.gz
SERVER-48990 Added comparable chunk version as a prerequisite to implement a causally consistent collection cache
Diffstat (limited to 'src')
-rw-r--r--src/mongo/s/SConscript1
-rw-r--r--src/mongo/s/catalog_cache.cpp26
-rw-r--r--src/mongo/s/catalog_cache.h79
-rw-r--r--src/mongo/s/comparable_chunk_version_test.cpp109
4 files changed, 214 insertions, 1 deletions
diff --git a/src/mongo/s/SConscript b/src/mongo/s/SConscript
index 771a567dc7b..ef829350aeb 100644
--- a/src/mongo/s/SConscript
+++ b/src/mongo/s/SConscript
@@ -570,6 +570,7 @@ env.CppUnitTest(
'build_versioned_requests_for_targeted_shards_test.cpp',
'catalog_cache_test.cpp',
'catalog_cache_refresh_test.cpp',
+ 'comparable_chunk_version_test.cpp',
'comparable_database_version_test.cpp',
'catalog/type_changelog_test.cpp',
'catalog/type_chunk_test.cpp',
diff --git a/src/mongo/s/catalog_cache.cpp b/src/mongo/s/catalog_cache.cpp
index 0d0c0bdbad4..6ed5ed4ce90 100644
--- a/src/mongo/s/catalog_cache.cpp
+++ b/src/mongo/s/catalog_cache.cpp
@@ -861,6 +861,32 @@ DatabaseVersion CachedDatabaseInfo::databaseVersion() const {
return _dbt.getVersion();
}
+AtomicWord<uint64_t> ComparableChunkVersion::_localSequenceNumSource{1ULL};
+
+ComparableChunkVersion ComparableChunkVersion::makeComparableChunkVersion(
+ const ChunkVersion& version) {
+ return ComparableChunkVersion(version, _localSequenceNumSource.fetchAndAdd(1));
+}
+
+const ChunkVersion& ComparableChunkVersion::getVersion() const {
+ return _chunkVersion;
+}
+
+uint64_t ComparableChunkVersion::getLocalSequenceNum() const {
+ return _localSequenceNum;
+}
+
+BSONObj ComparableChunkVersion::toBSON() const {
+ BSONObjBuilder builder;
+ _chunkVersion.appendToCommand(&builder);
+ builder.append("localSequenceNum", std::to_string(_localSequenceNum));
+ return builder.obj();
+}
+
+std::string ComparableChunkVersion::toString() const {
+ return toBSON().toString();
+}
+
CachedCollectionRoutingInfo::CachedCollectionRoutingInfo(NamespaceString nss,
CachedDatabaseInfo db,
std::shared_ptr<ChunkManager> cm)
diff --git a/src/mongo/s/catalog_cache.h b/src/mongo/s/catalog_cache.h
index b699cb0d5ac..3a98d31826d 100644
--- a/src/mongo/s/catalog_cache.h
+++ b/src/mongo/s/catalog_cache.h
@@ -37,6 +37,7 @@
#include "mongo/s/catalog/type_database.h"
#include "mongo/s/catalog_cache_loader.h"
#include "mongo/s/chunk_manager.h"
+#include "mongo/s/chunk_version.h"
#include "mongo/s/client/shard.h"
#include "mongo/s/database_version_gen.h"
#include "mongo/util/concurrency/notification.h"
@@ -144,7 +145,83 @@ private:
DatabaseVersion _dbVersion;
// Locally incremented sequence number that allows to compare two database versions with
- // different UUIDs. Each new comparableDatabaseVersion will have a grater sequence number then
+ // different UUIDs. Each new comparableDatabaseVersion will have a greater sequence number then
+ // the ones created before.
+ uint64_t _localSequenceNum{0};
+};
+
+/**
+ * Constructed to be used exclusively by the CatalogCache as a vector clock (Time) to drive
+ * CollectionCache's lookups.
+ *
+ * The ChunkVersion class contains an non comparable epoch, which makes impossible to compare two
+ * ChunkVersions when their epochs's differ.
+ *
+ * This class wraps a ChunkVersion object with a node-local sequence number (_localSequenceNum) that
+ * allows the comparision.
+ *
+ * This class should go away once a cluster-wide comparable ChunkVersion is implemented.
+ */
+class ComparableChunkVersion {
+public:
+ static ComparableChunkVersion makeComparableChunkVersion(const ChunkVersion& version);
+
+ ComparableChunkVersion() = default;
+
+ const ChunkVersion& getVersion() const;
+
+ uint64_t getLocalSequenceNum() const;
+
+ BSONObj toBSON() const;
+
+ std::string toString() const;
+
+ bool sameEpoch(const ComparableChunkVersion& other) const {
+ return _chunkVersion.epoch() == other._chunkVersion.epoch();
+ }
+
+ bool operator==(const ComparableChunkVersion& other) const {
+ return sameEpoch(other) &&
+ (_chunkVersion.majorVersion() == other._chunkVersion.majorVersion() &&
+ _chunkVersion.minorVersion() == other._chunkVersion.minorVersion());
+ }
+
+ bool operator!=(const ComparableChunkVersion& other) const {
+ return !(*this == other);
+ }
+
+ bool operator<(const ComparableChunkVersion& other) const {
+ if (sameEpoch(other)) {
+ return _chunkVersion.majorVersion() < other._chunkVersion.majorVersion() ||
+ (_chunkVersion.majorVersion() == other._chunkVersion.majorVersion() &&
+ _chunkVersion.minorVersion() < other._chunkVersion.minorVersion());
+ } else {
+ return _localSequenceNum < other._localSequenceNum;
+ }
+ }
+
+ bool operator>(const ComparableChunkVersion& other) const {
+ return other < *this;
+ }
+
+ bool operator<=(const ComparableChunkVersion& other) const {
+ return !(*this > other);
+ }
+
+ bool operator>=(const ComparableChunkVersion& other) const {
+ return !(*this < other);
+ }
+
+private:
+ static AtomicWord<uint64_t> _localSequenceNumSource;
+
+ ComparableChunkVersion(const ChunkVersion& version, uint64_t localSequenceNum)
+ : _chunkVersion(version), _localSequenceNum(localSequenceNum) {}
+
+ ChunkVersion _chunkVersion;
+
+ // Locally incremented sequence number that allows to compare two colection versions with
+ // different epochs. Each new comparableChunkVersion will have a greater sequence number than
// the ones created before.
uint64_t _localSequenceNum{0};
};
diff --git a/src/mongo/s/comparable_chunk_version_test.cpp b/src/mongo/s/comparable_chunk_version_test.cpp
new file mode 100644
index 00000000000..941d9bad080
--- /dev/null
+++ b/src/mongo/s/comparable_chunk_version_test.cpp
@@ -0,0 +1,109 @@
+/**
+ * Copyright (C) 2020-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.
+ */
+
+#include "mongo/platform/basic.h"
+
+#include "mongo/s/catalog_cache.h"
+#include "mongo/s/chunk_version.h"
+#include "mongo/unittest/unittest.h"
+
+namespace mongo {
+namespace {
+
+TEST(ComparableChunkVersionTest, VersionsEqual) {
+ auto epoch = OID::gen();
+ const auto version1 =
+ ComparableChunkVersion::makeComparableChunkVersion(ChunkVersion(1, 0, epoch));
+ const auto version2 =
+ ComparableChunkVersion::makeComparableChunkVersion(ChunkVersion(1, 0, epoch));
+ ASSERT(version1.getVersion() == version2.getVersion());
+ ASSERT(version1 == version2);
+}
+
+TEST(ComparableChunkVersionTest, VersionsEqualAfterCopy) {
+ ChunkVersion chunkVersion(1, 0, OID::gen());
+ const auto version1 = ComparableChunkVersion::makeComparableChunkVersion(chunkVersion);
+ const auto version2 = version1;
+ ASSERT(version1 == version2);
+}
+
+TEST(ComparableChunkVersionTest, CompareVersionDifferentEpochs) {
+ const auto version1 =
+ ComparableChunkVersion::makeComparableChunkVersion(ChunkVersion(2, 0, OID::gen()));
+ const auto version2 =
+ ComparableChunkVersion::makeComparableChunkVersion(ChunkVersion(1, 0, OID::gen()));
+ ASSERT(version2 != version1);
+ ASSERT(version2 > version1);
+ ASSERT_FALSE(version2 < version1);
+}
+
+TEST(ComparableChunkVersionTest, VersionGreaterSameEpochs) {
+ const auto epoch = OID::gen();
+ const auto version1 =
+ ComparableChunkVersion::makeComparableChunkVersion(ChunkVersion(1, 0, epoch));
+ const auto version2 =
+ ComparableChunkVersion::makeComparableChunkVersion(ChunkVersion(1, 1, epoch));
+ const auto version3 =
+ ComparableChunkVersion::makeComparableChunkVersion(ChunkVersion(2, 0, epoch));
+ ASSERT(version2 != version1);
+ ASSERT(version2 > version1);
+ ASSERT_FALSE(version2 < version1);
+ ASSERT(version3 != version2);
+ ASSERT(version3 > version2);
+ ASSERT_FALSE(version3 < version2);
+}
+
+TEST(ComparableChunkVersionTest, VersionLessSameEpoch) {
+ const auto epoch = OID::gen();
+ const auto version1 =
+ ComparableChunkVersion::makeComparableChunkVersion(ChunkVersion(1, 0, epoch));
+ const auto version2 =
+ ComparableChunkVersion::makeComparableChunkVersion(ChunkVersion(1, 1, epoch));
+ const auto version3 =
+ ComparableChunkVersion::makeComparableChunkVersion(ChunkVersion(2, 0, epoch));
+ ASSERT(version1 != version2);
+ ASSERT(version1 < version2);
+ ASSERT_FALSE(version1 > version2);
+ ASSERT(version3 != version2);
+ ASSERT(version2 < version3);
+ ASSERT_FALSE(version2 > version3);
+}
+
+TEST(ComparableChunkVersionTest, DefaultConstructedVersionIsAlwaysLess) {
+ const ComparableChunkVersion defaultVersion{};
+ ASSERT_EQ(defaultVersion.getLocalSequenceNum(), 0);
+ const auto version1 =
+ ComparableChunkVersion::makeComparableChunkVersion(ChunkVersion(0, 0, OID::gen()));
+ ASSERT(defaultVersion != version1);
+ ASSERT(defaultVersion < version1);
+ ASSERT_FALSE(defaultVersion > version1);
+}
+
+} // namespace
+} // namespace mongo