diff options
Diffstat (limited to 'src/mongo/db/storage/mmap_v1/btree/key.cpp')
-rw-r--r-- | src/mongo/db/storage/mmap_v1/btree/key.cpp | 1040 |
1 files changed, 524 insertions, 516 deletions
diff --git a/src/mongo/db/storage/mmap_v1/btree/key.cpp b/src/mongo/db/storage/mmap_v1/btree/key.cpp index 5cc1afbdc69..cbb89d8fab9 100644 --- a/src/mongo/db/storage/mmap_v1/btree/key.cpp +++ b/src/mongo/db/storage/mmap_v1/btree/key.cpp @@ -39,26 +39,26 @@ namespace mongo { - using std::endl; - using std::numeric_limits; - using std::min; +using std::endl; +using std::numeric_limits; +using std::min; - extern const Ordering nullOrdering = Ordering::make(BSONObj()); +extern const Ordering nullOrdering = Ordering::make(BSONObj()); - // KeyBson is for V0 (version #0) indexes +// KeyBson is for V0 (version #0) indexes - int oldCompare(const BSONObj& l,const BSONObj& r, const Ordering &o); +int oldCompare(const BSONObj& l, const BSONObj& r, const Ordering& o); - // "old" = pre signed dates & such; i.e. btree V0 - /* must be same canon type when called */ - int oldCompareElementValues(const BSONElement& l, const BSONElement& r) { - dassert( l.canonicalType() == r.canonicalType() ); - int f; - double x; +// "old" = pre signed dates & such; i.e. btree V0 +/* must be same canon type when called */ +int oldCompareElementValues(const BSONElement& l, const BSONElement& r) { + dassert(l.canonicalType() == r.canonicalType()); + int f; + double x; - switch ( l.type() ) { + switch (l.type()) { case EOO: - case Undefined: // EOO and Undefined are same canonicalType + case Undefined: // EOO and Undefined are same canonicalType case jstNULL: case MaxKey: case MinKey: @@ -75,35 +75,36 @@ namespace mongo { return lULL == rULL ? 0 : 1; } case NumberLong: - if( r.type() == NumberLong ) { + if (r.type() == NumberLong) { long long L = l._numberLong(); long long R = r._numberLong(); - if( L < R ) return -1; - if( L == R ) return 0; + if (L < R) + return -1; + if (L == R) + return 0; return 1; } - // else fall through + // else fall through case NumberInt: case NumberDouble: { double left = l.number(); double right = r.number(); - bool lNan = !( left <= numeric_limits< double >::max() && - left >= -numeric_limits< double >::max() ); - bool rNan = !( right <= numeric_limits< double >::max() && - right >= -numeric_limits< double >::max() ); - if ( lNan ) { - if ( rNan ) { + bool lNan = + !(left <= numeric_limits<double>::max() && left >= -numeric_limits<double>::max()); + bool rNan = !(right <= numeric_limits<double>::max() && + right >= -numeric_limits<double>::max()); + if (lNan) { + if (rNan) { return 0; - } - else { + } else { return -1; } - } - else if ( rNan ) { + } else if (rNan) { return 1; } x = left - right; - if ( x < 0 ) return -1; + if (x < 0) + return -1; return x == 0 ? 0 : 1; } case jstOID: @@ -119,562 +120,569 @@ namespace mongo { case DBRef: { int lsz = l.valuesize(); int rsz = r.valuesize(); - if ( lsz - rsz != 0 ) return lsz - rsz; + if (lsz - rsz != 0) + return lsz - rsz; return memcmp(l.value(), r.value(), lsz); } case BinData: { - int lsz = l.objsize(); // our bin data size in bytes, not including the subtype byte + int lsz = l.objsize(); // our bin data size in bytes, not including the subtype byte int rsz = r.objsize(); - if ( lsz - rsz != 0 ) return lsz - rsz; - return memcmp(l.value()+4, r.value()+4, lsz+1); + if (lsz - rsz != 0) + return lsz - rsz; + return memcmp(l.value() + 4, r.value() + 4, lsz + 1); } case RegEx: { int c = strcmp(l.regex(), r.regex()); - if ( c ) + if (c) return c; return strcmp(l.regexFlags(), r.regexFlags()); } - case CodeWScope : { + case CodeWScope: { f = l.canonicalType() - r.canonicalType(); - if ( f ) + if (f) return f; - f = strcmp( l.codeWScopeCode() , r.codeWScopeCode() ); - if ( f ) + f = strcmp(l.codeWScopeCode(), r.codeWScopeCode()); + if (f) return f; - f = strcmp( l.codeWScopeScopeDataUnsafe() , r.codeWScopeScopeDataUnsafe() ); - if ( f ) + f = strcmp(l.codeWScopeScopeDataUnsafe(), r.codeWScopeScopeDataUnsafe()); + if (f) return f; return 0; } default: - log() << "oldCompareElementValues: bad type " << (int) l.type() << endl; + log() << "oldCompareElementValues: bad type " << (int)l.type() << endl; verify(false); - } - return -1; - } - - int oldElemCompare(const BSONElement&l , const BSONElement& r) { - int lt = (int) l.canonicalType(); - int rt = (int) r.canonicalType(); - int x = lt - rt; - if( x ) - return x; - return oldCompareElementValues(l, r); } - - // pre signed dates & such - int oldCompare(const BSONObj& l,const BSONObj& r, const Ordering &o) { - BSONObjIterator i(l); - BSONObjIterator j(r); - unsigned mask = 1; - while ( 1 ) { - // so far, equal... - - BSONElement l = i.next(); - BSONElement r = j.next(); - if ( l.eoo() ) - return r.eoo() ? 0 : -1; - if ( r.eoo() ) - return 1; - - int x; - { - x = oldElemCompare(l, r); - if( o.descending(mask) ) - x = -x; - } - if ( x != 0 ) - return x; - mask <<= 1; + return -1; +} + +int oldElemCompare(const BSONElement& l, const BSONElement& r) { + int lt = (int)l.canonicalType(); + int rt = (int)r.canonicalType(); + int x = lt - rt; + if (x) + return x; + return oldCompareElementValues(l, r); +} + +// pre signed dates & such +int oldCompare(const BSONObj& l, const BSONObj& r, const Ordering& o) { + BSONObjIterator i(l); + BSONObjIterator j(r); + unsigned mask = 1; + while (1) { + // so far, equal... + + BSONElement l = i.next(); + BSONElement r = j.next(); + if (l.eoo()) + return r.eoo() ? 0 : -1; + if (r.eoo()) + return 1; + + int x; + { + x = oldElemCompare(l, r); + if (o.descending(mask)) + x = -x; } - return -1; - } - - /* old style compares: - - dates are unsigned - - strings no nulls - */ - int KeyBson::woCompare(const KeyBson& r, const Ordering &o) const { - return oldCompare(_o, r._o, o); - } - - // woEqual could be made faster than woCompare but this is for backward compatibility so not worth a big effort - bool KeyBson::woEqual(const KeyBson& r) const { - return oldCompare(_o, r._o, nullOrdering) == 0; - } - - // [ ][HASMORE][x][y][canontype_4bits] - enum CanonicalsEtc { - cminkey=1, - cnull=2, - cdouble=4, - cstring=6, - cbindata=7, - coid=8, - cfalse=10, - ctrue=11, - cdate=12, - cmaxkey=14, - cCANONTYPEMASK = 0xf, - cY = 0x10, - cint = cY | cdouble, - cX = 0x20, - clong = cX | cdouble, - cHASMORE = 0x40, - cNOTUSED = 0x80 // but see IsBSON sentinel - this bit not usable without great care - }; - - // bindata bson type - const unsigned BinDataLenMask = 0xf0; // lengths are powers of 2 of this value - const unsigned BinDataTypeMask = 0x0f; // 0-7 as you would expect, 8-15 are 128+value. see BinDataType. - const int BinDataLenMax = 32; - const int BinDataLengthToCode[] = { - 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, - 0x80, -1/*9*/, 0x90/*10*/, -1/*11*/, 0xa0/*12*/, -1/*13*/, 0xb0/*14*/, -1/*15*/, - 0xc0/*16*/, -1, -1, -1, 0xd0/*20*/, -1, -1, -1, - 0xe0/*24*/, -1, -1, -1, -1, -1, -1, -1, - 0xf0/*32*/ - }; - const int BinDataCodeToLength[] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 32 - }; - - int binDataCodeToLength(int codeByte) { - return BinDataCodeToLength[codeByte >> 4]; - } - - /** object cannot be represented in compact format. so store in traditional bson format - with a leading sentinel byte IsBSON to indicate it's in that format. - - Given that the KeyV1Owned constructor already grabbed a bufbuilder, we reuse it here - so that we don't have to do an extra malloc. - */ - void KeyV1Owned::traditional(const BSONObj& obj) { - b.reset(); - b.appendUChar(IsBSON); - b.appendBuf(obj.objdata(), obj.objsize()); - _keyData = (const unsigned char *) b.buf(); - } - - KeyV1Owned::KeyV1Owned(const KeyV1& rhs) { - b.appendBuf( rhs.data(), rhs.dataSize() ); - _keyData = (const unsigned char *) b.buf(); - dassert( b.len() == dataSize() ); // check datasize method is correct - dassert( (*_keyData & cNOTUSED) == 0 ); + if (x != 0) + return x; + mask <<= 1; } - - // fromBSON to Key format - KeyV1Owned::KeyV1Owned(const BSONObj& obj) { - BSONObj::iterator i(obj); - unsigned char bits = 0; - while( 1 ) { - BSONElement e = i.next(); - if( i.more() ) - bits |= cHASMORE; - switch( e.type() ) { + return -1; +} + +/* old style compares: + - dates are unsigned + - strings no nulls +*/ +int KeyBson::woCompare(const KeyBson& r, const Ordering& o) const { + return oldCompare(_o, r._o, o); +} + +// woEqual could be made faster than woCompare but this is for backward compatibility so not worth a big effort +bool KeyBson::woEqual(const KeyBson& r) const { + return oldCompare(_o, r._o, nullOrdering) == 0; +} + +// [ ][HASMORE][x][y][canontype_4bits] +enum CanonicalsEtc { + cminkey = 1, + cnull = 2, + cdouble = 4, + cstring = 6, + cbindata = 7, + coid = 8, + cfalse = 10, + ctrue = 11, + cdate = 12, + cmaxkey = 14, + cCANONTYPEMASK = 0xf, + cY = 0x10, + cint = cY | cdouble, + cX = 0x20, + clong = cX | cdouble, + cHASMORE = 0x40, + cNOTUSED = 0x80 // but see IsBSON sentinel - this bit not usable without great care +}; + +// bindata bson type +const unsigned BinDataLenMask = 0xf0; // lengths are powers of 2 of this value +const unsigned BinDataTypeMask = + 0x0f; // 0-7 as you would expect, 8-15 are 128+value. see BinDataType. +const int BinDataLenMax = 32; +const int BinDataLengthToCode[] = { + 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, + 0x70, 0x80, -1 /*9*/, 0x90 /*10*/, -1 /*11*/, 0xa0 /*12*/, -1 /*13*/, + 0xb0 /*14*/, -1 /*15*/, 0xc0 /*16*/, -1, -1, -1, 0xd0 /*20*/, + -1, -1, -1, 0xe0 /*24*/, -1, -1, -1, + -1, -1, -1, -1, 0xf0 /*32*/ +}; +const int BinDataCodeToLength[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 32}; + +int binDataCodeToLength(int codeByte) { + return BinDataCodeToLength[codeByte >> 4]; +} + +/** object cannot be represented in compact format. so store in traditional bson format + with a leading sentinel byte IsBSON to indicate it's in that format. + + Given that the KeyV1Owned constructor already grabbed a bufbuilder, we reuse it here + so that we don't have to do an extra malloc. +*/ +void KeyV1Owned::traditional(const BSONObj& obj) { + b.reset(); + b.appendUChar(IsBSON); + b.appendBuf(obj.objdata(), obj.objsize()); + _keyData = (const unsigned char*)b.buf(); +} + +KeyV1Owned::KeyV1Owned(const KeyV1& rhs) { + b.appendBuf(rhs.data(), rhs.dataSize()); + _keyData = (const unsigned char*)b.buf(); + dassert(b.len() == dataSize()); // check datasize method is correct + dassert((*_keyData & cNOTUSED) == 0); +} + +// fromBSON to Key format +KeyV1Owned::KeyV1Owned(const BSONObj& obj) { + BSONObj::iterator i(obj); + unsigned char bits = 0; + while (1) { + BSONElement e = i.next(); + if (i.more()) + bits |= cHASMORE; + switch (e.type()) { case MinKey: - b.appendUChar(cminkey|bits); + b.appendUChar(cminkey | bits); break; case jstNULL: - b.appendUChar(cnull|bits); + b.appendUChar(cnull | bits); break; case MaxKey: - b.appendUChar(cmaxkey|bits); + b.appendUChar(cmaxkey | bits); break; case Bool: - b.appendUChar( (e.boolean()?ctrue:cfalse) | bits ); + b.appendUChar((e.boolean() ? ctrue : cfalse) | bits); break; case jstOID: - b.appendUChar(coid|bits); + b.appendUChar(coid | bits); b.appendBuf(e.__oid().view().view(), OID::kOIDSize); break; - case BinData: - { - int t = e.binDataType(); - // 0-7 and 0x80 to 0x87 are supported by Key - if( (t & 0x78) == 0 && t != ByteArrayDeprecated ) { - int len; - const char * d = e.binData(len); - if( len <= BinDataLenMax ) { - int code = BinDataLengthToCode[len]; - if( code >= 0 ) { - if( t >= 128 ) - t = (t-128) | 0x08; - dassert( (code&t) == 0 ); - b.appendUChar( cbindata|bits ); - b.appendUChar( code | t ); - b.appendBuf(d, len); - break; - } + case BinData: { + int t = e.binDataType(); + // 0-7 and 0x80 to 0x87 are supported by Key + if ((t & 0x78) == 0 && t != ByteArrayDeprecated) { + int len; + const char* d = e.binData(len); + if (len <= BinDataLenMax) { + int code = BinDataLengthToCode[len]; + if (code >= 0) { + if (t >= 128) + t = (t - 128) | 0x08; + dassert((code & t) == 0); + b.appendUChar(cbindata | bits); + b.appendUChar(code | t); + b.appendBuf(d, len); + break; } } - traditional(obj); - return; } + traditional(obj); + return; + } case Date: - b.appendUChar(cdate|bits); + b.appendUChar(cdate | bits); b.appendStruct(e.date()); break; - case String: - { - b.appendUChar(cstring|bits); - // note we do not store the terminating null, to save space. - unsigned x = (unsigned) e.valuestrsize() - 1; - if( x > 255 ) { - traditional(obj); - return; - } - b.appendUChar(x); - b.appendBuf(e.valuestr(), x); - break; + case String: { + b.appendUChar(cstring | bits); + // note we do not store the terminating null, to save space. + unsigned x = (unsigned)e.valuestrsize() - 1; + if (x > 255) { + traditional(obj); + return; } + b.appendUChar(x); + b.appendBuf(e.valuestr(), x); + break; + } case NumberInt: - b.appendUChar(cint|bits); - b.appendNum((double) e._numberInt()); + b.appendUChar(cint | bits); + b.appendNum((double)e._numberInt()); break; - case NumberLong: - { - long long n = e._numberLong(); - long long m = 2LL << 52; - DEV { - long long d = m-1; - verify( ((long long) ((double) -d)) == -d ); - } - if( n >= m || n <= -m ) { - // can't represent exactly as a double - traditional(obj); - return; - } - b.appendUChar(clong|bits); - b.appendNum((double) n); - break; + case NumberLong: { + long long n = e._numberLong(); + long long m = 2LL << 52; + DEV { + long long d = m - 1; + verify(((long long)((double)-d)) == -d); } - case NumberDouble: - { - double d = e._numberDouble(); - if( std::isnan(d) ) { - traditional(obj); - return; - } - b.appendUChar(cdouble|bits); - b.appendNum(d); - break; + if (n >= m || n <= -m) { + // can't represent exactly as a double + traditional(obj); + return; + } + b.appendUChar(clong | bits); + b.appendNum((double)n); + break; + } + case NumberDouble: { + double d = e._numberDouble(); + if (std::isnan(d)) { + traditional(obj); + return; } + b.appendUChar(cdouble | bits); + b.appendNum(d); + break; + } default: // if other types involved, store as traditional BSON traditional(obj); return; - } - if( !i.more() ) - break; - bits = 0; } - _keyData = (const unsigned char *) b.buf(); - dassert( b.len() == dataSize() ); // check datasize method is correct - dassert( (*_keyData & cNOTUSED) == 0 ); + if (!i.more()) + break; + bits = 0; } - - BSONObj KeyV1::toBson() const { - verify( _keyData != 0 ); - if( !isCompactFormat() ) - return bson(); - - BSONObjBuilder b(512); - const unsigned char *p = _keyData; - while( 1 ) { - unsigned bits = *p++; - - switch( bits & 0x3f ) { - case cminkey: b.appendMinKey(""); break; - case cnull: b.appendNull(""); break; - case cfalse: b.appendBool("", false); break; - case ctrue: b.appendBool("", true); break; - case cmaxkey: - b.appendMaxKey(""); - break; - case cstring: - { - unsigned sz = *p++; - // we build the element ourself as we have to null terminate it - BufBuilder &bb = b.bb(); - bb.appendNum((char) String); - bb.appendUChar(0); // fieldname "" - bb.appendNum(sz+1); - bb.appendBuf(p, sz); - bb.appendUChar(0); // null char at end of string - p += sz; - break; - } - case coid: - { - OID oid = OID::from(p); - b.appendOID("", &oid); - p += OID::kOIDSize; - break; - } - case cbindata: - { - int len = binDataCodeToLength(*p); - int subtype = (*p) & BinDataTypeMask; - if( subtype & 0x8 ) { - subtype = (subtype & 0x7) | 0x80; - } - b.appendBinData("", len, (BinDataType) subtype, ++p); - p += len; - break; - } - case cdate: - b.appendDate("", (Date_t&) *p); - p += 8; - break; - case cdouble: - b.append("", (double&) *p); - p += sizeof(double); - break; - case cint: - b.append("", static_cast< int >((reinterpret_cast< const PackedDouble& >(*p)).d)); - p += sizeof(double); - break; - case clong: - b.append("", static_cast< long long>((reinterpret_cast< const PackedDouble& >(*p)).d)); - p += sizeof(double); - break; - default: - verify(false); - } - - if( (bits & cHASMORE) == 0 ) + _keyData = (const unsigned char*)b.buf(); + dassert(b.len() == dataSize()); // check datasize method is correct + dassert((*_keyData & cNOTUSED) == 0); +} + +BSONObj KeyV1::toBson() const { + verify(_keyData != 0); + if (!isCompactFormat()) + return bson(); + + BSONObjBuilder b(512); + const unsigned char* p = _keyData; + while (1) { + unsigned bits = *p++; + + switch (bits & 0x3f) { + case cminkey: + b.appendMinKey(""); break; - } - return b.obj(); - } - - static int compare(const unsigned char *&l, const unsigned char *&r) { - int lt = (*l & cCANONTYPEMASK); - int rt = (*r & cCANONTYPEMASK); - int x = lt - rt; - if( x ) - return x; - - l++; r++; - - // same type - switch( lt ) { - case cdouble: - { - double L = (reinterpret_cast< const PackedDouble* >(l))->d; - double R = (reinterpret_cast< const PackedDouble* >(r))->d; - if( L < R ) - return -1; - if( L != R ) - return 1; - l += 8; r += 8; + case cnull: + b.appendNull(""); + break; + case cfalse: + b.appendBool("", false); + break; + case ctrue: + b.appendBool("", true); + break; + case cmaxkey: + b.appendMaxKey(""); + break; + case cstring: { + unsigned sz = *p++; + // we build the element ourself as we have to null terminate it + BufBuilder& bb = b.bb(); + bb.appendNum((char)String); + bb.appendUChar(0); // fieldname "" + bb.appendNum(sz + 1); + bb.appendBuf(p, sz); + bb.appendUChar(0); // null char at end of string + p += sz; break; } - case cstring: - { - int lsz = *l; - int rsz = *r; - int common = min(lsz, rsz); - l++; r++; // skip the size byte - // use memcmp as we (will) allow zeros in UTF8 strings - int res = memcmp(l, r, common); - if( res ) - return res; - // longer string is the greater one - int diff = lsz-rsz; - if( diff ) - return diff; - l += lsz; r += lsz; + case coid: { + OID oid = OID::from(p); + b.appendOID("", &oid); + p += OID::kOIDSize; break; } - case cbindata: - { - int L = *l; - int R = *r; - int llen = binDataCodeToLength(L); - int diff = L-R; // checks length and subtype simultaneously - if( diff ) { - // unfortunately nibbles are backwards to do subtype and len in one check (could bit swap...) - int rlen = binDataCodeToLength(R); - if( llen != rlen ) - return llen - rlen; - return diff; + case cbindata: { + int len = binDataCodeToLength(*p); + int subtype = (*p) & BinDataTypeMask; + if (subtype & 0x8) { + subtype = (subtype & 0x7) | 0x80; } - // same length, same type - l++; r++; - int res = memcmp(l, r, llen); - if( res ) - return res; - l += llen; r += llen; + b.appendBinData("", len, (BinDataType)subtype, ++p); + p += len; break; } - case cdate: - { - long long L = *((long long *) l); - long long R = *((long long *) r); - if( L < R ) - return -1; - if( L > R ) - return 1; - l += 8; r += 8; + case cdate: + b.appendDate("", (Date_t&)*p); + p += 8; break; - } - case coid: - { - int res = memcmp(l, r, OID::kOIDSize); - if( res ) - return res; - l += OID::kOIDSize; r += OID::kOIDSize; + case cdouble: + b.append("", (double&)*p); + p += sizeof(double); + break; + case cint: + b.append("", static_cast<int>((reinterpret_cast<const PackedDouble&>(*p)).d)); + p += sizeof(double); break; + case clong: + b.append("", static_cast<long long>((reinterpret_cast<const PackedDouble&>(*p)).d)); + p += sizeof(double); + break; + default: + verify(false); + } + + if ((bits & cHASMORE) == 0) + break; + } + return b.obj(); +} + +static int compare(const unsigned char*& l, const unsigned char*& r) { + int lt = (*l & cCANONTYPEMASK); + int rt = (*r & cCANONTYPEMASK); + int x = lt - rt; + if (x) + return x; + + l++; + r++; + + // same type + switch (lt) { + case cdouble: { + double L = (reinterpret_cast<const PackedDouble*>(l))->d; + double R = (reinterpret_cast<const PackedDouble*>(r))->d; + if (L < R) + return -1; + if (L != R) + return 1; + l += 8; + r += 8; + break; + } + case cstring: { + int lsz = *l; + int rsz = *r; + int common = min(lsz, rsz); + l++; + r++; // skip the size byte + // use memcmp as we (will) allow zeros in UTF8 strings + int res = memcmp(l, r, common); + if (res) + return res; + // longer string is the greater one + int diff = lsz - rsz; + if (diff) + return diff; + l += lsz; + r += lsz; + break; + } + case cbindata: { + int L = *l; + int R = *r; + int llen = binDataCodeToLength(L); + int diff = L - R; // checks length and subtype simultaneously + if (diff) { + // unfortunately nibbles are backwards to do subtype and len in one check (could bit swap...) + int rlen = binDataCodeToLength(R); + if (llen != rlen) + return llen - rlen; + return diff; } + // same length, same type + l++; + r++; + int res = memcmp(l, r, llen); + if (res) + return res; + l += llen; + r += llen; + break; + } + case cdate: { + long long L = *((long long*)l); + long long R = *((long long*)r); + if (L < R) + return -1; + if (L > R) + return 1; + l += 8; + r += 8; + break; + } + case coid: { + int res = memcmp(l, r, OID::kOIDSize); + if (res) + return res; + l += OID::kOIDSize; + r += OID::kOIDSize; + break; + } default: // all the others are a match -- e.g. null == null ; - } - - return 0; - } - - // at least one of this and right are traditional BSON format - int NOINLINE_DECL KeyV1::compareHybrid(const KeyV1& right, const Ordering& order) const { - BSONObj L = toBson(); - BSONObj R = right.toBson(); - return L.woCompare(R, order, /*considerfieldname*/false); } - int KeyV1::woCompare(const KeyV1& right, const Ordering &order) const { - const unsigned char *l = _keyData; - const unsigned char *r = right._keyData; - - if( (*l|*r) == IsBSON ) // only can do this if cNOTUSED maintained - return compareHybrid(right, order); - - unsigned mask = 1; - while( 1 ) { - char lval = *l; - char rval = *r; - { - int x = compare(l, r); // updates l and r pointers - if( x ) { - if( order.descending(mask) ) - x = -x; - return x; - } - } - - { - int x = ((int)(lval & cHASMORE)) - ((int)(rval & cHASMORE)); - if( x ) - return x; - if( (lval & cHASMORE) == 0 ) - break; + return 0; +} + +// at least one of this and right are traditional BSON format +int NOINLINE_DECL KeyV1::compareHybrid(const KeyV1& right, const Ordering& order) const { + BSONObj L = toBson(); + BSONObj R = right.toBson(); + return L.woCompare(R, order, /*considerfieldname*/ false); +} + +int KeyV1::woCompare(const KeyV1& right, const Ordering& order) const { + const unsigned char* l = _keyData; + const unsigned char* r = right._keyData; + + if ((*l | *r) == IsBSON) // only can do this if cNOTUSED maintained + return compareHybrid(right, order); + + unsigned mask = 1; + while (1) { + char lval = *l; + char rval = *r; + { + int x = compare(l, r); // updates l and r pointers + if (x) { + if (order.descending(mask)) + x = -x; + return x; } + } - mask <<= 1; + { + int x = ((int)(lval & cHASMORE)) - ((int)(rval & cHASMORE)); + if (x) + return x; + if ((lval & cHASMORE) == 0) + break; } - return 0; + mask <<= 1; } - static unsigned sizes[] = { - 0, - 1, //cminkey=1, - 1, //cnull=2, - 0, - 9, //cdouble=4, - 0, - 0, //cstring=6, - 0, - 13, //coid=8, - 0, - 1, //cfalse=10, - 1, //ctrue=11, - 9, //cdate=12, - 0, - 1, //cmaxkey=14, - 0 - }; - - inline unsigned sizeOfElement(const unsigned char *p) { - unsigned type = *p & cCANONTYPEMASK; - unsigned sz = sizes[type]; - if( sz == 0 ) { - if( type == cstring ) { - sz = ((unsigned) p[1]) + 2; - } - else { - verify( type == cbindata ); - sz = binDataCodeToLength(p[1]) + 2; - } + return 0; +} + +static unsigned sizes[] = {0, + 1, // cminkey=1, + 1, // cnull=2, + 0, + 9, // cdouble=4, + 0, + 0, // cstring=6, + 0, + 13, // coid=8, + 0, + 1, // cfalse=10, + 1, // ctrue=11, + 9, // cdate=12, + 0, + 1, // cmaxkey=14, + 0}; + +inline unsigned sizeOfElement(const unsigned char* p) { + unsigned type = *p & cCANONTYPEMASK; + unsigned sz = sizes[type]; + if (sz == 0) { + if (type == cstring) { + sz = ((unsigned)p[1]) + 2; + } else { + verify(type == cbindata); + sz = binDataCodeToLength(p[1]) + 2; } - return sz; } + return sz; +} - int KeyV1::dataSize() const { - const unsigned char *p = _keyData; - if( !isCompactFormat() ) { - return bson().objsize() + 1; - } - - bool more; - do { - unsigned z = sizeOfElement(p); - more = (*p & cHASMORE) != 0; - p += z; - } while( more ); - return p - _keyData; +int KeyV1::dataSize() const { + const unsigned char* p = _keyData; + if (!isCompactFormat()) { + return bson().objsize() + 1; } - bool KeyV1::woEqual(const KeyV1& right) const { - const unsigned char *l = _keyData; - const unsigned char *r = right._keyData; - - if( (*l|*r) == IsBSON ) { - return toBson().equal(right.toBson()); - } + bool more; + do { + unsigned z = sizeOfElement(p); + more = (*p & cHASMORE) != 0; + p += z; + } while (more); + return p - _keyData; +} + +bool KeyV1::woEqual(const KeyV1& right) const { + const unsigned char* l = _keyData; + const unsigned char* r = right._keyData; + + if ((*l | *r) == IsBSON) { + return toBson().equal(right.toBson()); + } - while( 1 ) { - char lval = *l; - char rval = *r; - if( (lval&(cCANONTYPEMASK|cHASMORE)) != (rval&(cCANONTYPEMASK|cHASMORE)) ) - return false; - l++; r++; - switch( lval&cCANONTYPEMASK ) { + while (1) { + char lval = *l; + char rval = *r; + if ((lval & (cCANONTYPEMASK | cHASMORE)) != (rval & (cCANONTYPEMASK | cHASMORE))) + return false; + l++; + r++; + switch (lval & cCANONTYPEMASK) { case coid: - if( *((unsigned*) l) != *((unsigned*) r) ) + if (*((unsigned*)l) != *((unsigned*)r)) return false; - l += 4; r += 4; + l += 4; + r += 4; case cdate: - if( *((unsigned long long *) l) != *((unsigned long long *) r) ) + if (*((unsigned long long*)l) != *((unsigned long long*)r)) return false; - l += 8; r += 8; + l += 8; + r += 8; break; case cdouble: - if( (reinterpret_cast< const PackedDouble* > (l))->d != (reinterpret_cast< const PackedDouble* >(r))->d ) + if ((reinterpret_cast<const PackedDouble*>(l))->d != + (reinterpret_cast<const PackedDouble*>(r))->d) return false; - l += 8; r += 8; + l += 8; + r += 8; break; - case cstring: - { - if( *l != *r ) - return false; // not same length - unsigned sz = ((unsigned) *l) + 1; - if( memcmp(l, r, sz) ) - return false; - l += sz; r += sz; - break; - } - case cbindata: - { - if( *l != *r ) - return false; // len or subtype mismatch - int len = binDataCodeToLength(*l) + 1; - if( memcmp(l, r, len) ) - return false; - l += len; r += len; - break; - } + case cstring: { + if (*l != *r) + return false; // not same length + unsigned sz = ((unsigned)*l) + 1; + if (memcmp(l, r, sz)) + return false; + l += sz; + r += sz; + break; + } + case cbindata: { + if (*l != *r) + return false; // len or subtype mismatch + int len = binDataCodeToLength(*l) + 1; + if (memcmp(l, r, len)) + return false; + l += len; + r += len; + break; + } case cminkey: case cnull: case cfalse: @@ -683,23 +691,23 @@ namespace mongo { break; default: verify(false); - } - if( (lval&cHASMORE) == 0 ) - break; } - return true; + if ((lval & cHASMORE) == 0) + break; } - - struct CmpUnitTest : public StartupTest { - void run() { - char a[2]; - char b[2]; - a[0] = -3; - a[1] = 0; - b[0] = 3; - b[1] = 0; - verify( strcmp(a,b)>0 && memcmp(a,b,2)>0 ); - } - } cunittest; + return true; +} + +struct CmpUnitTest : public StartupTest { + void run() { + char a[2]; + char b[2]; + a[0] = -3; + a[1] = 0; + b[0] = 3; + b[1] = 0; + verify(strcmp(a, b) > 0 && memcmp(a, b, 2) > 0); + } +} cunittest; } // namespace mongo |