Skip to content

Commit

Permalink
SERVER-939 Changed FieldParser to have the correct BSON ownership sem…
Browse files Browse the repository at this point in the history
…antics.
  • Loading branch information
Alberto Lerner committed Nov 11, 2012
1 parent e735e4d commit 889fd75
Show file tree
Hide file tree
Showing 5 changed files with 111 additions and 81 deletions.
2 changes: 1 addition & 1 deletion src/mongo/s/field_parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ namespace mongo {
}

if (elem.type() == Object) {
*out = elem.Obj().getOwned();
*out = elem.embeddedObject();
return true;
}

Expand Down
8 changes: 7 additions & 1 deletion src/mongo/s/field_parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,16 @@ namespace mongo {
class FieldParser {
public:
/**
* Returns true and fill in 'out' with the contents of the field described by 'field'
* Returns true and fills in 'out' with the contents of the field described by 'field'
* or with the value in 'def', depending on whether the field is present and has the
* correct type in 'doc' or not, respectively. Otherwise, if the field exists but has
* the wrong type, returns false.
*
* NOTE ON BSON OWNERSHIP:
*
* The caller must assume that this class will point to data inside 'doc' without
* copying it. In practice this means that 'doc' MUST EXIST for as long as 'out'
* stays in scope.
*/
static bool extract(BSONObj doc,
const BSONField<bool>& field,
Expand Down
12 changes: 6 additions & 6 deletions src/mongo/s/type_collection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ namespace mongo {

using mongoutils::str::stream;

const string CollectionType::ConfigNS = "config.collections";
BSONField<string> CollectionType::ns("_id");
BSONField<string> CollectionType::primary("primary");
const std::string CollectionType::ConfigNS = "config.collections";
BSONField<std::string> CollectionType::ns("_id");
BSONField<std::string> CollectionType::primary("primary");
BSONField<BSONObj> CollectionType::keyPattern("key");
BSONField<bool> CollectionType::unique("unique");
BSONField<Date_t> CollectionType::createdAt("createdAt");
Expand All @@ -42,8 +42,8 @@ namespace mongo {
CollectionType::~CollectionType() {
}

bool CollectionType::isValid(string* errMsg) const {
string dummy;
bool CollectionType::isValid(std::string* errMsg) const {
std::string dummy;
if (errMsg == NULL) {
errMsg = &dummy;
}
Expand Down Expand Up @@ -160,7 +160,7 @@ namespace mongo {
other->_epoch = _epoch;
}

string CollectionType::toString() const {
std::string CollectionType::toString() const {
return toBSON().toString();
}

Expand Down
65 changes: 38 additions & 27 deletions src/mongo/s/type_collection.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,19 @@ namespace mongo {
*
* Usage Example:
*
* BSONObj query = QUERY(CollectionInfo::ns("mynamspace") <<
* CollectionInfo::unique(true));
* collDoc = conn->findOne(query);
* // Contact the config. 'conn' has been obtained before.
* DBClientBase* conn;
* BSONObj query = QUERY(CollectionType::ns("db.coll") <<
* CollectionType::unique(true));
* collDoc = conn->findOne(CollectionType::ConfigNS, query);
*
* // Process the response.
* CollectionType coll;
* coll.fromBSON(collDoc);
* if (! coll.isValid()) {
* /// take action
* // Can't use 'coll'. Take action.
* }
* // use coll
* // use 'coll'
*
*/
class CollectionType {
Expand All @@ -51,16 +55,16 @@ namespace mongo {
//

// Name of the collection in the config server.
static const string ConfigNS;
static const std::string ConfigNS;

// Field names and types in the collection type.
static BSONField<string> ns; // collection's namespace
static BSONField<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 collecation was created
static BSONField<bool> noBalance; // true if balancing is disabled
static BSONField<OID> epoch; // disambiguate ns (drop/recreate)
static BSONField<std::string> ns; // collection's namespace
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<bool> noBalance; // true if balancing is disabled
static BSONField<OID> epoch; // disambiguate ns (drop/recreate)

// Deprecated fields should only be used in parseBSON calls. Exposed here for testing only.
static BSONField<OID> DEPRECATED_lastmodEpoch;
Expand All @@ -76,9 +80,9 @@ namespace mongo {

/**
* Returns true if all the mandatory fields are present and have valid
* representations. Otherwise returs false and fills in the optional 'errMsg' string.
* representations. Otherwise returns false and fills in the optional 'errMsg' string.
*/
bool isValid(string* errMsg) const;
bool isValid(std::string* errMsg) const;

/**
* Returns the BSON representation of the entry.
Expand All @@ -104,35 +108,42 @@ namespace mongo {
/**
* Returns a string representation of the current internal state.
*/
string toString() const;
std::string toString() const;

//
// individual field accessors
//

void setNS(const StringData& ns) { _ns = string(ns.data(), ns.size()); }
const string& getNS() const { return _ns; }
void setPrimary(const StringData& name) { _primary = string(name.data(), name.size()); }
const string& getPrimary() const { return _primary; }
void setNS(const StringData& ns) { _ns = std::string(ns.data(), ns.size()); }
const std::string& getNS() const { return _ns; }

void setPrimary(const StringData& name) { _primary=std::string(name.data(), name.size()); }
const std::string& getPrimary() const { return _primary; }

void setKeyPattern(const BSONObj keyPattern) { _keyPattern = keyPattern.getOwned(); }
BSONObj getKeyPattern() const { return _keyPattern; }

void setUnique(bool unique) { _unique = unique; }
bool getUnique() const { return _unique; }

void setCreatedAt(const Date_t& time) { _createdAt = time; }
Date_t getCreatedAt() const { return _createdAt; }

void setNoBalance(bool noBalance) { _noBalance = noBalance; }
bool getNoBalance() const { return _noBalance; }

void setEpoch(OID oid) { _epoch = oid; }
OID getEpoch() const { return _epoch; }

private:
string _ns; // mandatory namespace
string _primary; // either or with _keyPattern
BSONObj _keyPattern; // sharding parttern if sharded
bool _unique; // not optional if sharded, index is unique
Date_t _createdAt; // mandatory creation time
bool _noBalance; // optional, if sharded, disable balancing
OID _epoch; // mandatory, to disambiguate collection incarnations
// 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
bool _noBalance; // (S) optional if sharded, disable balancing
OID _epoch; // (M) disambiguates collection incarnations

};

Expand Down
105 changes: 59 additions & 46 deletions src/mongo/s/type_collection_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,87 +23,100 @@

namespace {

using mongo::CollectionType;
using mongo::BSONObj;
using mongo::OID;
using mongo::Date_t;

TEST(Validity, Empty) {
mongo::CollectionType coll;
coll.parseBSON(mongo::BSONObj());
CollectionType coll;
BSONObj emptyObj = BSONObj();
coll.parseBSON(emptyObj);
ASSERT_FALSE(coll.isValid(NULL));
}

TEST(Validity, ShardedCollection) {
mongo::CollectionType coll;
coll.parseBSON(BSON(mongo::CollectionType::ns("db.coll") <<
mongo::CollectionType::keyPattern(BSON("a" << 1)) <<
mongo::CollectionType::createdAt(1ULL) <<
mongo::CollectionType::epoch(mongo::OID::gen())));
CollectionType coll;
BSONObj obj = BSON(CollectionType::ns("db.coll") <<
CollectionType::keyPattern(BSON("a" << 1)) <<
CollectionType::createdAt(1ULL) <<
CollectionType::epoch(OID::gen()));
coll.parseBSON(obj);
ASSERT_TRUE(coll.isValid(NULL));
}

TEST(Validity, UnshardedCollection) {
mongo::CollectionType coll;
coll.parseBSON(BSON(mongo::CollectionType::ns("db.coll") <<
mongo::CollectionType::primary("my_primary_shard") <<
mongo::CollectionType::createdAt(1ULL) <<
mongo::CollectionType::epoch(mongo::OID::gen())));
CollectionType coll;
BSONObj obj = BSON(CollectionType::ns("db.coll") <<
CollectionType::primary("my_primary_shard") <<
CollectionType::createdAt(1ULL) <<
CollectionType::epoch(OID::gen()));
coll.parseBSON(obj);
ASSERT_TRUE(coll.isValid(NULL));
}

TEST(Validity, MixingOptionals) {
mongo::CollectionType coll;
coll.parseBSON(BSON(mongo::CollectionType::ns("db.coll") <<
mongo::CollectionType::createdAt(time(0)) <<
mongo::CollectionType::unique(true)));
CollectionType coll;
BSONObj obj = BSON(CollectionType::ns("db.coll") <<
CollectionType::createdAt(time(0)) <<
CollectionType::unique(true));
coll.parseBSON(obj);
ASSERT_FALSE(coll.isValid(NULL));
}

TEST(Compatibility, OldLastmod ) {
mongo::CollectionType coll;
mongo::Date_t creation(time(0));
coll.parseBSON(BSON(mongo::CollectionType::ns("db.coll") <<
mongo::CollectionType::primary("my_primary_shard") <<
mongo::CollectionType::DEPRECATED_lastmod(creation) <<
mongo::CollectionType::epoch(mongo::OID::gen())));
CollectionType coll;
Date_t creation(time(0));
BSONObj obj = BSON(CollectionType::ns("db.coll") <<
CollectionType::primary("my_primary_shard") <<
CollectionType::DEPRECATED_lastmod(creation) <<
CollectionType::epoch(OID::gen()));
coll.parseBSON(obj);
ASSERT_TRUE(coll.isValid(NULL));
ASSERT_EQUALS(coll.getCreatedAt(), creation);
}

TEST(Compatibility, OldEpoch) {
mongo::CollectionType coll;
mongo::OID epoch = mongo::OID::gen();
coll.parseBSON(BSON(mongo::CollectionType::ns("db.coll") <<
mongo::CollectionType::primary("my_primary_shard") <<
mongo::CollectionType::createdAt(1ULL) <<
mongo::CollectionType::DEPRECATED_lastmodEpoch(epoch)));
CollectionType coll;
OID epoch = OID::gen();
BSONObj obj = BSON(CollectionType::ns("db.coll") <<
CollectionType::primary("my_primary_shard") <<
CollectionType::createdAt(1ULL) <<
CollectionType::DEPRECATED_lastmodEpoch(epoch));
coll.parseBSON(obj);
ASSERT_TRUE(coll.isValid(NULL));
ASSERT_EQUALS(coll.getEpoch(), epoch);
}

TEST(Compatibility, OldDroppedTrue) {
// The 'dropped' field creates a special case. We'd parse the doc containing it but
// would generate and empty CollectionType, which is not valid.
mongo::CollectionType coll;
coll.parseBSON(BSON(mongo::CollectionType::ns("db.coll") <<
mongo::CollectionType::keyPattern(BSON("a" << 1)) <<
mongo::CollectionType::unique(false) <<
mongo::CollectionType::DEPRECATED_lastmod(1ULL) <<
mongo::CollectionType::DEPRECATED_lastmodEpoch(mongo::OID::gen()) <<
mongo::CollectionType::DEPRECATED_dropped(true)));
// would generate an empty CollectionType, which is not valid.
CollectionType coll;
BSONObj obj = BSON(CollectionType::ns("db.coll") <<
CollectionType::keyPattern(BSON("a" << 1)) <<
CollectionType::unique(false) <<
CollectionType::DEPRECATED_lastmod(1ULL) <<
CollectionType::DEPRECATED_lastmodEpoch(OID::gen()) <<
CollectionType::DEPRECATED_dropped(true));
coll.parseBSON(obj);
ASSERT_EQUALS(coll.getNS(), "");
ASSERT_EQUALS(coll.getKeyPattern(), mongo::BSONObj());
ASSERT_EQUALS(coll.getKeyPattern(), BSONObj());
ASSERT_EQUALS(coll.getUnique(), false);
ASSERT_EQUALS(coll.getCreatedAt(), 0ULL);
ASSERT_EQUALS(coll.getEpoch(), mongo::OID());
ASSERT_EQUALS(coll.getEpoch(), OID());
ASSERT_FALSE(coll.isValid(NULL));
}

TEST(Compatibility, OldDroppedFalse) {
mongo::CollectionType coll;
mongo::OID epoch = mongo::OID::gen();
coll.parseBSON(BSON(mongo::CollectionType::ns("db.coll") <<
mongo::CollectionType::keyPattern(BSON("a" << 1)) <<
mongo::CollectionType::unique(true) <<
mongo::CollectionType::DEPRECATED_lastmod(1ULL) <<
mongo::CollectionType::DEPRECATED_lastmodEpoch(epoch) <<
mongo::CollectionType::DEPRECATED_dropped(false)));
CollectionType coll;
OID epoch = OID::gen();
BSONObj obj = BSON(CollectionType::ns("db.coll") <<
CollectionType::keyPattern(BSON("a" << 1)) <<
CollectionType::unique(true) <<
CollectionType::DEPRECATED_lastmod(1ULL) <<
CollectionType::DEPRECATED_lastmodEpoch(epoch) <<
CollectionType::DEPRECATED_dropped(false));
coll.parseBSON(obj);
ASSERT_EQUALS(coll.getNS(), "db.coll");
ASSERT_EQUALS(coll.getKeyPattern(), BSON("a" << 1));
ASSERT_EQUALS(coll.getUnique(), true);
Expand Down

0 comments on commit 889fd75

Please sign in to comment.