diff options
author | Greg Studer <greg@10gen.com> | 2012-11-26 14:14:35 -0500 |
---|---|---|
committer | Greg Studer <greg@10gen.com> | 2012-12-03 17:01:20 -0500 |
commit | 64408b78c89a65a4a727b57d552b64bf5f7eb803 (patch) | |
tree | 1e82a375b2ddcacb79eb1d3e2035cc6b647c4f6f /src/mongo/s | |
parent | d26f22eb2e4280f3dc5713ab99da810208c783da (diff) | |
download | mongo-64408b78c89a65a4a727b57d552b64bf5f7eb803.tar.gz |
SERVER-939 modify config types for config version changes
Diffstat (limited to 'src/mongo/s')
-rw-r--r-- | src/mongo/s/SConscript | 3 | ||||
-rw-r--r-- | src/mongo/s/cluster_constants.cpp | 1 | ||||
-rw-r--r-- | src/mongo/s/cluster_constants.h | 1 | ||||
-rw-r--r-- | src/mongo/s/field_parser.cpp | 116 | ||||
-rw-r--r-- | src/mongo/s/field_parser.h | 44 | ||||
-rw-r--r-- | src/mongo/s/type_chunk.cpp | 80 | ||||
-rw-r--r-- | src/mongo/s/type_chunk.h | 88 | ||||
-rw-r--r-- | src/mongo/s/type_collection.cpp | 90 | ||||
-rw-r--r-- | src/mongo/s/type_collection.h | 26 | ||||
-rw-r--r-- | src/mongo/s/type_config_version.cpp | 156 | ||||
-rw-r--r-- | src/mongo/s/type_config_version.h | 128 | ||||
-rw-r--r-- | src/mongo/s/type_database.cpp | 2 | ||||
-rw-r--r-- | src/mongo/s/type_database.h | 2 | ||||
-rw-r--r-- | src/mongo/s/type_shard.cpp | 30 | ||||
-rw-r--r-- | src/mongo/s/type_shard.h | 4 |
15 files changed, 603 insertions, 168 deletions
diff --git a/src/mongo/s/SConscript b/src/mongo/s/SConscript index e88793dba2a..8520525295d 100644 --- a/src/mongo/s/SConscript +++ b/src/mongo/s/SConscript @@ -11,7 +11,8 @@ env.StaticLibrary('base', ['cluster_constants.cpp', 'type_chunk.cpp', 'type_collection.cpp', 'type_database.cpp', - 'type_shard.cpp'], + 'type_shard.cpp', + 'type_config_version.cpp'], LIBDEPS=['$BUILD_DIR/mongo/base/base', '$BUILD_DIR/mongo/bson']) diff --git a/src/mongo/s/cluster_constants.cpp b/src/mongo/s/cluster_constants.cpp index f75fd97ff26..5412d61fd9a 100644 --- a/src/mongo/s/cluster_constants.cpp +++ b/src/mongo/s/cluster_constants.cpp @@ -43,6 +43,7 @@ namespace mongo { BSONField<Date_t> CollectionFields::lastmod("lastmod"); BSONField<bool> CollectionFields::dropped("dropped"); BSONField<bool> CollectionFields::noBalance("noBalance"); + BSONField<OID> CollectionFields::epoch("lastmodEpoch"); const string ConfigNS::chunk = "config.chunks"; BSONField<string> ChunkFields::name("_id"); diff --git a/src/mongo/s/cluster_constants.h b/src/mongo/s/cluster_constants.h index f6bc723c752..32612a82553 100644 --- a/src/mongo/s/cluster_constants.h +++ b/src/mongo/s/cluster_constants.h @@ -82,6 +82,7 @@ namespace mongo { static BSONField<Date_t> lastmod; // when collecation was created static BSONField<bool> dropped; // logical deletion static BSONField<bool> noBalance; // true if balancing is disabled + static BSONField<OID> epoch; // Epoch of collection }; /** diff --git a/src/mongo/s/field_parser.cpp b/src/mongo/s/field_parser.cpp index b9be26e1e72..0602eae6157 100644 --- a/src/mongo/s/field_parser.cpp +++ b/src/mongo/s/field_parser.cpp @@ -15,13 +15,29 @@ */ #include "mongo/s/field_parser.h" +#include "mongo/util/mongoutils/str.h" namespace mongo { + using mongoutils::str::stream; + + template<class T> + void _genFieldErrMsg(const BSONObj& doc, + const BSONField<T>& field, + const string expected, + string* errMsg) + { + if (!errMsg) return; + *errMsg = stream() << "wrong type for '" << field() << "' field, expected " << expected + << ", found " << doc[field.name()].toString(); + } + bool FieldParser::extract(BSONObj doc, const BSONField<bool>& field, bool def, - bool* out) { + bool* out, + string* errMsg) + { BSONElement elem = doc[field.name()]; if (elem.eoo()) { *out = def; @@ -33,13 +49,16 @@ namespace mongo { return true; } + _genFieldErrMsg(doc, field, "boolean", errMsg); return false; } bool FieldParser::extract(BSONObj doc, const BSONField<BSONArray>& field, const BSONArray& def, - BSONArray* out) { + BSONArray* out, + string* errMsg) + { BSONElement elem = doc[field.name()]; if (elem.eoo()) { *out = def; @@ -47,17 +66,20 @@ namespace mongo { } if (elem.type() == Array) { - *out = BSONArray(elem.embeddedObject()); + *out = BSONArray(elem.embeddedObject().getOwned()); return true; } + _genFieldErrMsg(doc, field, "array", errMsg); return false; } bool FieldParser::extract(BSONObj doc, const BSONField<BSONObj>& field, const BSONObj& def, - BSONObj* out) { + BSONObj* out, + string* errMsg) + { BSONElement elem = doc[field.name()]; if (elem.eoo()) { *out = def; @@ -65,17 +87,20 @@ namespace mongo { } if (elem.type() == Object) { - *out = elem.embeddedObject(); + *out = elem.embeddedObject().getOwned(); return true; } + _genFieldErrMsg(doc, field, "object", errMsg); return false; } bool FieldParser::extract(BSONObj doc, const BSONField<Date_t>& field, const Date_t def, - Date_t* out) { + Date_t* out, + string* errMsg) + { BSONElement elem = doc[field.name()]; if (elem.eoo()) { *out = def; @@ -87,13 +112,16 @@ namespace mongo { return true; } + _genFieldErrMsg(doc, field, "date or timestamp", errMsg); return false; } bool FieldParser::extract(BSONObj doc, const BSONField<string>& field, const string& def, - string* out) { + string* out, + string* errMsg) + { BSONElement elem = doc[field.name()]; if (elem.eoo()) { *out = def; @@ -105,13 +133,16 @@ namespace mongo { return true; } + _genFieldErrMsg(doc, field, "string", errMsg); return false; } bool FieldParser::extract(BSONObj doc, const BSONField<OID>& field, const OID& def, - OID* out) { + OID* out, + string* errMsg) + { BSONElement elem = doc[field.name()]; if (elem.eoo()) { *out = def; @@ -123,13 +154,58 @@ namespace mongo { return true; } + _genFieldErrMsg(doc, field, "OID", errMsg); + return false; + } + + bool FieldParser::extract(BSONObj doc, + const BSONField<int>& field, + const int& def, + int* out, + string* errMsg) + { + BSONElement elem = doc[field.name()]; + if (elem.eoo()) { + *out = def; + return true; + } + + if (elem.type() == NumberInt) { + *out = elem.numberInt(); + return true; + } + + _genFieldErrMsg(doc, field, "integer", errMsg); + return false; + } + + bool FieldParser::extractNumber(BSONObj doc, + const BSONField<int>& field, + const int& def, + int* out, + string* errMsg) + { + BSONElement elem = doc[field.name()]; + if (elem.eoo()) { + *out = def; + return true; + } + + if (elem.isNumber()) { + *out = elem.numberInt(); + return true; + } + + _genFieldErrMsg(doc, field, "number", errMsg); return false; } bool FieldParser::extract(BSONObj doc, const BSONField<long long>& field, const long long& def, - long long* out) { + long long* out, + string* errMsg) + { BSONElement elem = doc[field.name()]; if (elem.eoo()) { *out = def; @@ -141,6 +217,28 @@ namespace mongo { return true; } + _genFieldErrMsg(doc, field, "long", errMsg); + return false; + } + + bool FieldParser::extractNumber(BSONObj doc, + const BSONField<long long>& field, + const long long& def, + long long* out, + string* errMsg) + { + BSONElement elem = doc[field.name()]; + if (elem.eoo()) { + *out = def; + return true; + } + + if (elem.isNumber()) { + *out = elem.numberLong(); + return true; + } + + _genFieldErrMsg(doc, field, "number", errMsg); return false; } diff --git a/src/mongo/s/field_parser.h b/src/mongo/s/field_parser.h index bddae660562..c02fd438f52 100644 --- a/src/mongo/s/field_parser.h +++ b/src/mongo/s/field_parser.h @@ -41,37 +41,67 @@ namespace mongo { static bool extract(BSONObj doc, const BSONField<bool>& field, bool def, - bool* out); + bool* out, + string* errMsg = NULL); static bool extract(BSONObj doc, const BSONField<BSONArray>& field, const BSONArray& def, - BSONArray* out); + BSONArray* out, + string* errMsg = NULL); static bool extract(BSONObj doc, const BSONField<BSONObj>& field, const BSONObj& def, - BSONObj* out); + BSONObj* out, + string* errMsg = NULL); static bool extract(BSONObj doc, const BSONField<Date_t>& field, const Date_t def, - Date_t* out); + Date_t* out, + string* errMsg = NULL); static bool extract(BSONObj doc, const BSONField<string>& field, const string& def, - string* out); + string* out, + string* errMsg = NULL); static bool extract(BSONObj doc, const BSONField<OID>& field, const OID& def, - OID* out); + OID* out, + string* errMsg = NULL); + + static bool extract(BSONObj doc, + const BSONField<int>& field, + const int& def, + int* out, + string* errMsg = NULL); static bool extract(BSONObj doc, const BSONField<long long>& field, const long long& def, - long long* out); + long long* out, + string* errMsg = NULL); + + /** + * The following extractNumber methods do implicit conversion between any numeric type and + * the BSONField type. This can be useful when an exact numeric type is not needed, for + * example if the field is sometimes modified from the shell which can change the type. + */ + static bool extractNumber(BSONObj doc, + const BSONField<int>& field, + const int& def, + int* out, + string* errMsg = NULL); + + static bool extractNumber(BSONObj doc, + const BSONField<long long>& field, + const long long& def, + long long* out, + string* errMsg = NULL); }; } // namespace mongo diff --git a/src/mongo/s/type_chunk.cpp b/src/mongo/s/type_chunk.cpp index 306f722a74a..ce513a62a8e 100644 --- a/src/mongo/s/type_chunk.cpp +++ b/src/mongo/s/type_chunk.cpp @@ -15,7 +15,6 @@ */ #include <cstring> // for strcmp - #include "mongo/s/type_chunk.h" #include "mongo/s/field_parser.h" @@ -47,9 +46,8 @@ namespace mongo { bool ChunkType::isValid(std::string* errMsg) const { std::string dummy; - if (errMsg == NULL) { - errMsg = &dummy; - } + + if (errMsg == NULL) errMsg = &dummy; // All the mandatory fields must be present. if (_name.empty()) { @@ -60,11 +58,11 @@ namespace mongo { *errMsg = stream() << "missing " << ns.name() << " field"; return false; } - if (! _min.nFields()) { + if (!_min.nFields()) { *errMsg = stream() << "missing " << min.name() << " field"; return false; } - if (! _max.nFields()) { + if (!_max.nFields()) { *errMsg = stream() << "missing " << max.name() << " field"; return false; } @@ -110,12 +108,10 @@ namespace mongo { if (_min.nFields()) builder.append(min(), _min); if (_max.nFields()) builder.append(max(), _max); - if (_version._combined != 0ULL) { - BSONArrayBuilder arrBuilder(builder.subarrayStart(version())); - arrBuilder.appendTimestamp(_version._major, _version._minor); - arrBuilder.append(_version._epoch); - arrBuilder.done(); - } + // For now, write both the deprecated *and* the new fields + + _version.addToBSON(builder, version()); + _version.addToBSON(builder, DEPRECATED_lastmod()); if (!_shard.empty()) builder.append(shard(), _shard); if (_jumbo) builder.append(jumbo(), _jumbo); @@ -123,53 +119,37 @@ namespace mongo { return builder.obj(); } - void ChunkType::parseBSON(BSONObj source) { + string ChunkType::toString() const { + return toBSON().toString(); + } + + bool ChunkType::parseBSON(BSONObj source, string* errMsg) { clear(); - bool ok = true; - ok &= FieldParser::extract(source, name, "", &_name); - ok &= FieldParser::extract(source, ns, "", &_ns); - ok &= FieldParser::extract(source, min, BSONObj(), &_min); - ok &= FieldParser::extract(source, max, BSONObj(), &_max); - ok &= FieldParser::extract(source, shard, "", &_shard); - ok &= FieldParser::extract(source, jumbo, false, &_jumbo); - if (! ok) { - clear(); - return; - } + string dummy; + if (!errMsg) errMsg = &dummy; + + if (!FieldParser::extract(source, name, "", &_name, errMsg)) return false; + if (!FieldParser::extract(source, ns, "", &_ns, errMsg)) return false; + if (!FieldParser::extract(source, min, BSONObj(), &_min, errMsg)) return false; + if (!FieldParser::extract(source, max, BSONObj(), &_max, errMsg)) return false; + if (!FieldParser::extract(source, shard, "", &_shard, errMsg)) return false; + if (!FieldParser::extract(source, jumbo, false, &_jumbo, errMsg)) return false; // - // ShardChunkVersion backward compatibility logic + // ShardChunkVersion backward compatibility logic contained in ShardChunkVersion // // ShardChunkVersion is currently encoded as { 'version': [<TS>,<OID>] } - BSONArray arrVersion; - ok = FieldParser::extract(source, version, BSONArray(), &arrVersion); - if (! ok) { - clear(); - return; - } - else if (arrVersion.nFields()) { - bool okVersion; - _version = ShardChunkVersion::fromBSON(arrVersion, &okVersion); - if (! okVersion) { - clear(); - } - return; - } - // If we haven't found the current format try parsing the deprecated format - // { lastmod: <TS>, lastmodEpoch: <OID> }. - Date_t lastmod; - OID epoch; - ok = FieldParser::extract(source, DEPRECATED_lastmod, time(0), &lastmod); - ok &= FieldParser::extract(source, DEPRECATED_epoch, OID(), &epoch); - if (! ok) { - clear(); + if (ShardChunkVersion::canParseBSON(source, version())) { + _version = ShardChunkVersion::fromBSON(source, version()); } - else { - _version = ShardChunkVersion(lastmod.millis, epoch); + else if (ShardChunkVersion::canParseBSON(source, DEPRECATED_lastmod())) { + _version = ShardChunkVersion::fromBSON(source, DEPRECATED_lastmod()); } + + return true; } void ChunkType::clear() { @@ -182,7 +162,7 @@ namespace mongo { _jumbo = false; } - void ChunkType::cloneTo(ChunkType* other) { + void ChunkType::cloneTo(ChunkType* other) const { other->clear(); other->_name = _name; other->_ns = _ns; diff --git a/src/mongo/s/type_chunk.h b/src/mongo/s/type_chunk.h index a10fdfa206e..23f12db3280 100644 --- a/src/mongo/s/type_chunk.h +++ b/src/mongo/s/type_chunk.h @@ -22,7 +22,6 @@ #include "mongo/base/string_data.h" #include "mongo/db/jsobj.h" #include "mongo/s/util.h" // for ShardChunkVersion - namespace mongo { /** @@ -71,8 +70,8 @@ namespace mongo { // Transition to new format, 2.2 -> 2.4 // 2.2 can read both lastmod + lastmodEpoch format and 2.4 [ lastmod, OID ] formats. - static BSONField<Date_t> DEPRECATED_lastmod; // major | minor versions - static BSONField<OID> DEPRECATED_epoch; // disambiguates collection incarnations + static BSONField<Date_t> DEPRECATED_lastmod; // major | minor versions + static BSONField<OID> DEPRECATED_epoch; // disambiguates collection incarnations // // chunk type methods @@ -96,7 +95,7 @@ namespace mongo { * Clears and populates the internal state using the 'source' BSON object if the * latter contains valid values. Otherwise clear the internal state. */ - void parseBSON(BSONObj source); + bool parseBSON(BSONObj source, std::string* errMsg); /** * Clears the internal state. @@ -106,7 +105,7 @@ namespace mongo { /** * Copies all the fields present in 'this' to 'other'. */ - void cloneTo(ChunkType* other); + void cloneTo(ChunkType* other) const; /** * Returns a string representation of the current internal state. @@ -117,36 +116,71 @@ namespace mongo { // individual field accessors // - void setName(const StringData& name) { _name = std::string(name.data(), name.size()); } - const std::string& getName() const { return _name; } + void setName(const StringData& name) { + _name = std::string(name.data(), name.size()); + } + + const std::string& getName() const { + return _name; + } + + void setNS(const StringData& ns) { + _ns = std::string(ns.data(), ns.size()); + } + + const std::string& getNS() const { + return _ns; + } + + void setMin(const BSONObj& min) { + _min = min.getOwned(); + } + + BSONObj getMin() const { + return _min; + } + + void setMax(const BSONObj& max) { + _max = max.getOwned(); + } + + BSONObj getMax() const { + return _max; + } - void setNS(const StringData& ns) { _ns = std::string(ns.data(), ns.size()); } - const std::string& getNS() const { return _ns; } + void setVersion(const ShardChunkVersion& version) { + _version = version; + } - void setMin(const BSONObj& min) { _min = min.getOwned(); } - BSONObj getMin() const { return _min; } + const ShardChunkVersion& getVersion() const { + return _version; + } - void setMax(const BSONObj& max) { _max = max.getOwned(); } - BSONObj getMax() const { return _max; } + void setShard(const StringData& shard) { + _shard = std::string(shard.data(), shard.size()); + } - void setVersion(const ShardChunkVersion& version) { _version = version; } - const ShardChunkVersion& getVersion() const { return _version; } + const std::string& getShard() const { + return _shard; + } - void setShard(const StringData& shard) { _shard=std::string(shard.data(), shard.size()); } - const std::string& getShard() const { return _shard; } + void setJumbo(bool jumbo) { + _jumbo = jumbo; + } - void setJumbo(bool jumbo) { _jumbo = jumbo; } - bool getJumbo() const { return _jumbo; } + bool getJumbo() const { + return _jumbo; + } private: // Convention: (M)andatory, (O)ptional, (S)pecial rule. - string _name; // (M) chunk's id - string _ns; // (M) collection this chunk is in - BSONObj _min; // (M) first key of the range, inclusive - BSONObj _max; // (M) last key of the range, non-inclusive - ShardChunkVersion _version; // (M) version of this chunk - string _shard; // (M) shard this chunk lives in - bool _jumbo; // (O) too big to move? + string _name; // (M) chunk's id + string _ns; // (M) collection this chunk is in + BSONObj _min; // (M) first key of the range, inclusive + BSONObj _max; // (M) last key of the range, non-inclusive + ShardChunkVersion _version; // (M) version of this chunk + string _shard; // (M) shard this chunk lives in + bool _jumbo; // (O) too big to move? }; -} // namespace mongo +} // namespace mongo diff --git a/src/mongo/s/type_collection.cpp b/src/mongo/s/type_collection.cpp index c3643fc2398..a1f5246c375 100644 --- a/src/mongo/s/type_collection.cpp +++ b/src/mongo/s/type_collection.cpp @@ -27,13 +27,14 @@ namespace mongo { BSONField<std::string> CollectionType::primary("primary"); BSONField<BSONObj> CollectionType::keyPattern("key"); BSONField<bool> CollectionType::unique("unique"); - BSONField<Date_t> CollectionType::createdAt("createdAt"); + BSONField<Date_t> CollectionType::updatedAt("updatedAt"); BSONField<bool> CollectionType::noBalance("noBalance"); BSONField<OID> CollectionType::epoch("epoch"); + // To-be-deprecated, not yet + BSONField<bool> CollectionType::dropped("dropped"); BSONField<OID> CollectionType::DEPRECATED_lastmodEpoch("lastmodEpoch"); BSONField<Date_t> CollectionType::DEPRECATED_lastmod("lastmod"); - BSONField<bool> CollectionType::DEPRECATED_dropped("dropped"); CollectionType::CollectionType() { clear(); @@ -44,28 +45,26 @@ namespace mongo { bool CollectionType::isValid(std::string* errMsg) const { std::string dummy; - if (errMsg == NULL) { - errMsg = &dummy; - } + + if (errMsg == NULL) errMsg = &dummy; // All the mandatory fields must be present. if (_ns.empty()) { *errMsg = stream() << "missing " << ns.name() << " field"; return false; } - if (_createdAt.millis == 0) { - *errMsg = stream() << "missing " << createdAt.name() << " field"; + if (_updatedAt.millis == 0) { + *errMsg = stream() << "missing " << updatedAt.name() << " field"; return false; } - if (! _epoch.isSet()) { + if (!_epoch.isSet()) { *errMsg = stream() << "missing " << epoch.name() << " field"; return false; } // Either sharding or primary information should be filled. if (_primary.empty() == (_keyPattern.nFields() == 0)) { - *errMsg = stream() << "either " << primary.name() - << " or " << keyPattern.name() + *errMsg = stream() << "either " << primary.name() << " or " << keyPattern.name() << " should be filled"; return false; } @@ -81,62 +80,59 @@ namespace mongo { BSONObj CollectionType::toBSON() const { BSONObjBuilder builder; - if (!_ns.empty()) builder.append(ns(), _ns); + builder.append(ns(), _ns); if (!_primary.empty()) builder.append(primary(), _primary); if (_keyPattern.nFields()) builder.append(keyPattern(), _keyPattern); if (_unique) builder.append(unique(), _unique); - if (_createdAt.millis > 0ULL) builder.append(createdAt(), _createdAt); + builder.append(updatedAt(), _updatedAt); + builder.append(DEPRECATED_lastmod(), _updatedAt); if (_noBalance) builder.append(noBalance(), _noBalance); - if (_epoch.isSet()) builder.append(epoch(), _epoch); + if (_epoch.isSet()) { + builder.append(epoch(), _epoch); + builder.append(DEPRECATED_lastmodEpoch(), _epoch); + } + // Always need to write dropped for compatibility w/ 2.0/2.2 + builder.append(dropped(), _dropped); return builder.obj(); } - void CollectionType::parseBSON(BSONObj source) { + bool CollectionType::parseBSON(BSONObj source, string* errMsg) { clear(); - bool ok = true; - ok &= FieldParser::extract(source, ns, "", &_ns); - ok &= FieldParser::extract(source, primary, "", &_primary); - ok &= FieldParser::extract(source, keyPattern, BSONObj(), &_keyPattern); - ok &= FieldParser::extract(source, unique, false, &_unique); - ok &= FieldParser::extract(source, createdAt, 0ULL, &_createdAt); - ok &= FieldParser::extract(source, noBalance, false, &_noBalance); - ok &= FieldParser::extract(source, epoch, OID(), &_epoch); - if (! ok) { - clear(); - return; - } + string dummy; + if (!errMsg) errMsg = &dummy; + + if (!FieldParser::extract(source, ns, "", &_ns, errMsg)) return false; + if (!FieldParser::extract(source, primary, "", &_primary, errMsg)) return false; + if (!FieldParser::extract(source, keyPattern, BSONObj(), &_keyPattern, errMsg)) return false; + if (!FieldParser::extract(source, unique, false, &_unique, errMsg)) return false; + if (!FieldParser::extract(source, updatedAt, 0ULL, &_updatedAt, errMsg)) return false; + if (!FieldParser::extract(source, noBalance, false, &_noBalance, errMsg)) return false; + if (!FieldParser::extract(source, epoch, OID(), &_epoch, errMsg)) return false; + if (!FieldParser::extract(source, dropped, false, &_dropped, errMsg)) return false; // // backward compatibility // // 'createAt' used to be called 'lastmod' up to 2.2. + Date_t lastmod; - if (! FieldParser::extract(source, DEPRECATED_lastmod, 0ULL, &lastmod)) { - clear(); - return; - } - else if (lastmod != 0ULL) { - _createdAt = lastmod; - } + if (!FieldParser::extract(source, DEPRECATED_lastmod, 0ULL, &lastmod, errMsg)) return false; - // There was a flag to mark a collection as loggically dropped, up to 2.2. - bool dropped; - if (! FieldParser::extract(source, DEPRECATED_dropped, false, &dropped) || dropped) { - clear(); - return; + if (lastmod != 0ULL) { + _updatedAt = lastmod; } // 'lastmodEpoch' was a transition format to 'epoch', up to 2.2 OID lastmodEpoch; - if (! FieldParser::extract(source, DEPRECATED_lastmodEpoch, OID(), &lastmodEpoch)) { - clear(); - return; - } - else if (lastmodEpoch.isSet()) { + if (!FieldParser::extract(source, DEPRECATED_lastmodEpoch, OID(), &lastmodEpoch, errMsg)) return false; + + if (lastmodEpoch.isSet()) { _epoch = lastmodEpoch; } + + return true; } void CollectionType::clear() { @@ -144,20 +140,22 @@ namespace mongo { _primary.clear(); _keyPattern = BSONObj(); _unique = false; - _createdAt = 0ULL; + _updatedAt = 0ULL; _noBalance = false; _epoch = OID(); + _dropped = false; } - void CollectionType::cloneTo(CollectionType* other) { + void CollectionType::cloneTo(CollectionType* other) const { other->clear(); other->_ns = _ns; other->_primary = _primary; other->_keyPattern = _keyPattern; other->_unique = _unique; - other->_createdAt = _createdAt; + other->_updatedAt = _updatedAt; other->_noBalance = _noBalance; other->_epoch = _epoch; + other->_dropped = _dropped; } std::string CollectionType::toString() const { diff --git a/src/mongo/s/type_collection.h b/src/mongo/s/type_collection.h index 3302d6c0d66..aac83375c5b 100644 --- a/src/mongo/s/type_collection.h +++ b/src/mongo/s/type_collection.h @@ -43,6 +43,10 @@ namespace mongo { * if (! coll.isValid()) { * // Can't use 'coll'. Take action. * } + * if (coll.isDropped()) { + * // Coll doesn't exist, Take action. + * } + * * // use 'coll' * */ @@ -62,14 +66,15 @@ namespace mongo { static BSONField<std::string> primary; // primary db when not sharded static BSONField<BSONObj> keyPattern; // sharding key, if sharded static BSONField<bool> unique; // sharding key unique? - static BSONField<Date_t> createdAt; // when collection was created + static BSONField<Date_t> updatedAt; // when collection was created static BSONField<bool> noBalance; // true if balancing is disabled static BSONField<OID> epoch; // disambiguate ns (drop/recreate) + // To-be-deprecated, not yet + static BSONField<bool> dropped; // true if we should ignore this collection entry // Deprecated fields should only be used in parseBSON calls. Exposed here for testing only. static BSONField<OID> DEPRECATED_lastmodEpoch; static BSONField<Date_t> DEPRECATED_lastmod; - static BSONField<bool> DEPRECATED_dropped; // // collection type methods @@ -93,7 +98,7 @@ namespace mongo { * Clears and populates the internal state using the 'source' BSON object if the * latter contains valid values. Otherwise clear the internal state. */ - void parseBSON(BSONObj source); + bool parseBSON(BSONObj source, std::string* errMsg); /** * Clears the internal state. @@ -103,7 +108,7 @@ namespace mongo { /** * Copies all the fields present in 'this' to 'other'. */ - void cloneTo(CollectionType* other); + void cloneTo(CollectionType* other) const; /** * Returns a string representation of the current internal state. @@ -124,10 +129,10 @@ namespace mongo { BSONObj getKeyPattern() const { return _keyPattern; } void setUnique(bool unique) { _unique = unique; } - bool getUnique() const { return _unique; } + bool isUnique() const { return _unique; } - void setCreatedAt(const Date_t& time) { _createdAt = time; } - Date_t getCreatedAt() const { return _createdAt; } + void setUpdatedAt(const Date_t& time) { _updatedAt = time; } + Date_t getUpdatedAt() const { return _updatedAt; } void setNoBalance(bool noBalance) { _noBalance = noBalance; } bool getNoBalance() const { return _noBalance; } @@ -135,16 +140,19 @@ namespace mongo { void setEpoch(OID oid) { _epoch = oid; } OID getEpoch() const { return _epoch; } + void setDropped(bool dropped) { _dropped = dropped; } + bool isDropped() const { return _dropped; } + private: // Convention: (M)andatory, (O)ptional, (S)pecial rule. std::string _ns; // (M) namespace std::string _primary; // (S) either/or with _keyPattern BSONObj _keyPattern; // (S) sharding pattern if sharded bool _unique; // (S) mandatory if sharded, index is unique - Date_t _createdAt; // (M) creation time + Date_t _updatedAt; // (M) last updated time bool _noBalance; // (S) optional if sharded, disable balancing OID _epoch; // (M) disambiguates collection incarnations - + bool _dropped; // (O) if true, ignore this entry }; } // namespace mongo diff --git a/src/mongo/s/type_config_version.cpp b/src/mongo/s/type_config_version.cpp new file mode 100644 index 00000000000..8fc69c45cf8 --- /dev/null +++ b/src/mongo/s/type_config_version.cpp @@ -0,0 +1,156 @@ +/** + * Copyright (C) 2012 10gen Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * 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 + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "mongo/s/type_config_version.h" + +#include "mongo/s/field_parser.h" +#include "mongo/util/mongoutils/str.h" + +namespace mongo { + + using mongoutils::str::stream; + + const string VersionType::ConfigNS("config.version"); + + const BSONField<int> VersionType::minVersion("minVersion"); + const BSONField<int> VersionType::maxVersion("maxVersion"); + const BSONField<OID> VersionType::clusterId("clusterId"); + const BSONField<int> VersionType::version_DEPRECATED("version"); + + VersionType::VersionType() { + clear(); + } + + VersionType::~VersionType() { + } + + bool VersionType::isValid(string* errMsg) const { + + std::string dummy; + + if (errMsg == NULL) { + errMsg = &dummy; + } + + if (_minVersion == -1) { + if (errMsg) { + *errMsg = stream() << "no version found"; + } + return false; + } + + // Hardcoded 3 here because it's the last version without a cluster id + if (_maxVersion > 3 && !_clusterId.isSet()) { + if (errMsg) { + *errMsg = stream() << "no clusterId found"; + } + return false; + } + + return true; + } + + void VersionType::clear() { + _minVersion = -1; + _maxVersion = -1; + _clusterId = OID(); + } + + bool VersionType::parseBSON(const BSONObj& source, string* errMsg) { + clear(); + + string dummy; + if (!errMsg) errMsg = &dummy; + + if (!FieldParser::extractNumber(source, minVersion, -1, &_minVersion, errMsg)) return false; + + if (_minVersion == -1) { + if (!FieldParser::extractNumber(source, version_DEPRECATED, -1, &_minVersion, errMsg)) return false; + } + + if (!FieldParser::extractNumber(source, maxVersion, -1, &_maxVersion, errMsg)) return false; + + if (!FieldParser::extract(source, clusterId, OID(), &_clusterId, errMsg)) return false; + + if (_maxVersion == -1) { + _maxVersion = _minVersion; + } + + return true; + } + + BSONObj VersionType::toBSON() const { + return BSON("_id" << 1 + << version_DEPRECATED(_minVersion) + << minVersion(_minVersion) + << maxVersion(_maxVersion) + << clusterId(_clusterId)); + } + + string VersionType::toString() const { + return toBSON().toString(); + } + + OID VersionType::getClusterId() const { + return _clusterId; + } + + void VersionType::setClusterId(const OID& clusterId) { + _clusterId = clusterId; + } + + int VersionType::getMinCompatibleVersion() const { + return _minVersion; + } + + void VersionType::setMinCompatibleVersion(int version) { + _minVersion = version; + } + + int VersionType::getMaxCompatibleVersion() const { + return _maxVersion; + } + + void VersionType::setMaxCompatibleVersion(int version) { + _maxVersion = version; + } + + bool VersionType::isCompatibleVersion(int version) const { + return version >= _minVersion && version <= _maxVersion; + } + + void VersionType::setDefaultVersion() { + _minVersion = 1; + _maxVersion = 1; + _clusterId = OID(); + } + + void VersionType::setEmptyVersion() { + _minVersion = 0; + _maxVersion = 0; + _clusterId = OID(); + } + + bool VersionType::isEmptyVersion() const { + return _minVersion == 0 && _maxVersion == 0 && _clusterId == OID(); + } + + bool VersionType::isEquivalentTo(const VersionType& other) const { + return _minVersion == other._minVersion && _maxVersion == other._maxVersion + && _clusterId == other._clusterId; + } + +} // namespace mongo diff --git a/src/mongo/s/type_config_version.h b/src/mongo/s/type_config_version.h new file mode 100644 index 00000000000..5fc5f40b642 --- /dev/null +++ b/src/mongo/s/type_config_version.h @@ -0,0 +1,128 @@ +/** + * Copyright (C) 2012 10gen Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * 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 + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#pragma once + +#include <string> + +#include "mongo/base/disallow_copying.h" +#include "mongo/base/string_data.h" +#include "mongo/db/jsobj.h" + +namespace mongo { + + /** + * This class represents the layout and contents of the single document contained in the + * config.version collection. All manipulation of this document should be done using this class. + * + * Usage Example: + * + * DBClientBase* conn; + * BSONObj query = QUERY(); + * versionDoc = conn->findOne(VersionType::ConfigNS, query); + * + * // Process the response. + * VersionType versionInfo; + * if (!versionInfo.parseBSON(versionDoc)) { + * // Can't parse document, take action + * } + * if (!versionInfo.isValid()) { + * // Can't use version, take action. + * } + * // use 'versionInfo' + * + */ + class VersionType { + MONGO_DISALLOW_COPYING(VersionType); + public: + + // Name of the versions collection in the config schema + static const string ConfigNS; + + // Field names and types of the version document + static const BSONField<int> minVersion; + static const BSONField<int> maxVersion; + static const BSONField<OID> clusterId; + + // Transition to new format v2.2->v2.4 + // We eventually will not use version, minVersion and maxVersion instead + static const BSONField<int> version_DEPRECATED; + + VersionType(); + ~VersionType(); + + /** + * Returns true if all the mandatory fields are present and have valid + * representations. Otherwise returns false and fills in the optional 'errMsg' string. + */ + bool isValid(std::string* errMsg) const; + + /** + * Returns the BSON representation of the entry. + */ + BSONObj toBSON() const; + + /** + * Clears and populates the internal state using the 'source' BSON object if the + * latter contains valid values. Otherwise clear the internal state. + */ + bool parseBSON(const BSONObj& source, std::string* errMsg); + + /** + * Clears the internal state. + */ + void clear(); + + /** + * Returns a string representation of the current internal state. + */ + std::string toString() const; + + // + // individual field accessors and helpers + // + + OID getClusterId() const; + void setClusterId(const OID& clusterId); + + int getMinCompatibleVersion() const; + void setMinCompatibleVersion(int version); + + int getMaxCompatibleVersion() const; + void setMaxCompatibleVersion(int version); + + bool isCompatibleVersion(int version) const; + + // If there is no version document but other config collections exist, + // this is the default version we use + void setDefaultVersion(); + + // If there is no data in the config server, this is the default version we use + void setEmptyVersion(); + + bool isEmptyVersion() const; + + // Checks whether two versions are equivalent + bool isEquivalentTo(const VersionType& other) const; + + private: + + int _minVersion; + int _maxVersion; + OID _clusterId; + }; + +} // namespace mongo diff --git a/src/mongo/s/type_database.cpp b/src/mongo/s/type_database.cpp index 8ed2a9762c1..060a40b3db1 100644 --- a/src/mongo/s/type_database.cpp +++ b/src/mongo/s/type_database.cpp @@ -102,7 +102,7 @@ namespace mongo { _draining = false; } - void DatabaseType::cloneTo(DatabaseType* other) { + void DatabaseType::cloneTo(DatabaseType* other) const { other->clear(); other->_name = _name; other->_primary = _primary; diff --git a/src/mongo/s/type_database.h b/src/mongo/s/type_database.h index 37c98d05c01..6993fa1d42e 100644 --- a/src/mongo/s/type_database.h +++ b/src/mongo/s/type_database.h @@ -101,7 +101,7 @@ namespace mongo { /** * Copies all the fields present in 'this' to 'other'. */ - void cloneTo(DatabaseType* other); + void cloneTo(DatabaseType* other) const; /** * Returns a string representation of the current internal state. diff --git a/src/mongo/s/type_shard.cpp b/src/mongo/s/type_shard.cpp index 7313f44036c..66440f33dc2 100644 --- a/src/mongo/s/type_shard.cpp +++ b/src/mongo/s/type_shard.cpp @@ -39,10 +39,9 @@ namespace mongo { } bool ShardType::isValid(std::string* errMsg) const { - std::string dummy; - if (errMsg == NULL) { - errMsg = &dummy; - } + + string dummy; + if (!errMsg) errMsg = &dummy; // All the mandatory fields must be present. if (_name.empty()) { @@ -67,18 +66,19 @@ namespace mongo { return builder.obj(); } - void ShardType::parseBSON(BSONObj source) { + bool ShardType::parseBSON(BSONObj source, string* errMsg) { clear(); - bool ok = true; - ok &= FieldParser::extract(source, name, "", &_name); - ok &= FieldParser::extract(source, host, "", &_host); - ok &= FieldParser::extract(source, draining, false, &_draining); - ok &= FieldParser::extract(source, maxSize, 0LL, &_maxSize); - ok &= FieldParser::extract(source, tags, BSONArray(), &_tags); - if (! ok) { - clear(); - } + string dummy; + if (!errMsg) errMsg = &dummy; + + if (!FieldParser::extract(source, name, "", &_name, errMsg)) return false; + if (!FieldParser::extract(source, host, "", &_host, errMsg)) return false; + if (!FieldParser::extract(source, draining, false, &_draining, errMsg)) return false; + if (!FieldParser::extract(source, maxSize, 0LL, &_maxSize, errMsg)) return false; + if (!FieldParser::extract(source, tags, BSONArray(), &_tags, errMsg)) return false; + + return true; } void ShardType::clear() { @@ -89,7 +89,7 @@ namespace mongo { _tags = BSONArray(); } - void ShardType::cloneTo(ShardType* other) { + void ShardType::cloneTo(ShardType* other) const { other->clear(); other->_name = _name; other->_host = _host; diff --git a/src/mongo/s/type_shard.h b/src/mongo/s/type_shard.h index e705f1d3d42..60745f4553c 100644 --- a/src/mongo/s/type_shard.h +++ b/src/mongo/s/type_shard.h @@ -84,7 +84,7 @@ namespace mongo { * Clears and populates the internal state using the 'source' BSON object if the * latter contains valid values. Otherwise clear the internal state. */ - void parseBSON(BSONObj source); + bool parseBSON(BSONObj source, std::string* errMsg); /** * Clears the internal state. @@ -94,7 +94,7 @@ namespace mongo { /** * Copies all the fields present in 'this' to 'other'. */ - void cloneTo(ShardType* other); + void cloneTo(ShardType* other) const; /** * Returns a string representation of the current internal state. |