summaryrefslogtreecommitdiff
path: root/src/mongo/s
diff options
context:
space:
mode:
authorKaloian Manassiev <kaloian.manassiev@mongodb.com>2015-10-29 13:04:59 -0400
committerKaloian Manassiev <kaloian.manassiev@mongodb.com>2015-10-30 11:46:36 -0400
commit81abe6a2a36c1bbc77463e4c85d8734c9830de98 (patch)
tree867adeff1662c809c4557c95361fd16d787ccda5 /src/mongo/s
parentfe73340de3865df04fe6be19c3291ad2dcd9ec18 (diff)
downloadmongo-81abe6a2a36c1bbc77463e4c85d8734c9830de98.tar.gz
SERVER-21186 Fix chunk version handling in ChunkType
On read, the parsing code was preferring the old 'version' field, which is not being written since version 2.4 and on write it was writing both the old 'version' field and the somewhat newer 'lastmod'. Made it to only look for 'lastmod' and to never write 'version'.
Diffstat (limited to 'src/mongo/s')
-rw-r--r--src/mongo/s/catalog/replset/catalog_manager_replica_set_shard_collection_test.cpp15
-rw-r--r--src/mongo/s/catalog/replset/catalog_manager_replica_set_test.cpp4
-rw-r--r--src/mongo/s/catalog/type_chunk.cpp20
-rw-r--r--src/mongo/s/catalog/type_chunk.h1
-rw-r--r--src/mongo/s/catalog/type_chunk_test.cpp110
-rw-r--r--src/mongo/s/chunk_diff_test.cpp60
-rw-r--r--src/mongo/s/chunk_manager.cpp4
-rw-r--r--src/mongo/s/chunk_version.cpp7
-rw-r--r--src/mongo/s/chunk_version.h70
-rw-r--r--src/mongo/s/chunk_version_test.cpp74
-rw-r--r--src/mongo/s/commands/cluster_get_shard_version_cmd.cpp3
11 files changed, 122 insertions, 246 deletions
diff --git a/src/mongo/s/catalog/replset/catalog_manager_replica_set_shard_collection_test.cpp b/src/mongo/s/catalog/replset/catalog_manager_replica_set_shard_collection_test.cpp
index bcbb46f8c1f..8fafa6c5ada 100644
--- a/src/mongo/s/catalog/replset/catalog_manager_replica_set_shard_collection_test.cpp
+++ b/src/mongo/s/catalog/replset/catalog_manager_replica_set_shard_collection_test.cpp
@@ -364,12 +364,7 @@ TEST_F(ShardCollectionTest, noInitialChunksOrData) {
expectedChunk.setMin(keyPattern.getKeyPattern().globalMin());
expectedChunk.setMax(keyPattern.getKeyPattern().globalMax());
expectedChunk.setShard(shard.getName());
- {
- ChunkVersion expectedVersion;
- expectedVersion.incEpoch();
- expectedVersion.incMajor();
- expectedChunk.setVersion(expectedVersion);
- }
+ expectedChunk.setVersion(ChunkVersion(1, 0, OID::gen()));
distLock()->expectLock(
[&](StringData name,
@@ -498,9 +493,7 @@ TEST_F(ShardCollectionTest, withInitialChunks) {
BSONObj splitPoint2 = BSON("_id" << 200);
BSONObj splitPoint3 = BSON("_id" << 300);
- ChunkVersion expectedVersion;
- expectedVersion.incEpoch();
- expectedVersion.incMajor();
+ ChunkVersion expectedVersion(1, 0, OID::gen());
ChunkType expectedChunk0;
expectedChunk0.setNS(ns);
@@ -665,9 +658,7 @@ TEST_F(ShardCollectionTest, withInitialData) {
BSONObj splitPoint2 = BSON("_id" << 200);
BSONObj splitPoint3 = BSON("_id" << 300);
- ChunkVersion expectedVersion;
- expectedVersion.incEpoch();
- expectedVersion.incMajor();
+ ChunkVersion expectedVersion(1, 0, OID::gen());
ChunkType expectedChunk0;
expectedChunk0.setNS(ns);
diff --git a/src/mongo/s/catalog/replset/catalog_manager_replica_set_test.cpp b/src/mongo/s/catalog/replset/catalog_manager_replica_set_test.cpp
index c93bbbda17b..f784f25e6fc 100644
--- a/src/mongo/s/catalog/replset/catalog_manager_replica_set_test.cpp
+++ b/src/mongo/s/catalog/replset/catalog_manager_replica_set_test.cpp
@@ -480,7 +480,7 @@ TEST_F(CatalogManagerReplSetTest, GetChunksForNSWithSortAndLimit) {
ASSERT_OK(catalogManager()->getChunks(operationContext(),
chunksQuery,
- BSON(ChunkType::version() << -1),
+ BSON(ChunkType::DEPRECATED_lastmod() << -1),
1,
&chunks,
&opTime));
@@ -501,7 +501,7 @@ TEST_F(CatalogManagerReplSetTest, GetChunksForNSWithSortAndLimit) {
ASSERT_EQ(query->ns(), ChunkType::ConfigNS);
ASSERT_EQ(query->getFilter(), chunksQuery);
- ASSERT_EQ(query->getSort(), BSON(ChunkType::version() << -1));
+ ASSERT_EQ(query->getSort(), BSON(ChunkType::DEPRECATED_lastmod() << -1));
ASSERT_EQ(query->getLimit().get(), 1);
checkReadConcern(request.cmdObj, Timestamp(0, 0), repl::OpTime::kUninitializedTerm);
diff --git a/src/mongo/s/catalog/type_chunk.cpp b/src/mongo/s/catalog/type_chunk.cpp
index 68b9c016cae..f59bf0ea7a0 100644
--- a/src/mongo/s/catalog/type_chunk.cpp
+++ b/src/mongo/s/catalog/type_chunk.cpp
@@ -47,7 +47,6 @@ const BSONField<std::string> ChunkType::name("_id");
const BSONField<std::string> ChunkType::ns("ns");
const BSONField<BSONObj> ChunkType::min("min");
const BSONField<BSONObj> ChunkType::max("max");
-const BSONField<BSONArray> ChunkType::version("version");
const BSONField<std::string> ChunkType::shard("shard");
const BSONField<bool> ChunkType::jumbo("jumbo");
const BSONField<Date_t> ChunkType::DEPRECATED_lastmod("lastmod");
@@ -109,17 +108,12 @@ StatusWith<ChunkType> ChunkType::fromBSON(const BSONObj& source) {
}
}
- //
- // ChunkVersion backward compatibility logic contained in ChunkVersion
- //
-
- // ChunkVersion is currently encoded as { 'version': [<TS>,<OID>] }
-
- if (ChunkVersion::canParseBSON(source, version())) {
- chunk._version = ChunkVersion::fromBSON(source, version());
- } else if (ChunkVersion::canParseBSON(source, DEPRECATED_lastmod())) {
- chunk._version = ChunkVersion::fromBSON(source, DEPRECATED_lastmod());
+ // The format of chunk version encoding is { lastmod: <Major|Minor>, lastmodEpoch: OID }
+ if (!ChunkVersion::canParseBSON(source, DEPRECATED_lastmod())) {
+ return Status(ErrorCodes::BadValue,
+ str::stream() << "Unable to parse chunk version from " << source);
}
+ chunk._version = ChunkVersion::fromBSON(source, DEPRECATED_lastmod());
return chunk;
}
@@ -143,8 +137,7 @@ Status ChunkType::validate() const {
}
if (!_version.is_initialized() || !_version->isSet()) {
- return Status(ErrorCodes::NoSuchKey,
- str::stream() << "missing " << version.name() << " field");
+ return Status(ErrorCodes::NoSuchKey, str::stream() << "missing version field");
}
if (!_shard.is_initialized() || _shard->empty()) {
@@ -192,7 +185,6 @@ BSONObj ChunkType::toBSON() const {
builder.append(shard.name(), getShard());
if (_version) {
// For now, write both the deprecated *and* the new fields
- _version->addToBSON(builder, version());
_version->addToBSON(builder, DEPRECATED_lastmod());
}
if (_jumbo)
diff --git a/src/mongo/s/catalog/type_chunk.h b/src/mongo/s/catalog/type_chunk.h
index 52a452a20f2..739d652ce98 100644
--- a/src/mongo/s/catalog/type_chunk.h
+++ b/src/mongo/s/catalog/type_chunk.h
@@ -56,7 +56,6 @@ public:
static const BSONField<std::string> ns;
static const BSONField<BSONObj> min;
static const BSONField<BSONObj> max;
- static const BSONField<BSONArray> version;
static const BSONField<std::string> shard;
static const BSONField<bool> jumbo;
static const BSONField<Date_t> DEPRECATED_lastmod;
diff --git a/src/mongo/s/catalog/type_chunk_test.cpp b/src/mongo/s/catalog/type_chunk_test.cpp
index 5bfab7a31af..8806bafefac 100644
--- a/src/mongo/s/catalog/type_chunk_test.cpp
+++ b/src/mongo/s/catalog/type_chunk_test.cpp
@@ -42,115 +42,95 @@ using namespace mongo;
using std::string;
TEST(ChunkType, MissingRequiredFields) {
- ChunkType chunk;
- BSONArray version = BSON_ARRAY(Date_t::fromMillisSinceEpoch(1) << OID::gen());
+ ChunkVersion chunkVersion(1, 2, OID::gen());
BSONObj objModNS =
BSON(ChunkType::name("test.mycol-a_MinKey")
<< ChunkType::min(BSON("a" << 10 << "b" << 10)) << ChunkType::max(BSON("a" << 20))
- << ChunkType::version(version) << ChunkType::shard("shard0001"));
+ << "lastmod" << Timestamp(chunkVersion.toLong()) << "lastmodEpoch"
+ << chunkVersion.epoch() << ChunkType::shard("shard0001"));
StatusWith<ChunkType> chunkRes = ChunkType::fromBSON(objModNS);
ASSERT_FALSE(chunkRes.isOK());
BSONObj objModName =
- BSON(ChunkType::ns("test.mycol")
- << ChunkType::min(BSON("a" << 10 << "b" << 10)) << ChunkType::max(BSON("a" << 20))
- << ChunkType::version(version) << ChunkType::shard("shard0001"));
+ BSON(ChunkType::ns("test.mycol") << ChunkType::min(BSON("a" << 10 << "b" << 10))
+ << ChunkType::max(BSON("a" << 20)) << "lastmod"
+ << Timestamp(chunkVersion.toLong()) << "lastmodEpoch"
+ << chunkVersion.epoch() << ChunkType::shard("shard0001"));
chunkRes = ChunkType::fromBSON(objModName);
ASSERT_FALSE(chunkRes.isOK());
- BSONObj objModKeys = BSON(ChunkType::name("test.mycol-a_MinKey")
- << ChunkType::ns("test.mycol") << ChunkType::version(version)
- << ChunkType::shard("shard0001"));
+ BSONObj objModKeys =
+ BSON(ChunkType::name("test.mycol-a_MinKey")
+ << ChunkType::ns("test.mycol") << "lastmod" << Timestamp(chunkVersion.toLong())
+ << "lastmodEpoch" << chunkVersion.epoch() << ChunkType::shard("shard0001"));
chunkRes = ChunkType::fromBSON(objModKeys);
ASSERT_FALSE(chunkRes.isOK());
BSONObj objModShard =
BSON(ChunkType::name("test.mycol-a_MinKey")
<< ChunkType::ns("test.mycol") << ChunkType::min(BSON("a" << 10 << "b" << 10))
- << ChunkType::max(BSON("a" << 20)) << ChunkType::version(version));
+ << ChunkType::max(BSON("a" << 20)) << "lastmod" << Timestamp(chunkVersion.toLong())
+ << "lastmodEpoch" << chunkVersion.epoch());
chunkRes = ChunkType::fromBSON(objModShard);
ASSERT_FALSE(chunkRes.isOK());
}
-TEST(ChunkType, DifferentNumberOfColumns) {
- BSONArray version = BSON_ARRAY(Date_t::fromMillisSinceEpoch(1) << OID::gen());
+TEST(ChunkType, MinAndMaxShardKeysDifferInNumberOfKeys) {
+ ChunkVersion chunkVersion(1, 2, OID::gen());
BSONObj obj =
BSON(ChunkType::name("test.mycol-a_MinKey")
<< ChunkType::ns("test.mycol") << ChunkType::min(BSON("a" << 10 << "b" << 10))
- << ChunkType::max(BSON("a" << 20)) << ChunkType::version(version)
- << ChunkType::shard("shard0001"));
+ << ChunkType::max(BSON("a" << 20)) << "lastmod" << Timestamp(chunkVersion.toLong())
+ << "lastmodEpoch" << chunkVersion.epoch() << ChunkType::shard("shard0001"));
StatusWith<ChunkType> chunkRes = ChunkType::fromBSON(obj);
- ASSERT(chunkRes.isOK());
+ ASSERT_OK(chunkRes.getStatus());
ASSERT_FALSE(chunkRes.getValue().validate().isOK());
}
-TEST(ChunkType, DifferentColumns) {
- BSONArray version = BSON_ARRAY(Date_t::fromMillisSinceEpoch(1) << OID::gen());
- BSONObj obj = BSON(ChunkType::name("test.mycol-a_MinKey")
- << ChunkType::ns("test.mycol") << ChunkType::min(BSON("a" << 10))
- << ChunkType::max(BSON("b" << 20)) << ChunkType::version(version)
- << ChunkType::shard("shard0001"));
+TEST(ChunkType, MinAndMaxShardKeysDifferInKeyNames) {
+ ChunkVersion chunkVersion(1, 2, OID::gen());
+ BSONObj obj =
+ BSON(ChunkType::name("test.mycol-a_MinKey")
+ << ChunkType::ns("test.mycol") << ChunkType::min(BSON("a" << 10))
+ << ChunkType::max(BSON("b" << 20)) << "lastmod" << Timestamp(chunkVersion.toLong())
+ << "lastmodEpoch" << chunkVersion.epoch() << ChunkType::shard("shard0001"));
StatusWith<ChunkType> chunkRes = ChunkType::fromBSON(obj);
- ASSERT(chunkRes.isOK());
+ ASSERT_OK(chunkRes.getStatus());
ASSERT_FALSE(chunkRes.getValue().validate().isOK());
}
TEST(ChunkType, NotAscending) {
- BSONArray version = BSON_ARRAY(Date_t::fromMillisSinceEpoch(1) << OID::gen());
- BSONObj obj = BSON(ChunkType::name("test.mycol-a_MinKey")
- << ChunkType::ns("test.mycol") << ChunkType::min(BSON("a" << 20))
- << ChunkType::max(BSON("a" << 10)) << ChunkType::version(version)
- << ChunkType::shard("shard0001"));
+ ChunkVersion chunkVersion(1, 2, OID::gen());
+ BSONObj obj =
+ BSON(ChunkType::name("test.mycol-a_MinKey")
+ << ChunkType::ns("test.mycol") << ChunkType::min(BSON("a" << 20))
+ << ChunkType::max(BSON("a" << 10)) << "lastmod" << Timestamp(chunkVersion.toLong())
+ << "lastmodEpoch" << chunkVersion.epoch() << ChunkType::shard("shard0001"));
StatusWith<ChunkType> chunkRes = ChunkType::fromBSON(obj);
- ASSERT(chunkRes.isOK());
+ ASSERT_OK(chunkRes.getStatus());
ASSERT_FALSE(chunkRes.getValue().validate().isOK());
}
-TEST(ChunkType, NewFormatVersion) {
- ChunkType chunk;
- OID epoch = OID::gen();
- BSONArray version = BSON_ARRAY(Date_t::fromMillisSinceEpoch(1) << epoch);
- BSONObj obj = BSON(ChunkType::name("test.mycol-a_MinKey")
- << ChunkType::ns("test.mycol") << ChunkType::min(BSON("a" << 10))
- << ChunkType::max(BSON("a" << 20)) << ChunkType::version(version)
- << ChunkType::shard("shard0001"));
- StatusWith<ChunkType> chunkRes = ChunkType::fromBSON(obj);
- ASSERT(chunkRes.isOK());
- chunk = chunkRes.getValue();
-
- ASSERT_EQUALS(chunk.getName(), "test.mycol-a_MinKey");
- ASSERT_EQUALS(chunk.getNS(), "test.mycol");
- ASSERT_EQUALS(chunk.getMin(), BSON("a" << 10));
- ASSERT_EQUALS(chunk.getMax(), BSON("a" << 20));
- ChunkVersion fetchedVersion = chunk.getVersion();
- ASSERT_EQUALS(fetchedVersion.toLong(), 1ULL);
- ASSERT_EQUALS(fetchedVersion.epoch(), epoch);
- ASSERT_EQUALS(chunk.getShard(), "shard0001");
- ASSERT_TRUE(chunk.validate().isOK());
-}
-
-TEST(ChunkType, OldFormatVersion) {
- ChunkType chunk;
- OID epoch = OID::gen();
- BSONObj obj = BSON(ChunkType::name("test.mycol-a_MinKey")
- << ChunkType::ns("test.mycol") << ChunkType::min(BSON("a" << 10))
- << ChunkType::max(BSON("a" << 20))
- << ChunkType::DEPRECATED_lastmod(Date_t::fromMillisSinceEpoch(1))
- << ChunkType::DEPRECATED_epoch(epoch) << ChunkType::shard("shard0001"));
+TEST(ChunkType, CorrectContents) {
+ ChunkVersion chunkVersion(1, 2, OID::gen());
+ BSONObj obj =
+ BSON(ChunkType::name("test.mycol-a_MinKey")
+ << ChunkType::ns("test.mycol") << ChunkType::min(BSON("a" << 10))
+ << ChunkType::max(BSON("a" << 20)) << "lastmod" << Timestamp(chunkVersion.toLong())
+ << "lastmodEpoch" << chunkVersion.epoch() << ChunkType::shard("shard0001"));
StatusWith<ChunkType> chunkRes = ChunkType::fromBSON(obj);
- ASSERT(chunkRes.isOK());
- chunk = chunkRes.getValue();
+ ASSERT_OK(chunkRes.getStatus());
+ ChunkType chunk = chunkRes.getValue();
ASSERT_EQUALS(chunk.getName(), "test.mycol-a_MinKey");
ASSERT_EQUALS(chunk.getNS(), "test.mycol");
ASSERT_EQUALS(chunk.getMin(), BSON("a" << 10));
ASSERT_EQUALS(chunk.getMax(), BSON("a" << 20));
- ChunkVersion fetchedVersion = chunk.getVersion();
- ASSERT_EQUALS(fetchedVersion.toLong(), 1ULL);
- ASSERT_EQUALS(fetchedVersion.epoch(), epoch);
+ ASSERT_EQUALS(chunk.getVersion().toLong(), chunkVersion.toLong());
+ ASSERT_EQUALS(chunk.getVersion().epoch(), chunkVersion.epoch());
ASSERT_EQUALS(chunk.getShard(), "shard0001");
- ASSERT_TRUE(chunk.validate().isOK());
+ ASSERT_OK(chunk.validate());
}
TEST(ChunkType, BadType) {
diff --git a/src/mongo/s/chunk_diff_test.cpp b/src/mongo/s/chunk_diff_test.cpp
index 28dd7e63f1e..7c6bab7e94d 100644
--- a/src/mongo/s/chunk_diff_test.cpp
+++ b/src/mongo/s/chunk_diff_test.cpp
@@ -31,6 +31,7 @@
#include <string>
#include <map>
#include <utility>
+#include <vector>
#include "mongo/db/jsobj.h"
#include "mongo/db/operation_context_noop.h"
@@ -46,6 +47,7 @@ using std::string;
using std::pair;
using std::make_pair;
using std::map;
+using std::vector;
// Generates pseudorandom values
PseudoRandom rand(1);
@@ -91,10 +93,10 @@ public:
/**
* Converts array of raw BSONObj chunks to a vector of ChunkType.
*/
-void convertBSONArrayToChunkTypes(const BSONArray& chunksArray,
+void convertBSONArrayToChunkTypes(const vector<BSONObj>& chunksArray,
std::vector<ChunkType>* chunksVector) {
- for (const BSONElement& obj : chunksArray) {
- auto chunkTypeRes = ChunkType::fromBSON(obj.Obj());
+ for (const BSONObj& obj : chunksArray) {
+ auto chunkTypeRes = ChunkType::fromBSON(obj);
ASSERT(chunkTypeRes.isOK());
chunksVector->push_back(chunkTypeRes.getValue());
}
@@ -117,7 +119,7 @@ protected:
int maxChunks = 100000;
int keySize = 2;
- BSONArrayBuilder chunksB;
+ vector<BSONObj> chunksB;
BSONObj lastSplitPt;
ChunkVersion version(1, 0, OID());
@@ -153,13 +155,13 @@ protected:
rand(2) ? version.incMajor() : version.incMinor();
version.addToBSON(chunkB, ChunkType::DEPRECATED_lastmod());
- chunksB.append(chunkB.obj());
+ chunksB.push_back(chunkB.obj());
}
lastSplitPt = splitPt;
}
- BSONArray chunks = chunksB.arr();
+ vector<BSONObj> chunks(std::move(chunksB));
// Setup the empty ranges and versions first
RangeMap ranges;
@@ -186,12 +188,13 @@ protected:
int numChunks = numInitialChunks;
for (int i = 0; i < numDiffs; i++) {
- BSONArrayBuilder diffsB;
- BSONArrayBuilder newChunksB;
- BSONObjIterator chunksIt(chunks);
+ vector<BSONObj> newChunksB;
- while (chunksIt.more()) {
- BSONObj chunk = chunksIt.next().Obj();
+ vector<BSONObj>::iterator it = chunks.begin();
+
+ while (it != chunks.end()) {
+ BSONObj chunk = *it;
+ ++it;
int randChoice = rand(10);
@@ -250,25 +253,23 @@ protected:
BSONObj left = leftB.obj();
BSONObj right = rightB.obj();
- newChunksB.append(left);
- newChunksB.append(right);
-
- diffsB.append(right);
- diffsB.append(left);
+ newChunksB.push_back(left);
+ newChunksB.push_back(right);
numChunks++;
- } else if (randChoice < 4 && chunksIt.more()) {
+ } else if (randChoice < 4 && it != chunks.end()) {
// Simulate a migrate
BSONObj prevShardChunk;
- while (chunksIt.more()) {
- prevShardChunk = chunksIt.next().Obj();
+ while (it != chunks.end()) {
+ prevShardChunk = *it;
+ ++it;
if (prevShardChunk[ChunkType::shard()].String() ==
chunk[ChunkType::shard()].String()) {
break;
}
- newChunksB.append(prevShardChunk);
+ newChunksB.push_back(prevShardChunk);
prevShardChunk = BSONObj();
}
@@ -302,26 +303,20 @@ protected:
BSONObj newShard = newShardB.obj();
BSONObj prevShard = prevShardB.obj();
- newChunksB.append(newShard);
- newChunksB.append(prevShard);
-
- diffsB.append(newShard);
- diffsB.append(prevShard);
-
+ newChunksB.push_back(newShard);
+ newChunksB.push_back(prevShard);
} else {
- newChunksB.append(chunk);
+ newChunksB.push_back(chunk);
}
} else {
- newChunksB.append(chunk);
+ newChunksB.push_back(chunk);
}
}
- BSONArray diffs = diffsB.arr();
- chunks = newChunksB.arr();
+ chunks = std::move(newChunksB);
// Rarely entirely clear out our data
if (rand(10) < 1) {
- diffs = chunks;
ranges.clear();
maxVersion = ChunkVersion(0, 0, OID());
maxShardVersions.clear();
@@ -381,8 +376,7 @@ private:
0);
}
- ChunkVersion version =
- ChunkVersion::fromBSON(chunk.toBSON()[ChunkType::DEPRECATED_lastmod()]);
+ ChunkVersion version = chunk.getVersion();
if (version > foundMaxVersion)
foundMaxVersion = version;
diff --git a/src/mongo/s/chunk_manager.cpp b/src/mongo/s/chunk_manager.cpp
index 9dcc513eb32..e026e4f6738 100644
--- a/src/mongo/s/chunk_manager.cpp
+++ b/src/mongo/s/chunk_manager.cpp
@@ -410,9 +410,7 @@ void ChunkManager::createFirstChunks(OperationContext* txn,
// this is the first chunk; start the versioning from scratch
- ChunkVersion version;
- version.incEpoch();
- version.incMajor();
+ ChunkVersion version(1, 0, OID::gen());
log() << "going to create " << splitPoints.size() + 1 << " chunk(s) for: " << _ns
<< " using new epoch " << version.epoch();
diff --git a/src/mongo/s/chunk_version.cpp b/src/mongo/s/chunk_version.cpp
index 2006071760c..4f0e067357b 100644
--- a/src/mongo/s/chunk_version.cpp
+++ b/src/mongo/s/chunk_version.cpp
@@ -104,4 +104,11 @@ void ChunkVersion::appendForCommands(BSONObjBuilder* builder) const {
builder->appendArray(kShardVersion, toBSON());
}
+BSONObj ChunkVersion::toBSON() const {
+ BSONArrayBuilder b;
+ b.appendTimestamp(_combined);
+ b.append(_epoch);
+ return b.arr();
+}
+
} // namespace mongo
diff --git a/src/mongo/s/chunk_version.h b/src/mongo/s/chunk_version.h
index fc2f637be10..7aa8c4ee138 100644
--- a/src/mongo/s/chunk_version.h
+++ b/src/mongo/s/chunk_version.h
@@ -111,13 +111,6 @@ public:
_minor++;
}
- // Incrementing an epoch creates a new, randomly generated identifier
- void incEpoch() {
- _epoch = OID::gen();
- _major = 0;
- _minor = 0;
- }
-
// Note: this shouldn't be used as a substitute for version except in specific cases -
// epochs make versions more complex
unsigned long long toLong() const {
@@ -128,24 +121,14 @@ public:
return _combined > 0;
}
- bool isEpochSet() const {
- return _epoch.isSet();
- }
-
- std::string toString() const {
- std::stringstream ss;
- // Similar to month/day/year. For the most part when debugging, we care about major
- // so it's first
- ss << _major << "|" << _minor << "||" << _epoch;
- return ss.str();
- }
-
int majorVersion() const {
return _major;
}
+
int minorVersion() const {
return _minor;
}
+
OID epoch() const {
return _epoch;
}
@@ -237,17 +220,6 @@ public:
// { version : <TS> } and { version : [<TS>,<OID>] } format
//
- static bool canParseBSON(const BSONElement& el, const std::string& prefix = "") {
- bool canParse;
- fromBSON(el, prefix, &canParse);
- return canParse;
- }
-
- static ChunkVersion fromBSON(const BSONElement& el, const std::string& prefix = "") {
- bool canParse;
- return fromBSON(el, prefix, &canParse);
- }
-
static ChunkVersion fromBSON(const BSONElement& el, const std::string& prefix, bool* canParse) {
*canParse = true;
@@ -314,17 +286,6 @@ public:
// { version : [<TS>, <OID>] } format
//
- static bool canParseBSON(const BSONArray& arr) {
- bool canParse;
- fromBSON(arr, &canParse);
- return canParse;
- }
-
- static ChunkVersion fromBSON(const BSONArray& arr) {
- bool canParse;
- return fromBSON(arr, &canParse);
- }
-
static ChunkVersion fromBSON(const BSONArray& arr, bool* canParse) {
*canParse = false;
@@ -356,19 +317,16 @@ public:
// versions that know nothing about epochs.
//
- BSONObj toBSONWithPrefix(const std::string& prefixIn) const {
- BSONObjBuilder b;
-
- std::string prefix = prefixIn;
- if (prefix == "")
- prefix = "version";
+ BSONObj toBSONWithPrefix(const std::string& prefix) const {
+ invariant(!prefix.empty());
+ BSONObjBuilder b;
b.appendTimestamp(prefix, _combined);
b.append(prefix + "Epoch", _epoch);
return b.obj();
}
- void addToBSON(BSONObjBuilder& b, const std::string& prefix = "") const {
+ void addToBSON(BSONObjBuilder& b, const std::string& prefix) const {
b.appendElements(toBSONWithPrefix(prefix));
}
@@ -383,19 +341,13 @@ public:
*/
void appendForCommands(BSONObjBuilder* builder) const;
- BSONObj toBSON() const {
- // ChunkVersion wants to be an array.
- BSONArrayBuilder b;
- b.appendTimestamp(_combined);
- b.append(_epoch);
- return b.arr();
+ std::string toString() const {
+ StringBuilder sb;
+ sb << _major << "|" << _minor << "||" << _epoch;
+ return sb.str();
}
- void clear() {
- _minor = 0;
- _major = 0;
- _epoch = OID();
- }
+ BSONObj toBSON() const;
private:
union {
diff --git a/src/mongo/s/chunk_version_test.cpp b/src/mongo/s/chunk_version_test.cpp
index f660d3f104d..4bea7f466bd 100644
--- a/src/mongo/s/chunk_version_test.cpp
+++ b/src/mongo/s/chunk_version_test.cpp
@@ -35,61 +35,25 @@
namespace mongo {
namespace {
-/**
- * Tests parsing of BSON for versions. In version 2.2, this parsing is meant to be very
- * flexible so different formats can be tried and enforced later.
- *
- * Formats are:
- *
- * A) { vFieldName : <TSTYPE>, [ vFieldNameEpoch : <OID> ], ... }
- * B) { fieldName : [ <TSTYPE>, <OID> ], ... }
- *
- * vFieldName is a specifyable name - usually "version" (default) or "lastmod". <TSTYPE> is a
- * type convertible to Timestamp, ideally Timestamp but also numeric.
- * <OID> is a value of type OID.
- *
- */
-TEST(Compatibility, LegacyFormatA) {
- BSONObjBuilder versionObjB;
- versionObjB.appendTimestamp("testVersion", ChunkVersion(1, 1, OID()).toLong());
- versionObjB.append("testVersionEpoch", OID::gen());
- BSONObj versionObj = versionObjB.obj();
-
- ChunkVersion parsed = ChunkVersion::fromBSON(versionObj["testVersion"]);
-
- ASSERT(ChunkVersion::canParseBSON(versionObj["testVersion"]));
- ASSERT(parsed.majorVersion() == 1);
- ASSERT(parsed.minorVersion() == 1);
- ASSERT(!parsed.epoch().isSet());
-
- parsed = ChunkVersion::fromBSON(versionObj, "testVersion");
-
- ASSERT(ChunkVersion::canParseBSON(versionObj, "testVersion"));
- ASSERT(parsed.majorVersion() == 1);
- ASSERT(parsed.minorVersion() == 1);
- ASSERT(parsed.epoch().isSet());
-}
-
-TEST(Compatibility, SubArrayFormatB) {
- BSONObjBuilder tsObjB;
- tsObjB.appendTimestamp("ts", ChunkVersion(1, 1, OID()).toLong());
- BSONObj tsObj = tsObjB.obj();
-
- BSONObjBuilder versionObjB;
- BSONArrayBuilder subArrB(versionObjB.subarrayStart("testVersion"));
- // Append this weird way so we're sure we get a timestamp type
- subArrB.append(tsObj.firstElement());
- subArrB.append(OID::gen());
- subArrB.done();
- BSONObj versionObj = versionObjB.obj();
-
- ChunkVersion parsed = ChunkVersion::fromBSON(versionObj["testVersion"]);
-
- ASSERT(ChunkVersion::canParseBSON(versionObj["testVersion"]));
- ASSERT(ChunkVersion::canParseBSON(BSONArray(versionObj["testVersion"].Obj())));
- ASSERT(parsed.majorVersion() == 1);
- ASSERT(parsed.minorVersion() == 1);
- ASSERT(parsed.epoch().isSet());
+TEST(Parsing, EpochIsOptional) {
+ const OID oid = OID::gen();
+ bool canParse = false;
+
+ ChunkVersion chunkVersionComplete = ChunkVersion::fromBSON(
+ BSON("lastmod" << Timestamp(Seconds(2), 3) << "lastmodEpoch" << oid), "lastmod", &canParse);
+ ASSERT(canParse);
+ ASSERT(chunkVersionComplete.epoch().isSet());
+ ASSERT(chunkVersionComplete.epoch() == oid);
+ ASSERT_EQ(2, chunkVersionComplete.majorVersion());
+ ASSERT_EQ(3, chunkVersionComplete.minorVersion());
+
+ canParse = false;
+ ChunkVersion chunkVersionNoEpoch =
+ ChunkVersion::fromBSON(BSON("lastmod" << Timestamp(Seconds(3), 4)), "lastmod", &canParse);
+ ASSERT(canParse);
+ ASSERT(!chunkVersionNoEpoch.epoch().isSet());
+ ASSERT_EQ(3, chunkVersionNoEpoch.majorVersion());
+ ASSERT_EQ(4, chunkVersionNoEpoch.minorVersion());
}
TEST(Comparison, StrictEqual) {
diff --git a/src/mongo/s/commands/cluster_get_shard_version_cmd.cpp b/src/mongo/s/commands/cluster_get_shard_version_cmd.cpp
index 9ac3d9bdb61..66733161fdc 100644
--- a/src/mongo/s/commands/cluster_get_shard_version_cmd.cpp
+++ b/src/mongo/s/commands/cluster_get_shard_version_cmd.cpp
@@ -28,7 +28,6 @@
#include "mongo/platform/basic.h"
-
#include "mongo/db/auth/action_set.h"
#include "mongo/db/auth/action_type.h"
#include "mongo/db/auth/authorization_manager.h"
@@ -113,7 +112,7 @@ public:
}
cm->_printChunks();
- cm->getVersion().addToBSON(result);
+ cm->getVersion().addToBSON(result, "version");
return true;
}