diff options
author | Dwight <dmerriman@gmail.com> | 2009-08-03 14:16:49 -0400 |
---|---|---|
committer | Dwight <dmerriman@gmail.com> | 2009-08-03 14:16:49 -0400 |
commit | 733ba1e11d6c4cfd304c2d81ca757bd4c08065ea (patch) | |
tree | 8d35de2391cc1bfb3f8296e3b2ebb5d8f908c6c2 | |
parent | 7fd282b98989ac84562549d77a5d2c4f1fbb960b (diff) | |
download | mongo-733ba1e11d6c4cfd304c2d81ca757bd4c08065ea.tar.gz |
first cut off NumberLong (64 bit ints) in BSON
-rw-r--r-- | client/dbclient.cpp | 8 | ||||
-rw-r--r-- | db/jsobj.cpp | 42 | ||||
-rw-r--r-- | db/jsobj.h | 91 | ||||
-rw-r--r-- | db/jsobjmanipulator.h | 6 | ||||
-rw-r--r-- | db/query.cpp | 61 | ||||
-rw-r--r-- | s/shardkey.cpp | 13 |
6 files changed, 180 insertions, 41 deletions
diff --git a/client/dbclient.cpp b/client/dbclient.cpp index 0c6b06563ba..c20d5842fee 100644 --- a/client/dbclient.cpp +++ b/client/dbclient.cpp @@ -568,12 +568,8 @@ namespace mongo { ss << "_"; ss << f.fieldName() << "_"; - - if ( f.type() == NumberInt ) - ss << (int)(f.number() ); - else if ( f.type() == NumberDouble ) - ss << f.number(); - + if( f.isNumber() ) + ss << f.numberInt(); } toSave.append( "name" , ss.str() ); diff --git a/db/jsobj.cpp b/db/jsobj.cpp index 426665f587b..08c61a438b6 100644 --- a/db/jsobj.cpp +++ b/db/jsobj.cpp @@ -46,12 +46,12 @@ namespace mongo { s << "new Date(" << date() << ')'; break; case RegEx: - { - s << "/" << regex() << '/'; - const char *p = regexFlags(); - if ( p ) s << p; - } - break; + { + s << "/" << regex() << '/'; + const char *p = regexFlags(); + if ( p ) s << p; + } + break; case NumberDouble: { stringstream tmp; @@ -64,10 +64,11 @@ namespace mongo { s << ".0"; } break; + case NumberLong: + s << _numberLong(); + break; case NumberInt: - s.precision( 16 ); - s << number(); - //s << "(" << ( type() == NumberInt ? "int" : "double" ) << ")"; + s << _numberInt(); break; case Bool: s << ( boolean() ? "true" : "false" ); @@ -188,6 +189,9 @@ namespace mongo { case Symbol: s << '"' << escape( valuestr() ) << '"'; break; + case NumberLong: + s << _numberLong(); + break; case NumberInt: case NumberDouble: if ( number() >= -numeric_limits< double >::max() && @@ -336,6 +340,7 @@ namespace mongo { case Timestamp: case Date: case NumberDouble: + case NumberLong: x = 8; break; case jstOID: @@ -416,15 +421,13 @@ namespace mongo { return BSONObj::Equality; } + /* wo = "well ordered" */ int BSONElement::woCompare( const BSONElement &e, bool considerFieldName ) const { int lt = (int) type(); - if ( lt == NumberInt ) lt = NumberDouble; int rt = (int) e.type(); - if ( rt == NumberInt ) rt = NumberDouble; - int x = lt - rt; - if ( x != 0 ) + if( x != 0 && (!isNumber() || !e.isNumber()) ) return x; if ( considerFieldName ) { x = strcmp(fieldName(), e.fieldName()); @@ -435,7 +438,8 @@ namespace mongo { return x; } - /* must be same type! */ + /* must be same type when called, unless both sides are #s + */ int compareElementValues(const BSONElement& l, const BSONElement& r) { int f; double x; @@ -455,6 +459,15 @@ namespace mongo { if ( l.date() < r.date() ) return -1; return l.date() == r.date() ? 0 : 1; + case 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; + return 1; + } + // else fall through case NumberInt: case NumberDouble: { double left = l.number(); @@ -745,6 +758,7 @@ namespace mongo { return e; } + /* jul09 : 'deep' and this function will be going away in the future - kept only for backward compatibility of datafiles for now. */ void trueDat( bool *deep ) { if( deep ) *deep = true; diff --git a/db/jsobj.h b/db/jsobj.h index fd60cbfb552..5a37761741d 100644 --- a/db/jsobj.h +++ b/db/jsobj.h @@ -84,8 +84,10 @@ namespace mongo { NumberInt = 16, /** Updated to a Date with value next OpTime on insert */ Timestamp = 17, + /** 64 bit integer */ + NumberLong = 18, /** max type that is not MaxKey */ - JSTypeMax=17, + JSTypeMax=18, /** larger than all other types */ MaxKey=127 }; @@ -256,6 +258,8 @@ namespace mongo { */ bool trueValue() const { switch( type() ) { + case NumberLong: + return *reinterpret_cast< const long long* >( value() ) != 0; case NumberDouble: return *reinterpret_cast< const double* >( value() ) != 0; case NumberInt: @@ -272,19 +276,71 @@ namespace mongo { /** True if element is of a numeric type. */ bool isNumber() const { - return type() == NumberDouble || type() == NumberInt; + switch( type() ) { + case NumberLong: + case NumberDouble: + case NumberInt: + return true; + default: + return false; + } } - /** Retrieve the numeric value of the element. If not of a numeric type, returns 0. */ - double number() const { + + /** Return double value for this field. MUST be NumberDouble type. */ + double _numberDouble() const {return *reinterpret_cast< const double* >( value() ); } + /** Return double value for this field. MUST be NumberInt type. */ + int _numberInt() const {return *reinterpret_cast< const int* >( value() ); } + /** Return double value for this field. MUST be NumberLong type. */ + long long _numberLong() const {return *reinterpret_cast< const long long* >( value() ); } + + /** Retrieve int value for the element safely. Zero returned if not a number. */ + int numberInt() const { switch( type() ) { case NumberDouble: - return *reinterpret_cast< const double* >( value() ); + return (int) _numberDouble(); + case NumberInt: + return _numberInt(); + case NumberLong: + return (int) _numberLong(); + default: + return 0; + } + } + + /** Retrieve long value for the element safely. Zero returned if not a number. */ + long long numberLong() const { + switch( type() ) { + case NumberDouble: + return (long long) _numberDouble(); + case NumberInt: + return _numberInt(); + case NumberLong: + return _numberLong(); + default: + return 0; + } + } + + /** Retrieve the numeric value of the element. If not of a numeric type, returns 0. + NOTE: casts to double, data loss may occur with large (>52 bit) NumberLong values. + */ + double numberDouble() const { + switch( type() ) { + case NumberDouble: + return _numberDouble(); case NumberInt: return *reinterpret_cast< const int* >( value() ); + case NumberLong: + return (double) *reinterpret_cast< const long long* >( value() ); default: return 0; } } + /** Retrieve the numeric value of the element. If not of a numeric type, returns 0. + NOTE: casts to double, data loss may occur with large (>52 bit) NumberLong values. + */ + double number() const { return numberDouble(); } + /** Retrieve the object ID stored in the object. You must ensure the element is of type jstOID first. */ const OID &__oid() const { @@ -370,12 +426,19 @@ namespace mongo { just the value. */ bool valuesEqual(const BSONElement& r) const { - if ( isNumber() ) - return number() == r.number() && r.isNumber(); + switch( type() ) { + case NumberLong: + return _numberLong() == r.numberLong() && r.isNumber(); + case NumberDouble: + return _numberDouble() == r.number() && r.isNumber(); + case NumberInt: + return _numberInt() == r.numberInt() && r.isNumber(); + default: + ; + } bool match= valuesize() == r.valuesize() && memcmp(value(),r.value(),valuesize()) == 0; return match && type() == r.type(); - // todo: make "0" == 0.0 } /** Returns true if elements are equal. */ @@ -955,6 +1018,7 @@ namespace mongo { b.append(fieldName); b.append((char) (val?1:0)); } + /** Append a 32 bit integer element */ void append(const char *fieldName, int n) { b.append((char) NumberInt); @@ -965,7 +1029,17 @@ namespace mongo { void append(const string &fieldName, int n) { append( fieldName.c_str(), n ); } + + /** Append a 32 bit unsigned element - cast to a signed int. */ void append(const char *fieldName, unsigned n) { append(fieldName, (int) n); } + + /** Append a NumberLong */ + void append(const char *fieldName, long long n) { + b.append((char) NumberLong); + b.append(fieldName); + b.append(n); + } + /** Append a double element */ BSONObjBuilder& append(const char *fieldName, double n) { b.append((char) NumberDouble); @@ -973,6 +1047,7 @@ namespace mongo { b.append(n); return *this; } + /** Append a BSON Object ID (OID type). */ void appendOID(const char *fieldName, OID *oid = 0) { b.append((char) jstOID); diff --git a/db/jsobjmanipulator.h b/db/jsobjmanipulator.h index 927e6fac860..d534d08c242 100644 --- a/db/jsobjmanipulator.h +++ b/db/jsobjmanipulator.h @@ -35,11 +35,15 @@ public: OpTime::now().asDate() */ void initTimestamp(); + /** Change the value, in place, of the number. */ void setNumber(double d) { if ( element_.type() == NumberDouble ) *reinterpret_cast< double * >( value() ) = d; else if ( element_.type() == NumberInt ) *reinterpret_cast< int * >( value() ) = (int) d; - } + } + void setLong(long long n) { + if( element_.type() == NumberLong ) *reinterpret_cast< long long * >( value() ) = n; + } /** Replace the type and value of the element with the type and value of e, preserving the original fieldName */ diff --git a/db/query.cpp b/db/query.cpp index eb4d7341905..243871e1dbd 100644 --- a/db/query.cpp +++ b/db/query.cpp @@ -228,19 +228,47 @@ namespace mongo { vector< shared_ptr< BSONObjBuilder > > builderStorage_; }; + /* Used for modifiers such as $inc, $set, ... */ struct Mod { enum Op { INC, SET, PUSH, PUSH_ALL, PULL, PULL_ALL } op; const char *fieldName; + + // kind of lame; fix one day? double *ndouble; int *nint; + long long *nlong; + BSONElement elt; int pushStartSize; - void setn(double n) const { - if ( ndouble ) *ndouble = n; - else *nint = (int) n; + + /* [dm] why is this const? (or rather, why was setn const?) i see why but think maybe clearer if were not. */ + void inc(BSONElement& n) const { + uassert( "$inc value is not a number", n.isNumber() ); + if( ndouble ) + *ndouble += n.numberDouble(); + else if( nint ) + *nint += n.numberInt(); + else + *nlong += n.numberLong();\ + } + + void setElementToOurNumericValue(BSONElement& e) const { + BSONElementManipulator manip(e); + if( e.type() == NumberLong ) + manip.setLong(_getlong()); + else + manip.setNumber(_getn()); } - double getn() const { - return ndouble ? *ndouble : *nint; + + double _getn() const { + if( ndouble ) return *ndouble; + if( nint ) return *nint; + return (double) *nlong; + } + long long _getlong() const { + if( nlong ) return *nlong; + if( ndouble ) return (long long) *ndouble; + return *nint; } bool operator<( const Mod &other ) const { return strcmp( fieldName, other.fieldName ) < 0; @@ -415,13 +443,16 @@ namespace mongo { BSONElement e = obj.getFieldDotted(m.fieldName); if ( m.op == Mod::PULL || m.op == Mod::PULL_ALL ) continue; + + // [dm] the BSONElementManipulator statements below are for replication (correct?) if ( m.op == Mod::INC ) { - m.setn( e.number() + m.getn() ); - BSONElementManipulator( e ).setNumber( m.getn() ); + m.inc(e); + m.setElementToOurNumericValue(e); } else { - if ( e.isNumber() && m.elt.isNumber() ) - BSONElementManipulator( e ).setNumber( m.getn() ); - else + if ( e.isNumber() && m.elt.isNumber() ) { + // todo: handle NumberLong: + m.setElementToOurNumericValue(e); + } else BSONElementManipulator( e ).replaceTypeAndValue( m.elt ); } } @@ -475,7 +506,8 @@ namespace mongo { if ( cmp == 0 ) { BSONElement e = p->second; if ( m->op == Mod::INC ) { - m->setn( m->getn() + e.number() ); + m->inc(e); + //m->setn( m->getn() + e.number() ); b2.appendAs( m->elt, m->fieldName ); } else if ( m->op == Mod::SET ) { b2.appendAs( m->elt, m->fieldName ); @@ -604,6 +636,8 @@ namespace mongo { uassert( "Modifier $inc allowed for numbers only", f.isNumber() || op != Mod::INC ); uassert( "Modifier $pushAll/pullAll allowed for arrays only", f.type() == Array || ( op != Mod::PUSH_ALL && op != Mod::PULL_ALL ) ); m.elt = f; + + // horrible - to be cleaned up if ( f.type() == NumberDouble ) { m.ndouble = (double *) f.value(); m.nint = 0; @@ -611,6 +645,11 @@ namespace mongo { m.ndouble = 0; m.nint = (int *) f.value(); } + else if( f.type() == NumberLong ) { + m.ndouble = 0; + m.nint = 0; + m.nlong = (long long *) f.value(); + } mods_.push_back( m ); } } diff --git a/s/shardkey.cpp b/s/shardkey.cpp index c7be584f77b..b1fdd8ee8b0 100644 --- a/s/shardkey.cpp +++ b/s/shardkey.cpp @@ -165,6 +165,14 @@ namespace mongo { b.append(fn, x + (y - x)/2); break; } + case NumberLong: + { + long long x = l.numberLong(); + long long y = r.numberLong(); + assert( y >= x ); + b.append(fn, x + (y - x)/2); + break; + } case String: b.append(fn, middleString(l.valuestr(), r.valuestr())); break; @@ -208,7 +216,8 @@ namespace mongo { case Bool: return Date; case Date: return jstNULL; case jstNULL: return NumberInt; - case NumberInt: return MaxKey; + case NumberInt: return NumberLong; + case NumberLong: return MaxKey; default: uassert("type not supported by sharding [nextType]", false); } @@ -218,6 +227,7 @@ namespace mongo { BSONElement largestElementForType(int t, BSONObjBuilder& b) { switch( t ) { case MinKey: b.appendMinKey(""); break; + case NumberLong: b.append("", numeric_limits< long long >::min()); break; case NumberDouble: b.append("", numeric_limits< double >::min()); break; case String: b.append("", ""); break; case jstOID: @@ -240,6 +250,7 @@ namespace mongo { BSONElement smallestElementForType(int t, BSONObjBuilder& b) { switch( t ) { case MinKey: b.appendMinKey(""); break; + case NumberLong: b.append("", numeric_limits< long long >::min()); break; case NumberDouble: b.append("", numeric_limits< double >::min()); break; case String: b.append("", ""); break; case jstOID: |