bool CollectionMetadata::keyBelongsToMe( const BSONObj& key ) const { // For now, collections don't move. So if the collection is not sharded, assume // the document with the given key can be accessed. if ( _keyPattern.isEmpty() ) { return true; } if ( _rangesMap.size() <= 0 ) { return false; } RangeMap::const_iterator it = _rangesMap.upper_bound( key ); if ( it != _rangesMap.begin() ) it--; bool good = rangeContains( it->first, it->second, key ); #ifdef _DEBUG // Logs if in debugging mode and the point doesn't belong here. if ( !good ) { log() << "bad: " << key << " " << it->first << " " << key.woCompare( it->first ) << " " << key.woCompare( it->second ) << endl; for ( RangeMap::const_iterator i = _rangesMap.begin(); i != _rangesMap.end(); ++i ) { log() << "\t" << i->first << "\t" << i->second << "\t" << endl; } } #endif return good; }
/** * Makes sure that all the ranges here no longer exist on disk but the merged range does */ void assertWrittenAsMerged(const vector<KeyRange>& ranges) { dumpServer(); BSONObj rangeMin; BSONObj rangeMax; DBDirectClient client(&_txn); // Ensure written for (vector<KeyRange>::const_iterator it = ranges.begin(); it != ranges.end(); ++it) { Query query(BSON(ChunkType::min(it->minKey) << ChunkType::max(it->maxKey) << ChunkType::shard(shardName()))); ASSERT(client.findOne(ChunkType::ConfigNS, query).isEmpty()); if (rangeMin.isEmpty() || rangeMin.woCompare(it->minKey) > 0) { rangeMin = it->minKey; } if (rangeMax.isEmpty() || rangeMax.woCompare(it->maxKey) < 0) { rangeMax = it->maxKey; } } Query query(BSON(ChunkType::min(rangeMin) << ChunkType::max(rangeMax) << ChunkType::shard(shardName()))); ASSERT(!client.findOne(ChunkType::ConfigNS, query).isEmpty()); }
bool CollectionManager::belongsToMe(const BSONObj& point) const { // For now, collections don't move. So if the collection is not sharded, assume // the documet ca be accessed. if (_key.isEmpty()) { return true; } dassert(_rangesMap.size() > 0); RangeMap::const_iterator it = _rangesMap.upper_bound(point); if (it != _rangesMap.begin()) it--; bool good = contains(it->first, it->second, point); // Logs if in debugging mode and the point doesn't belong here. if(dcompare(!good)) { log() << "bad: " << point << " " << it->first << " " << point.woCompare(it->first) << " " << point.woCompare(it->second) << endl; for (RangeMap::const_iterator i=_rangesMap.begin(); i!=_rangesMap.end(); ++i) { log() << "\t" << i->first << "\t" << i->second << "\t" << endl; } } return good; }
static void assertEquals( const BSONObj &a, const BSONObj &b ) { if ( a.woCompare( b ) != 0 ) { out() << "expected: " << a.toString() << ", got: " << b.toString() << endl; } ASSERT( a.woCompare( b ) == 0 ); }
TEST( selector, simple_default_test_6 ) { { INT32 rc = SDB_OK ; mthSelector selector ; BSONObj rule = BSON( "a.b" << BSON( "$default" << 1 ) ) ; rc = selector.loadPattern( rule ) ; ASSERT_EQ( SDB_OK , rc ) ; BSONObj record = BSON( "a" << 1 << "b" << 1) ; BSONObj result ; rc = selector.select( record, result ) ; ASSERT_EQ( SDB_OK , rc ) ; cout << result.toString( FALSE, TRUE ) << endl ; BSONObj expect = BSONObj() ; rc = expect.woCompare( result ) ; ASSERT_EQ( SDB_OK, rc ) ; } { INT32 rc = SDB_OK ; mthSelector selector ; BSONObj rule = BSON( "a.b" << 1 ) ; rc = selector.loadPattern( rule ) ; ASSERT_EQ( SDB_OK , rc ) ; BSONObj record = BSON( "a" << 1 << "b" << 1 ) ; BSONObj result ; rc = selector.select( record, result ) ; ASSERT_EQ( SDB_OK , rc ) ; cout << result.toString( FALSE, TRUE ) << endl ; BSONObj expect = BSONObj() ; rc = expect.woCompare( result ) ; ASSERT_EQ( SDB_OK, rc ) ; } }
void run() { testRegex(); BSONObjBuilder A,B,C; A.append("x", 2); B.append("x", 2.0); C.append("x", 2.1); BSONObj a = A.done(); BSONObj b = B.done(); BSONObj c = C.done(); assert( !a.woEqual( b ) ); // comments on operator== int cmp = a.woCompare(b); assert( cmp == 0 ); cmp = a.woCompare(c); assert( cmp < 0 ); testoid(); }
static bool areResponsesEqual( const BatchedCommandResponse& responseA, const BatchedCommandResponse& responseB ) { // TODO: Better reporting of why not equal if ( responseA.getOk() != responseB.getOk() ) return false; if ( responseA.getN() != responseB.getN() ) return false; if ( responseA.isSingleUpsertedSet() != responseB.isSingleUpsertedSet() ) return false; if ( responseA.isUpsertDetailsSet() != responseB.isUpsertDetailsSet() ) return false; if ( responseA.isSingleUpsertedSet() ) { BSONObj upsertA = responseA.getSingleUpserted(); BSONObj upsertB = responseB.getSingleUpserted(); if ( upsertA.woCompare( upsertB ) != 0 ) return false; } if ( responseA.isUpsertDetailsSet() ) { // TODO: } if ( responseA.getOk() ) return true; // TODO: Compare errors here return true; }
int ShardKeyPattern::compare( const BSONObj& lObject , const BSONObj& rObject ) const { BSONObj L = extractKey(lObject); uassert( 10198 , "left object doesn't have full shard key", L.nFields() == (int)patternfields.size()); BSONObj R = extractKey(rObject); uassert( 10199 , "right object doesn't have full shard key", R.nFields() == (int)patternfields.size()); return L.woCompare(R); }
void testRegex() { BSONObjBuilder b; b.appendRegex("x", "foo"); BSONObj o = b.done(); BSONObjBuilder c; c.appendRegex("x", "goo"); BSONObj p = c.done(); assert( !o.woEqual( p ) ); assert( o.woCompare( p ) < 0 ); { BSONObjBuilder b; b.appendRegex("r", "^foo"); BSONObj o = b.done(); assert( o.firstElement().simpleRegex() == "foo" ); } { BSONObjBuilder b; b.appendRegex("r", "^f?oo"); BSONObj o = b.done(); assert( o.firstElement().simpleRegex() == "" ); } { BSONObjBuilder b; b.appendRegex("r", "^fz?oo"); BSONObj o = b.done(); assert( o.firstElement().simpleRegex() == "f" ); } }
TEST(QueryRequestTest, ParseFromCommandCommentWithValidMinMax) { BSONObj cmdObj = fromjson( "{find: 'testns'," "comment: 'the comment'," "min: {a: 1}," "max: {a: 2}}"); const NamespaceString nss("test.testns"); bool isExplain = false; unique_ptr<QueryRequest> qr( assertGet(QueryRequest::makeFromFindCommand(nss, cmdObj, isExplain))); ASSERT_EQUALS("the comment", qr->getComment()); BSONObj expectedMin = BSON("a" << 1); ASSERT_EQUALS(0, expectedMin.woCompare(qr->getMin())); BSONObj expectedMax = BSON("a" << 2); ASSERT_EQUALS(0, expectedMax.woCompare(qr->getMax())); }
TEST(KeyStringTest, Timestamp) { BSONObj a = BSON("" << Timestamp(0, 0)); BSONObj b = BSON("" << Timestamp(1234, 1)); BSONObj c = BSON("" << Timestamp(1234, 2)); BSONObj d = BSON("" << Timestamp(1235, 1)); { ROUNDTRIP(a); ROUNDTRIP(b); ROUNDTRIP(c); ASSERT_LESS_THAN(a, b); ASSERT_LESS_THAN(b, c); ASSERT_LESS_THAN(c, d); KeyString ka(a, ALL_ASCENDING); KeyString kb(b, ALL_ASCENDING); KeyString kc(c, ALL_ASCENDING); KeyString kd(d, ALL_ASCENDING); ASSERT(ka.compare(kb) < 0); ASSERT(kb.compare(kc) < 0); ASSERT(kc.compare(kd) < 0); } { Ordering ALL_ASCENDING = Ordering::make(BSON("a" << -1)); ROUNDTRIP(a); ROUNDTRIP(b); ROUNDTRIP(c); ASSERT(d.woCompare(c, ALL_ASCENDING) < 0); ASSERT(c.woCompare(b, ALL_ASCENDING) < 0); ASSERT(b.woCompare(a, ALL_ASCENDING) < 0); KeyString ka(a, ALL_ASCENDING); KeyString kb(b, ALL_ASCENDING); KeyString kc(c, ALL_ASCENDING); KeyString kd(d, ALL_ASCENDING); ASSERT(ka.compare(kb) > 0); ASSERT(kb.compare(kc) > 0); ASSERT(kc.compare(kd) > 0); } }
int ShardKeyPattern::compare( const BSONObj& lObject , const BSONObj& rObject ) const { BSONObj L = extractKey(lObject); uassert( 10198 , str::stream() << "left object (" << lObject << ") doesn't have full shard key (" << pattern << ')', L.nFields() == (int)patternfields.size()); BSONObj R = extractKey(rObject); uassert( 10199 , str::stream() << "right object (" << rObject << ") doesn't have full shard key (" << pattern << ')', R.nFields() == (int)patternfields.size()); return L.woCompare(R); }
bool AsyncResultsMerger::MergingComparator::operator()(const size_t& lhs, const size_t& rhs) { const BSONObj& leftDoc = _remotes[lhs].docBuffer.front(); const BSONObj& rightDoc = _remotes[rhs].docBuffer.front(); BSONObj leftDocKey = leftDoc[ClusterClientCursorParams::kSortKeyField].Obj(); BSONObj rightDocKey = rightDoc[ClusterClientCursorParams::kSortKeyField].Obj(); return leftDocKey.woCompare(rightDocKey, _sort, false /*considerFieldName*/) > 0; }
bool AsyncResultsMerger::MergingComparator::operator()(const size_t& lhs, const size_t& rhs) { const BSONObj& leftDoc = _remotes[lhs].docBuffer.front(); const BSONObj& rightDoc = _remotes[rhs].docBuffer.front(); BSONObj leftDocKey = leftDoc[ClusterClientCursorParams::kSortKeyField].Obj(); BSONObj rightDocKey = rightDoc[ClusterClientCursorParams::kSortKeyField].Obj(); // This does not need to sort with a collator, since mongod has already mapped strings to their // ICU comparison keys as part of the $sortKey meta projection. return leftDocKey.woCompare(rightDocKey, _sort, false /*considerFieldName*/) > 0; }
void testRegex() { BSONObjBuilder b; b.appendRegex("x", "foo"); BSONObj o = b.done(); BSONObjBuilder c; c.appendRegex("x", "goo"); BSONObj p = c.done(); assert( !o.woEqual( p ) ); assert( o.woCompare( p ) < 0 ); }
void testbounds(){ BSONObj l , r; { BSONObjBuilder b; b.append( "x" , numeric_limits<long long>::max() ); l = b.obj(); } { BSONObjBuilder b; b.append( "x" , numeric_limits<double>::max() ); r = b.obj(); } assert( l.woCompare( r ) < 0 ); assert( r.woCompare( l ) > 0 ); { BSONObjBuilder b; b.append( "x" , numeric_limits<int>::max() ); l = b.obj(); } assert( l.woCompare( r ) < 0 ); assert( r.woCompare( l ) > 0 ); }
void BSONInfo::Functions::bsonWoCompare(JSContext* cx, JS::CallArgs args) { if (args.length() != 2) uasserted(ErrorCodes::BadValue, "bsonWoCompare needs 2 argument"); if (!args.get(0).isObject()) uasserted(ErrorCodes::BadValue, "first argument to bsonWoCompare must be an object"); if (!args.get(1).isObject()) uasserted(ErrorCodes::BadValue, "second argument to bsonWoCompare must be an object"); BSONObj firstObject = ValueWriter(cx, args.get(0)).toBSON(); BSONObj secondObject = ValueWriter(cx, args.get(1)).toBSON(); args.rval().setInt32(firstObject.woCompare(secondObject)); }
TEST( selector, simple_slice_test_8 ) { INT32 rc = SDB_OK ; mthSelector selector ; BSONObj rule = BSON( "a.b" << BSON( "$slice" << 1 ) ) ; rc = selector.loadPattern( rule ) ; ASSERT_EQ( SDB_OK , rc ) ; BSONObj record = BSON( "a" << BSON_ARRAY( BSON("b" << 1 ) << BSON( "b" << BSON_ARRAY( 1 << 2 << 3)) << BSON( "b" << BSON_ARRAY(4 << 5 << 6))<< BSON("b" << 1) ) << "b" << 1 ) ; BSONObj result ; rc = selector.select( record, result ) ; ASSERT_EQ( SDB_OK , rc ) ; cout << result.toString( FALSE, TRUE ) << endl ; BSONObj expect = BSON( "a" << BSON_ARRAY( BSON( "b" << 1) << BSON("b" << BSON_ARRAY( 1)) << BSON("b" << BSON_ARRAY(4)) << BSON("b" << 1) )<< "b" << 1 ) ; rc = expect.woCompare( result ) ; ASSERT_EQ( SDB_OK, rc ) ; }
TEST( selector, simple_elemmatch_test_3 ) { INT32 rc = SDB_OK ; mthSelector selector ; BSONObj rule = BSON( "a" << BSON( "$elemMatch" << BSON( "b" << 1 ) ) ) ; rc = selector.loadPattern( rule ) ; ASSERT_EQ( SDB_OK , rc ) ; BSONObj record = BSON( "a" << 1 << "b" << 2 ) ; BSONObj result ; rc = selector.select( record, result ) ; ASSERT_EQ( SDB_OK , rc ) ; cout << result.toString( FALSE, TRUE ) << endl ; BSONObj expect = BSON( "b" << 2 ) ; rc = expect.woCompare( result ) ; ASSERT_EQ( SDB_OK, rc ) ; }
TEST( selector, simple_include_test_6 ) { INT32 rc = SDB_OK ; mthSelector selector ; BSONObj rule = BSON( "a.b" << BSON( "$include" << 1 ) ) ; rc = selector.loadPattern( rule ) ; ASSERT_EQ( SDB_OK , rc ) ; BSONObj record = BSON( "a" << BSON_ARRAY( BSON( "c" << 1) << BSON("d" << 1) << BSON("b"<< 1) << BSON("b" << 2)) ) ; BSONObj result ; rc = selector.select( record, result ) ; ASSERT_EQ( SDB_OK , rc ) ; cout << result.toString( FALSE, TRUE ) << endl ; BSONObj expect = BSON( "a" << BSON_ARRAY(BSONObj() << BSONObj() <<BSON("b" << 1) << BSON("b" << 2))) ; rc = expect.woCompare( result ) ; ASSERT_EQ( SDB_OK, rc ) ; }
// TODO: We should really update this to be an ASSERT_ something, so that we can print out // the expected and actual documents. bool checkDoc(const Document& lhs, const BSONObj& rhs) { // Get the fundamental result via BSONObj's woCompare path. This is the best starting // point, because we think that Document::getObject and the serialization mechanism is // pretty well sorted. BSONObj fromLhs = lhs.getObject(); const int primaryResult = fromLhs.woCompare(rhs); // Validate primary result via other comparison paths. const int secondaryResult = lhs.compareWithBSONObj(rhs, nullptr); assertSameSign(primaryResult, secondaryResult); // Check that mutables serialized result matches against its origin. ASSERT_EQUALS(0, lhs.compareWithBSONObj(fromLhs, nullptr)); return (primaryResult == 0); }
DiskLoc BtreeBasedAccessMethod::findSingle(const BSONObj& key) const { boost::scoped_ptr<BtreeInterface::Cursor> cursor(_newInterface->newCursor(1)); cursor->locate(key, minDiskLoc); // A null bucket means the key wasn't found (nor was anything found after it). if (cursor->isEOF()) { return DiskLoc(); } // We found something but it could be a key after 'key'. Examine what we're pointing at. if (0 != key.woCompare(cursor->getKey(), BSONObj(), false)) { // If the keys don't match, return "not found." return DiskLoc(); } // Return the DiskLoc found. return cursor->getDiskLoc(); }
bool ShardChunkManager::_belongsToMe( const BSONObj& x ) const { RangeMap::const_iterator it = _rangesMap.upper_bound( x ); if ( it != _rangesMap.begin() ) it--; bool good = contains( it->first , it->second , x ); #if 0 if ( ! good ) { log() << "bad: " << x << " " << it->first << " " << x.woCompare( it->first ) << " " << x.woCompare( it->second ) << endl; for ( RangeMap::const_iterator i=_rangesMap.begin(); i!=_rangesMap.end(); ++i ) { log() << "\t" << i->first << "\t" << i->second << "\t" << endl; } } #endif return good; }
RecordId IndexAccessMethod::findSingle(OperationContext* txn, const BSONObj& key) const { boost::scoped_ptr<SortedDataInterface::Cursor> cursor(_newInterface->newCursor(txn, 1)); cursor->locate(key, RecordId::min()); // A null bucket means the key wasn't found (nor was anything found after it). if (cursor->isEOF()) { return RecordId(); } // We found something but it could be a key after 'key'. Examine what we're pointing at. if (0 != key.woCompare(cursor->getKey(), BSONObj(), false)) { // If the keys don't match, return "not found." return RecordId(); } // Return the RecordId found. return cursor->getRecordId(); }
/** * "Finishes" the max object for the $max query option by filling in an empty object with * MinKey/MaxKey and stripping field names. * * See comment for finishMinObj() for why we need both 'minObj' and 'maxObj'. */ static BSONObj finishMaxObj(const BSONObj& kp, const BSONObj& minObj, const BSONObj& maxObj) { BSONObjBuilder bob; bob.appendMaxKey(""); BSONObj maxKey = bob.obj(); if (maxObj.isEmpty()) { if (0 < maxKey.woCompare(minObj, kp, false)) { BSONObjBuilder maxKeyBuilder; maxKeyBuilder.appendMaxKey(""); return maxKeyBuilder.obj(); } else { BSONObjBuilder minKeyBuilder; minKeyBuilder.appendMinKey(""); return minKeyBuilder.obj(); } } else { return stripFieldNames(maxObj); } }
DiskLoc BtreeBasedAccessMethod::findSingle(const BSONObj& key) const { DiskLoc bucket; int pos; _newInterface->locate(key, minDiskLoc, 1, &bucket, &pos); // A null bucket means the key wasn't found (nor was anything found after it). if (bucket.isNull()) { return DiskLoc(); } // We found something but it could be a key after 'key'. Examine what we're pointing at. if (0 != key.woCompare(_newInterface->getKey(bucket, pos), BSONObj(), false)) { // If the keys don't match, return "not found." return DiskLoc(); } // Return the DiskLoc found. return _newInterface->getDiskLoc(bucket, pos); }
unique_ptr<CollectionMetadata> CollectionMetadata::clonePlusChunk( const BSONObj& minKey, const BSONObj& maxKey, const ChunkVersion& newShardVersion) const { invariant(newShardVersion.epoch() == _shardVersion.epoch()); invariant(newShardVersion.isSet()); invariant(minKey.woCompare(maxKey) < 0); invariant(!rangeMapOverlaps(_chunksMap, minKey, maxKey)); unique_ptr<CollectionMetadata> metadata(stdx::make_unique<CollectionMetadata>()); metadata->_keyPattern = _keyPattern.getOwned(); metadata->fillKeyPatternFields(); metadata->_pendingMap = _pendingMap; metadata->_chunksMap = _chunksMap; metadata->_chunksMap.insert(make_pair(minKey.getOwned(), maxKey.getOwned())); metadata->_shardVersion = newShardVersion; metadata->_collVersion = newShardVersion > _collVersion ? newShardVersion : _collVersion; metadata->fillRanges(); invariant(metadata->isValid()); return metadata; }
/** * "Finishes" the max object for the $max query option by filling in an empty object with * MinKey/MaxKey and stripping field names. Also translates keys according to the collation, if * necessary. * * See comment for finishMinObj() for why we need both 'minObj' and 'maxObj'. */ static BSONObj finishMaxObj(const IndexEntry& indexEntry, const BSONObj& minObj, const BSONObj& maxObj) { BSONObjBuilder bob; bob.appendMaxKey(""); BSONObj maxKey = bob.obj(); if (maxObj.isEmpty()) { if (0 < maxKey.woCompare(minObj, indexEntry.keyPattern, false)) { BSONObjBuilder maxKeyBuilder; maxKeyBuilder.appendMaxKey(""); return maxKeyBuilder.obj(); } else { BSONObjBuilder minKeyBuilder; minKeyBuilder.appendMinKey(""); return minKeyBuilder.obj(); } } else { return stripFieldNamesAndApplyCollation(maxObj, indexEntry.collator); } }
uint64_t CollectionShardingState::_incrementChunkOnInsertOrUpdate(OperationContext* opCtx, const BSONObj& document, long dataWritten) { // Here, get the collection metadata and check if it exists. If it doesn't exist, then the // collection is not sharded, and we can simply return -1. ScopedCollectionMetadata metadata = getMetadata(); if (!metadata) { return -1; } std::shared_ptr<ChunkManager> cm = metadata->getChunkManager(); const ShardKeyPattern& shardKeyPattern = cm->getShardKeyPattern(); // Each inserted/updated document should contain the shard key. The only instance in which a // document could not contain a shard key is if the insert/update is performed through mongod // explicitly, as opposed to first routed through mongos. BSONObj shardKey = shardKeyPattern.extractShardKeyFromDoc(document); if (shardKey.woCompare(BSONObj()) == 0) { warning() << "inserting document " << document.toString() << " without shard key pattern " << shardKeyPattern << " into a sharded collection"; return -1; } // Use the shard key to locate the chunk into which the document was updated, and increment the // number of bytes tracked for the chunk. Note that we can assume the simple collation, because // shard keys do not support non-simple collations. std::shared_ptr<Chunk> chunk = cm->findIntersectingChunkWithSimpleCollation(shardKey); invariant(chunk); chunk->addBytesWritten(dataWritten); // If the chunk becomes too large, then we call the ChunkSplitter to schedule a split. Then, we // reset the tracking for that chunk to 0. if (_shouldSplitChunk(opCtx, shardKeyPattern, *chunk)) { // TODO: call ChunkSplitter here chunk->clearBytesWritten(); } return chunk->getBytesWritten(); }
TEST(QueryRequestTest, ParseFromCommandAllNonOptionFields) { BSONObj cmdObj = fromjson( "{find: 'testns'," "filter: {a: 1}," "sort: {b: 1}," "projection: {c: 1}," "hint: {d: 1}," "readConcern: {e: 1}," "$queryOptions: {$readPreference: 'secondary'}," "collation: {f: 1}," "limit: 3," "skip: 5," "batchSize: 90," "singleBatch: false}"); const NamespaceString nss("test.testns"); bool isExplain = false; unique_ptr<QueryRequest> qr( assertGet(QueryRequest::makeFromFindCommand(nss, cmdObj, isExplain))); // Check the values inside the QR. BSONObj expectedQuery = BSON("a" << 1); ASSERT_EQUALS(0, expectedQuery.woCompare(qr->getFilter())); BSONObj expectedSort = BSON("b" << 1); ASSERT_EQUALS(0, expectedSort.woCompare(qr->getSort())); BSONObj expectedProj = BSON("c" << 1); ASSERT_EQUALS(0, expectedProj.woCompare(qr->getProj())); BSONObj expectedHint = BSON("d" << 1); ASSERT_EQUALS(0, expectedHint.woCompare(qr->getHint())); BSONObj expectedReadConcern = BSON("e" << 1); ASSERT_EQUALS(0, expectedReadConcern.woCompare(qr->getReadConcern())); BSONObj expectedUnwrappedReadPref = BSON("$readPreference" << "secondary"); ASSERT_EQUALS(0, expectedUnwrappedReadPref.woCompare(qr->getUnwrappedReadPref())); BSONObj expectedCollation = BSON("f" << 1); ASSERT_EQUALS(0, expectedCollation.woCompare(qr->getCollation())); ASSERT_EQUALS(3, *qr->getLimit()); ASSERT_EQUALS(5, *qr->getSkip()); ASSERT_EQUALS(90, *qr->getBatchSize()); ASSERT(qr->wantMore()); }