summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDwight <dmerriman@gmail.com>2009-08-03 14:16:49 -0400
committerDwight <dmerriman@gmail.com>2009-08-03 14:16:49 -0400
commit733ba1e11d6c4cfd304c2d81ca757bd4c08065ea (patch)
tree8d35de2391cc1bfb3f8296e3b2ebb5d8f908c6c2
parent7fd282b98989ac84562549d77a5d2c4f1fbb960b (diff)
downloadmongo-733ba1e11d6c4cfd304c2d81ca757bd4c08065ea.tar.gz
first cut off NumberLong (64 bit ints) in BSON
-rw-r--r--client/dbclient.cpp8
-rw-r--r--db/jsobj.cpp42
-rw-r--r--db/jsobj.h91
-rw-r--r--db/jsobjmanipulator.h6
-rw-r--r--db/query.cpp61
-rw-r--r--s/shardkey.cpp13
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: