diff options
Diffstat (limited to 's/shardkey.cpp')
-rw-r--r-- | s/shardkey.cpp | 152 |
1 files changed, 130 insertions, 22 deletions
diff --git a/s/shardkey.cpp b/s/shardkey.cpp index e4deeec..84cdb4b 100644 --- a/s/shardkey.cpp +++ b/s/shardkey.cpp @@ -20,6 +20,7 @@ #include "chunk.h" #include "../db/jsobj.h" #include "../util/unittest.h" +#include "../util/timer.h" namespace mongo { @@ -30,12 +31,12 @@ namespace mongo { BSONObjBuilder max; BSONObjIterator it(p); - while (it.more()){ + while (it.more()) { BSONElement e (it.next()); min.appendMinKey(e.fieldName()); max.appendMaxKey(e.fieldName()); } - + gMin = min.obj(); gMax = max.obj(); } @@ -49,11 +50,11 @@ namespace mongo { } bool ShardKeyPattern::hasShardKey( const BSONObj& obj ) const { - /* this is written s.t. if obj has lots of fields, if the shard key fields are early, + /* this is written s.t. if obj has lots of fields, if the shard key fields are early, it is fast. so a bit more work to try to be semi-fast. */ - for(set<string>::const_iterator it = patternfields.begin(); it != patternfields.end(); ++it){ + for(set<string>::const_iterator it = patternfields.begin(); it != patternfields.end(); ++it) { if(obj.getFieldDotted(it->c_str()).eoo()) return false; } @@ -63,28 +64,90 @@ namespace mongo { bool ShardKeyPattern::isPrefixOf( const BSONObj& otherPattern ) const { BSONObjIterator a( pattern ); BSONObjIterator b( otherPattern ); - - while ( a.more() && b.more() ){ + + while ( a.more() && b.more() ) { BSONElement x = a.next(); BSONElement y = b.next(); if ( strcmp( x.fieldName() , y.fieldName() ) ) return false; } - + return ! a.more(); } - + string ShardKeyPattern::toString() const { return pattern.toString(); } - - /* things to test for compound : + + BSONObj ShardKeyPattern::moveToFront(const BSONObj& obj) const { + vector<const char*> keysToMove; + keysToMove.push_back("_id"); + BSONForEach(e, pattern) { + if (strchr(e.fieldName(), '.') == NULL) + keysToMove.push_back(e.fieldName()); + } + + if (keysToMove.size() == 1) { + return obj; + + } + else { + BufBuilder buf (obj.objsize()); + buf.appendNum(obj.objsize()); + + vector<pair<const char*, size_t> > copies; + pair<const char*, size_t> toCopy ((const char*)NULL, 0); // C++ NULL isn't a pointer type yet + + BSONForEach(e, obj) { + bool moveToFront = false; + for (vector<const char*>::const_iterator it(keysToMove.begin()), end(keysToMove.end()); it!=end; ++it) { + if (strcmp(e.fieldName(), *it) == 0) { + moveToFront = true; + break; + } + } + + if (moveToFront) { + buf.appendBuf(e.fieldName()-1, e.size()); + if (toCopy.first) { + copies.push_back(toCopy); + toCopy.first = NULL; + } + } + else { + if (!toCopy.first) { + toCopy.first = e.fieldName()-1; + toCopy.second = e.size(); + } + else { + toCopy.second += e.size(); + } + } + } + + for (vector<pair<const char*, size_t> >::const_iterator it(copies.begin()), end(copies.end()); it!=end; ++it) { + buf.appendBuf(it->first, it->second); + } + + if (toCopy.first) { + buf.appendBuf(toCopy.first, toCopy.second); + } + + buf.appendChar('\0'); + + BSONObj out (buf.buf(), true); + buf.decouple(); + return out; + } + } + + /* things to test for compound : \ middle (deprecating?) */ class ShardKeyUnitTest : public UnitTest { public: - - void testIsPrefixOf(){ + + void testIsPrefixOf() { { ShardKeyPattern k( BSON( "x" << 1 ) ); assert( ! k.isPrefixOf( BSON( "a" << 1 ) ) ); @@ -92,7 +155,7 @@ namespace mongo { assert( k.isPrefixOf( BSON( "x" << 1 << "a" << 1 ) ) ); assert( ! k.isPrefixOf( BSON( "a" << 1 << "x" << 1 ) ) ); } - { + { ShardKeyPattern k( BSON( "x" << 1 << "y" << 1 ) ); assert( ! k.isPrefixOf( BSON( "x" << 1 ) ) ); assert( ! k.isPrefixOf( BSON( "x" << 1 << "z" << 1 ) ) ); @@ -100,8 +163,8 @@ namespace mongo { assert( k.isPrefixOf( BSON( "x" << 1 << "y" << 1 << "z" << 1 ) ) ); } } - - void hasshardkeytest() { + + void hasshardkeytest() { BSONObj x = fromjson("{ zid : \"abcdefg\", num: 1.0, name: \"eliot\" }"); ShardKeyPattern k( BSON( "num" << 1 ) ); assert( k.hasShardKey(x) ); @@ -117,31 +180,68 @@ namespace mongo { } - void extractkeytest() { + void extractkeytest() { ShardKeyPattern k( fromjson("{a:1,'sub.b':-1,'sub.c':1}") ); BSONObj x = fromjson("{a:1,'sub.b':2,'sub.c':3}"); assert( k.extractKey( fromjson("{a:1,sub:{b:2,c:3}}") ).woEqual(x) ); assert( k.extractKey( fromjson("{sub:{b:2,c:3},a:1}") ).woEqual(x) ); } - void run(){ + void moveToFrontTest() { + ShardKeyPattern sk (BSON("a" << 1 << "b" << 1)); + + BSONObj ret; + + ret = sk.moveToFront(BSON("z" << 1 << "_id" << 1 << "y" << 1 << "a" << 1 << "x" << 1 << "b" << 1 << "w" << 1)); + assert(ret.woEqual(BSON("_id" << 1 << "a" << 1 << "b" << 1 << "z" << 1 << "y" << 1 << "x" << 1 << "w" << 1))); + + ret = sk.moveToFront(BSON("_id" << 1 << "a" << 1 << "b" << 1 << "z" << 1 << "y" << 1 << "x" << 1 << "w" << 1)); + assert(ret.woEqual(BSON("_id" << 1 << "a" << 1 << "b" << 1 << "z" << 1 << "y" << 1 << "x" << 1 << "w" << 1))); + + ret = sk.moveToFront(BSON("z" << 1 << "y" << 1 << "a" << 1 << "b" << 1 << "Z" << 1 << "Y" << 1)); + assert(ret.woEqual(BSON("a" << 1 << "b" << 1 << "z" << 1 << "y" << 1 << "Z" << 1 << "Y" << 1))); + + } + + void moveToFrontBenchmark(int numFields) { + BSONObjBuilder bb; + bb.append("_id", 1); + for (int i=0; i < numFields; i++) + bb.append(BSONObjBuilder::numStr(i), 1); + bb.append("key", 1); + BSONObj o = bb.obj(); + + ShardKeyPattern sk (BSON("key" << 1)); + + Timer t; + const int iterations = 100*1000; + for (int i=0; i< iterations; i++) { + sk.moveToFront(o); + } + + const double secs = t.micros() / 1000000.0; + const double ops_per_sec = iterations / secs; + + cout << "moveToFront (" << numFields << " fields) secs: " << secs << " ops_per_sec: " << ops_per_sec << endl; + } + void run() { extractkeytest(); ShardKeyPattern k( BSON( "key" << 1 ) ); - + BSONObj min = k.globalMin(); // cout << min.jsonString(TenGen) << endl; BSONObj max = k.globalMax(); - + BSONObj k1 = BSON( "key" << 5 ); assert( k.compare( min , max ) < 0 ); assert( k.compare( min , k1 ) < 0 ); assert( k.compare( max , min ) > 0 ); assert( k.compare( min , min ) == 0 ); - + hasshardkeytest(); assert( k.hasShardKey( k1 ) ); assert( ! k.hasShardKey( BSON( "key2" << 1 ) ) ); @@ -150,12 +250,20 @@ namespace mongo { BSONObj b = BSON( "key" << 999 ); assert( k.compare(a,b) < 0 ); - + testIsPrefixOf(); // add middle multitype tests + moveToFrontTest(); + + if (0) { // toggle to run benchmark + moveToFrontBenchmark(0); + moveToFrontBenchmark(10); + moveToFrontBenchmark(100); + } + log(1) << "shardKeyTest passed" << endl; } } shardKeyTest; - + } // namespace mongo |