Permalink
Browse files

SERVER-984 sorting of infinity

  • Loading branch information...
1 parent 2b6bd33 commit 5961cc9ddc44eb8a5ed2cf36d672f04411fbbe52 @dwight dwight committed Jul 5, 2011
Showing with 82 additions and 50 deletions.
  1. +22 −21 bson/bson-inl.h
  2. +3 −2 db/btree.cpp
  3. +1 −0 db/btreebuilder.cpp
  4. +15 −16 db/key.cpp
  5. +24 −4 dbtests/jsobjtests.cpp
  6. +17 −7 jstests/sort2.js
View
@@ -30,12 +30,15 @@
namespace mongo {
+ inline bool isNaN(double d) {
+ return d != d;
+ }
+
/* must be same type when called, unless both sides are #s
this large function is in header to facilitate inline-only use of bson
*/
inline int compareElementValues(const BSONElement& l, const BSONElement& r) {
int f;
- double x;
switch ( l.type() ) {
case EOO:
@@ -69,30 +72,28 @@ namespace mongo {
if( L == R ) return 0;
return 1;
}
- // else fall through
+ goto dodouble;
case NumberInt:
- case NumberDouble: {
- double left = l.number();
- double right = r.number();
- bool lNan = !( left <= std::numeric_limits< double >::max() &&
- left >= -std::numeric_limits< double >::max() );
- bool rNan = !( right <= numeric_limits< double >::max() &&
- right >= -numeric_limits< double >::max() );
- if ( lNan ) {
- if ( rNan ) {
- return 0;
- }
- else {
- return -1;
- }
+ if( r.type() == NumberInt ) {
+ int L = l._numberInt();
+ int R = r._numberInt();
+ if( L < R ) return -1;
+ return L == R ? 0 : 1;
}
- else if ( rNan ) {
+ // else fall through
+ case NumberDouble:
+dodouble:
+ {
+ double left = l.number();
+ double right = r.number();
+ if( left < right )
+ return -1;
+ if( left == right )
+ return 0;
+ if( isNaN(left) )
+ return isNaN(right) ? 0 : -1;
return 1;
}
- x = left - right;
- if ( x < 0 ) return -1;
- return x == 0 ? 0 : 1;
- }
case jstOID:
return memcmp(l.value(), r.value(), 12);
case Code:
View
@@ -341,8 +341,9 @@ namespace mongo {
const KeyNode klast = keyNode(this->n-1);
if( klast.key.woCompare(key, order) > 0 ) {
log() << "btree bucket corrupt? consider reindexing or running validate command" << endl;
- //cout << keyNode(n-1).key.toString() << endl;
- //cout << key.toString() << endl;
+ log() << " klast: " << keyNode(n-1).key.toString() << endl;
+ log() << " key: " << key.toString() << endl;
+ klast.key.woCompare(key, order);
assert(false);
}
}
View
@@ -62,6 +62,7 @@ namespace mongo {
template<class V>
void BtreeBuilder<V>::addKey(BSONObj& _key, DiskLoc loc) {
+
auto_ptr< KeyOwned > key( new KeyOwned(_key) );
if ( key->dataSize() > BtreeBucket<V>::KeyMax ) {
problem() << "Btree::insert: key too large to index, skipping " << idx.indexNamespace()
View
@@ -314,14 +314,13 @@ namespace mongo {
case NumberDouble:
{
double d = e._numberDouble();
- bool nan = !( d <= numeric_limits< double >::max() &&
- d >= -numeric_limits< double >::max() );
- if( !nan ) {
- b.appendUChar(cdouble|bits);
- b.appendNum(d);
- break;
+ if( isNaN(d) ) {
+ traditional(obj);
+ return;
}
- // else fall through and return a traditional BSON obj so our compressed keys need not check for nan
+ b.appendUChar(cdouble|bits);
+ b.appendNum(d);
+ break;
}
default:
// if other types involved, store as traditional BSON
@@ -425,7 +424,7 @@ namespace mongo {
double R = *((double *) r);
if( L < R )
return -1;
- if( L > R )
+ if( L != R )
return 1;
l += 8; r += 8;
break;
@@ -447,14 +446,6 @@ namespace mongo {
l += lsz; r += lsz;
break;
}
- case coid:
- {
- int res = memcmp(l, r, sizeof(OID));
- if( res )
- return res;
- l += 12; r += 12;
- break;
- }
case cbindata:
{
int L = *l;
@@ -482,6 +473,14 @@ namespace mongo {
l += 8; r += 8;
break;
}
+ case coid:
+ {
+ int res = memcmp(l, r, sizeof(OID));
+ if( res )
+ return res;
+ l += 12; r += 12;
+ break;
+ }
default:
// all the others are a match -- e.g. null == null
;
View
@@ -258,6 +258,11 @@ namespace JsobjTests {
}
keyTest(b.obj(), true);
}
+ {
+ double nan = numeric_limits<double>::quiet_NaN();
+ BSONObj o = BSON( "y" << nan );
+ keyTest(o);
+ }
{
BSONObjBuilder b;
@@ -331,21 +336,36 @@ namespace JsobjTests {
double inf = numeric_limits< double >::infinity();
double nan = numeric_limits< double >::quiet_NaN();
double nan2 = numeric_limits< double >::signaling_NaN();
+ ASSERT( isNaN(nan) );
+ ASSERT( isNaN(nan2) );
+ ASSERT( !isNaN(inf) );
+
+ bool x = nan == nan;
ASSERT( BSON( "a" << inf ).woCompare( BSON( "a" << inf ) ) == 0 );
- ASSERT( BSON( "a" << inf ).woCompare( BSON( "a" << 1 ) ) < 0 );
- ASSERT( BSON( "a" << 1 ).woCompare( BSON( "a" << inf ) ) > 0 );
+ ASSERT( BSON( "a" << inf ).woCompare( BSON( "a" << 1 ) ) > 0 );
+ ASSERT( BSON( "a" << 1 ).woCompare( BSON( "a" << inf ) ) < 0 );
ASSERT( BSON( "a" << nan ).woCompare( BSON( "a" << nan ) ) == 0 );
ASSERT( BSON( "a" << nan ).woCompare( BSON( "a" << 1 ) ) < 0 );
+
+ ASSERT( BSON( "a" << nan ).woCompare( BSON( "a" << 5000000000LL ) ) < 0 );
+
+ {
+ KeyV1Owned a( BSON( "a" << nan ) );
+ KeyV1Owned b( BSON( "a" << 1 ) );
+ Ordering o = Ordering::make(BSON("a"<<1));
+ ASSERT( a.woCompare(b, o) < 0 );
+ }
+
ASSERT( BSON( "a" << 1 ).woCompare( BSON( "a" << nan ) ) > 0 );
ASSERT( BSON( "a" << nan2 ).woCompare( BSON( "a" << nan2 ) ) == 0 );
ASSERT( BSON( "a" << nan2 ).woCompare( BSON( "a" << 1 ) ) < 0 );
ASSERT( BSON( "a" << 1 ).woCompare( BSON( "a" << nan2 ) ) > 0 );
- ASSERT( BSON( "a" << inf ).woCompare( BSON( "a" << nan ) ) == 0 );
- ASSERT( BSON( "a" << inf ).woCompare( BSON( "a" << nan2 ) ) == 0 );
+ ASSERT( BSON( "a" << inf ).woCompare( BSON( "a" << nan ) ) > 0 );
+ ASSERT( BSON( "a" << inf ).woCompare( BSON( "a" << nan2 ) ) > 0 );
ASSERT( BSON( "a" << nan ).woCompare( BSON( "a" << nan2 ) ) == 0 );
}
};
View
@@ -1,22 +1,32 @@
// test sorting, mainly a test ver simple with no index
t = db.sort2;
-t.drop();
+t.drop();
t.save({x:1, y:{a:5,b:4}});
t.save({x:1, y:{a:7,b:3}});
t.save({x:1, y:{a:2,b:3}});
t.save({x:1, y:{a:9,b:3}});
-
for( var pass = 0; pass < 2; pass++ ) {
-
var res = t.find().sort({'y.a':1}).toArray();
assert( res[0].y.a == 2 );
assert( res[1].y.a == 5 );
assert( res.length == 4 );
-
t.ensureIndex({"y.a":1});
-
}
-
-assert(t.validate().valid);
+assert(t.validate().valid);
+
+t.drop();
+t.insert({ x: 1 })
+t.insert({ x: 5000000000 })
+t.insert({ x: NaN });
+t.insert({ x: Infinity });
+t.insert({ x: -Infinity });
+var good = [NaN, -Infinity, 1, 5000000000, Infinity];
+for (var pass = 0; pass < 2; pass++) {
+ var res = t.find({}, { _id: 0 }).sort({ x: 1 }).toArray();
+ for (var i = 0; i < good.length; i++) {
+ assert(good[i].toString() == res[i].x.toString());
+ }
+ t.ensureIndex({ x : 1 });
+}

0 comments on commit 5961cc9

Please sign in to comment.