Skip to content
Browse files

SERVER-371 checkpoint

  • Loading branch information...
1 parent aa3995d commit 4798e64b1c66e332030b77cb136b98ba07b26366 @astaple astaple committed Jul 7, 2010
Showing with 334 additions and 28 deletions.
  1. +110 −0 db/btree.cpp
  2. +20 −5 db/btree.h
  3. +141 −11 db/btreecursor.cpp
  4. +1 −1 db/dbcommands.cpp
  5. +4 −3 db/queryoptimizer.cpp
  6. +1 −0 db/queryoptimizer.h
  7. +1 −1 jstests/explain2.js
  8. +3 −3 jstests/index1.js
  9. +49 −2 jstests/index_check6.js
  10. +2 −0 mongo.xcodeproj/project.pbxproj
  11. +2 −2 s/d_split.cpp
View
110 db/btree.cpp
@@ -362,6 +362,34 @@ namespace mongo {
break;
}
}
+
+ int BtreeBucket::customBSONCmp( const BSONObj &l, const BSONObj &rBegin, int rBeginLen, const BSONObj &rEnd, const Ordering &o ) {
+ BSONObjIterator ll( l );
+ BSONObjIterator rr( rBegin );
+ BSONObjIterator rr2( rEnd );
+ unsigned mask = 1;
+ for( int i = 0; i < rBeginLen; ++i, mask <<= 1 ) {
+ BSONElement lll = ll.next();
+ BSONElement rrr = rr.next();
+ rr2.next();
+
+ int x = lll.woCompare( rrr, false );
+ if ( o.descending( mask ) )
+ x = -x;
+ if ( x != 0 )
+ return x;
+ }
+ for( ; ll.more(); mask <<= 1 ) {
+ BSONElement lll = ll.next();
+ BSONElement rrr = rr2.next();
+ int x = lll.woCompare( rrr, false );
+ if ( o.descending( mask ) )
+ x = -x;
+ if ( x != 0 )
+ return x;
+ }
+ return 0;
+ }
bool BtreeBucket::exists(const IndexDetails& idx, DiskLoc thisLoc, const BSONObj& key, const Ordering& order) {
int pos;
@@ -848,6 +876,88 @@ namespace mongo {
return pos == n ? DiskLoc() /*theend*/ : thisLoc;
}
+ bool BtreeBucket::customFind( int l, int h, const BSONObj &keyBegin, int keyBeginLen, const BSONObj &keyEnd, const Ordering &order, int direction, DiskLoc &thisLoc, int &keyOfs, pair< DiskLoc, int > &bestParent ) {
+ while( 1 ) {
+ if ( l + 1 == h ) {
+ keyOfs = h;
+ DiskLoc next = thisLoc.btree()->k( keyOfs ).prevChildBucket;
+ if ( !next.isNull() ) {
+ bestParent = make_pair( thisLoc, keyOfs );
+ thisLoc = next;
+ return true;
+ } else {
+ return false;
+ }
+ }
+ int m = l + ( h - l ) / 2;
+ int cmp = customBSONCmp( thisLoc.btree()->keyNode( m ).key, keyBegin, keyBeginLen, keyEnd, order );
+ if ( cmp < 0 ) {
+ l = m;
+ } else {
+ h = m;
+ }
+ }
+ }
+
+ // find smallest/biggest value greater-equal/less-equal than specified
+ // starting thisLoc + keyOfs will be strictly less than/strictly greater than keyBegin/keyBeginLen/keyEnd
+ void BtreeBucket::advanceTo(const IndexDetails &id, DiskLoc &thisLoc, int &keyOfs, const BSONObj &keyBegin, int keyBeginLen, const BSONObj &keyEnd, const Ordering &order, int direction ) {
+ // TODO direction
+ if ( direction < 0 ) {
+ return;
+ }
+ int l = keyOfs;
+ int h = n - 1;
+ pair< DiskLoc, int > bestParent;
+ if ( customBSONCmp( keyNode( h ).key, keyBegin, keyBeginLen, keyEnd, order ) >= 0 ) {
+ // this comparison result assures h > l
+ if ( !customFind( l, h, keyBegin, keyBeginLen, keyEnd, order, direction, thisLoc, keyOfs, bestParent ) ) {
+ return;
+ }
+ } else {
+ // go up parents until rightmost node is >= target or at top
+ while( !thisLoc.btree()->parent.isNull() ) {
+ thisLoc = thisLoc.btree()->parent;
+ if ( customBSONCmp( thisLoc.btree()->keyNode( thisLoc.btree()->n - 1 ).key, keyBegin, keyBeginLen, keyEnd, order ) >= 0 ) {
+ break;
+ }
+ }
+ }
+ // go down until find smallest >= target
+ while( 1 ) {
+ l = 0;
+ // leftmost key may possibly be >= search key (if search target is in rChild of this node's leftmost child)
+ if ( customBSONCmp( thisLoc.btree()->keyNode( 0 ).key, keyBegin, keyBeginLen, keyEnd, order ) >= 0 ) {
+ DiskLoc next = thisLoc.btree()->k( 0 ).prevChildBucket;
+ if ( !next.isNull() ) {
+ bestParent = make_pair( thisLoc, 0 );
+ thisLoc = next;
+ continue;
+ } else {
+ keyOfs = 0;
+ return;
+ }
+ }
+ h = thisLoc.btree()->n - 1;
+ if ( customBSONCmp( thisLoc.btree()->keyNode( h ).key, keyBegin, keyBeginLen, keyEnd, order ) < 0 ) {
+ DiskLoc next = thisLoc.btree()->nextChild;
+ if ( next.isNull() ) {
+ // if bestParent is null, we've hit the end and thisLoc gets set to DiskLoc()
+ thisLoc = bestParent.first;
+ keyOfs = bestParent.second;
+ return;
+ } else {
+ thisLoc = next;
+ continue;
+ }
+ }
+ if ( !customFind( l, h, keyBegin, keyBeginLen, keyEnd, order, direction, thisLoc, keyOfs, bestParent ) ) {
+ return;
+ }
+ }
+ }
+
+
/* @thisLoc disk location of *this
*/
int BtreeBucket::_insert(DiskLoc thisLoc, DiskLoc recordLoc,
View
25 db/btree.h
@@ -234,6 +234,9 @@ namespace mongo {
/* advance one key position in the index: */
DiskLoc advance(const DiskLoc& thisLoc, int& keyOfs, int direction, const char *caller);
+
+ void advanceTo(const IndexDetails &id, DiskLoc &thisLoc, int &keyOfs, const BSONObj &keyBegin, int keyBeginLen, const BSONObj &keyEnd, const Ordering &order, int direction );
+
DiskLoc getHead(const DiskLoc& thisLoc);
/* get tree shape */
@@ -256,7 +259,9 @@ namespace mongo {
const BSONObj& key, const Ordering &order, bool dupsAllowed,
DiskLoc lChild, DiskLoc rChild, IndexDetails&);
bool find(const IndexDetails& idx, const BSONObj& key, DiskLoc recordLoc, const Ordering &order, int& pos, bool assertIfDup);
+ bool customFind( int l, int h, const BSONObj &keyBegin, int keyBeginLen, const BSONObj &keyEnd, const Ordering &order, int direction, DiskLoc &thisLoc, int &keyOfs, pair< DiskLoc, int > &bestParent );
static void findLargestKey(const DiskLoc& thisLoc, DiskLoc& largestLoc, int& largestKey);
+ static int customBSONCmp( const BSONObj &l, const BSONObj &rBegin, int rBeginLen, const BSONObj &rEnd, const Ordering &o );
public:
// simply builds and returns a dup key error message string
static string dupKeyError( const IndexDetails& idx , const BSONObj& key );
@@ -265,7 +270,7 @@ namespace mongo {
class BtreeCursor : public Cursor {
public:
- BtreeCursor( NamespaceDetails *_d, int _idxNo, const IndexDetails&, const BSONObj &startKey, const BSONObj &endKey, bool endKeyInclusive, int direction );
+ BtreeCursor( NamespaceDetails *_d, int _idxNo, const IndexDetails&, const BSONObj &startKey, const BSONObj &endKey, bool endKeyInclusive, int direction, bool independentFieldRanges = true );
BtreeCursor( NamespaceDetails *_d, int _idxNo, const IndexDetails& _id, const BoundList &_bounds, int _direction );
~BtreeCursor(){
@@ -369,9 +374,9 @@ namespace mongo {
/* Our btrees may (rarely) have "unused" keys when items are deleted.
Skip past them.
*/
- void skipUnusedKeys();
-
- /* Check if the current key is beyond endKey. */
+ bool skipUnusedKeys();
+ bool skipOutOfRangeKeysAndCheckEnd();
+ void skipAndCheck();
void checkEnd();
// selective audits on construction
@@ -382,18 +387,27 @@ namespace mongo {
// init start / end keys with a new range
void initInterval();
-
+
+ void advanceTo( const BSONObj &keyBegin, int keyBeginLen, const BSONObj &keyEnd);
+
+ static BSONObj makeSuperlativeKey( const BSONObj &order, int direction );
+
friend class BtreeBucket;
set<DiskLoc> dups;
NamespaceDetails *d;
int idxNo;
+
BSONObj startKey;
BSONObj endKey;
bool endKeyInclusive_;
+ int _nEqKeyElts;
+
bool multikey; // note this must be updated every getmore batch in case someone added a multikey...
const IndexDetails& indexDetails;
BSONObj order;
+ Ordering _ordering;
+ BSONObj _superlativeKey;
DiskLoc bucket;
int keyOfs;
int direction; // 1=fwd,-1=reverse
@@ -403,6 +417,7 @@ namespace mongo {
unsigned boundIndex_;
const IndexSpec& _spec;
shared_ptr< CoveredIndexMatcher > _matcher;
+ bool _independentFieldRanges;
};
View
152 db/btreecursor.cpp
@@ -27,17 +27,21 @@ namespace mongo {
extern int otherTraceLevel;
BtreeCursor::BtreeCursor( NamespaceDetails *_d, int _idxNo, const IndexDetails &_id,
- const BSONObj &_startKey, const BSONObj &_endKey, bool endKeyInclusive, int _direction ) :
+ const BSONObj &_startKey, const BSONObj &_endKey, bool endKeyInclusive, int _direction, bool independentFieldRanges ) :
d(_d), idxNo(_idxNo),
startKey( _startKey ),
endKey( _endKey ),
endKeyInclusive_( endKeyInclusive ),
+ _nEqKeyElts( 0 ),
multikey( d->isMultikey( idxNo ) ),
indexDetails( _id ),
order( _id.keyPattern() ),
+ _ordering( Ordering::make( order ) ),
+ _superlativeKey( makeSuperlativeKey( order, _direction ) ),
direction( _direction ),
boundIndex_(),
- _spec( _id.getSpec() )
+ _spec( _id.getSpec() ),
+ _independentFieldRanges( independentFieldRanges )
{
audit();
init();
@@ -48,20 +52,38 @@ namespace mongo {
:
d(_d), idxNo(_idxNo),
endKeyInclusive_( true ),
+ _nEqKeyElts( 0 ),
multikey( d->isMultikey( idxNo ) ),
indexDetails( _id ),
order( _id.keyPattern() ),
+ _ordering( Ordering::make( order ) ),
+ _superlativeKey( makeSuperlativeKey( order, _direction ) ),
direction( _direction ),
bounds_( _bounds ),
boundIndex_(),
- _spec( _id.getSpec() )
+ _spec( _id.getSpec() ),
+ _independentFieldRanges( true )
{
assert( !bounds_.empty() );
audit();
initInterval();
DEV assert( dups.size() == 0 );
}
+ BSONObj BtreeCursor::makeSuperlativeKey( const BSONObj &order, int direction ) {
+ BSONObjBuilder b;
+ BSONObjIterator i( order );
+ while( i.more() ) {
+ BSONElement e = i.next();
+ if ( ( e.number() < 0 ) ^ ( direction < 0 ) ) {
+ b.appendMinKey( "" );
+ } else {
+ b.appendMaxKey( "" );
+ }
+ }
+ return b.obj();
+ }
+
void BtreeCursor::audit() {
dassert( d->idxNo((IndexDetails&) indexDetails) == idxNo );
@@ -82,11 +104,21 @@ namespace mongo {
startKey = _spec.getType()->fixKey( startKey );
endKey = _spec.getType()->fixKey( endKey );
}
+ // TODO what about _spec?
+ _nEqKeyElts = 0;
+ BSONObjIterator i( startKey );
+ BSONObjIterator j( endKey );
+ while( i.more() && j.more() ) {
+ if ( i.next().valuesEqual( j.next() ) ) {
+ ++_nEqKeyElts;
+ } else {
+ break;
+ }
+ }
bool found;
bucket = indexDetails.head.btree()->
- locate(indexDetails, indexDetails.head, startKey, Ordering::make(order), keyOfs, found, direction > 0 ? minDiskLoc : maxDiskLoc, direction);
- skipUnusedKeys();
- checkEnd();
+ locate(indexDetails, indexDetails.head, startKey, _ordering, keyOfs, found, direction > 0 ? minDiskLoc : maxDiskLoc, direction);
+ skipAndCheck();
}
void BtreeCursor::initInterval() {
@@ -97,8 +129,25 @@ namespace mongo {
} while ( !ok() && ++boundIndex_ < bounds_.size() );
}
+ void BtreeCursor::skipAndCheck() {
+ skipUnusedKeys();
+ if ( !_independentFieldRanges ) {
+ checkEnd();
+ return;
+ }
+ while( 1 ) {
+ if ( !skipOutOfRangeKeysAndCheckEnd() ) {
+ break;
+ }
+ while( skipOutOfRangeKeysAndCheckEnd() );
+ if ( !skipUnusedKeys() ) {
+ break;
+ }
+ }
+ }
+
/* skip unused keys. */
- void BtreeCursor::skipUnusedKeys() {
+ bool BtreeCursor::skipUnusedKeys() {
int u = 0;
while ( 1 ) {
if ( !ok() )
@@ -112,9 +161,10 @@ namespace mongo {
}
if ( u > 10 )
OCCASIONALLY log() << "btree unused skipped:" << u << '\n';
+ return u;
}
-// Return a value in the set {-1, 0, 1} to represent the sign of parameter i.
+ // Return a value in the set {-1, 0, 1} to represent the sign of parameter i.
int sgn( int i ) {
if ( i == 0 )
return 0;
@@ -132,14 +182,94 @@ namespace mongo {
bucket = DiskLoc();
}
}
+
+ bool BtreeCursor::skipOutOfRangeKeysAndCheckEnd() {
+ if ( bucket.isNull() )
+ return false;
+ bool eq = true;
+ if ( !endKey.isEmpty() ) {
+ int i = 0;
+ BSONObjIterator c( currKey() );
+ BSONObjIterator l( startKey );
+ BSONObjIterator r( endKey );
+ BSONObjIterator o( order );
+ for( ; i < _nEqKeyElts; ++i ) {
+ BSONElement cc = c.next();
+ BSONElement ll = l.next();
+ BSONElement rr = r.next();
+ BSONElement oo = o.next();
+ int x = cc.woCompare( rr, false );
+ if ( ( oo.number() < 0 ) ^ ( direction < 0 ) ) {
+ x = -x;
+ }
+ if ( x > 0 ) {
+ bucket = DiskLoc();
+ return false;
+ }
+ // can't have x < 0, since start and end are equal for these fields
+ assert( x == 0 );
+ }
+ // first range (non equality) element
+ if( c.more() ) {
+ BSONElement cc = c.next();
+ BSONElement ll = l.next();
+ BSONElement rr = r.next();
+ BSONElement oo = o.next();
+ int x = cc.woCompare( rr, false );
+ if ( ( oo.number() < 0 ) ^ ( direction < 0 ) ) {
+ x = -x;
+ }
+ if ( x > 0 ) {
+ bucket = DiskLoc();
+ return false;
+ } else if ( x < 0 ) {
+ eq = false;
+ }
+ ++i;
+ }
+ // subsequent elements
+ for( ; c.more(); ++i ) {
+ BSONElement cc = c.next();
+ BSONElement ll = l.next();
+ BSONElement rr = r.next();
+ BSONElement oo = o.next();
+ int x = cc.woCompare( rr, false );
+ if ( ( oo.number() < 0 ) ^ ( direction < 0 ) ) {
+ x = -x;
+ }
+ if ( x > 0 ) {
+ advanceTo( currKey(), i, _superlativeKey );
+ return true;
+ } else if ( x < 0 ) {
+ eq = false;
+ int y = cc.woCompare( ll, false );
+ if ( ( oo.number() < 0 ) ^ ( direction < 0 ) ) {
+ y = -y;
+ }
+ if ( y < 0 ) {
+ advanceTo( currKey(), i, startKey );
+ return true;
+ }
+ }
+ }
+
+ if ( eq && !endKeyInclusive_ ) {
+ bucket = DiskLoc();
+ }
+ }
+ return false;
+ }
+ void BtreeCursor::advanceTo( const BSONObj &keyBegin, int keyBeginLen, const BSONObj &keyEnd) {
+ bucket.btree()->advanceTo( indexDetails, bucket, keyOfs, keyBegin, keyBeginLen, keyEnd, _ordering, direction );
+ }
+
bool BtreeCursor::advance() {
killCurrentOp.checkForInterrupt();
if ( bucket.isNull() )
return false;
bucket = bucket.btree()->advance(bucket, keyOfs, direction, "BtreeCursor::advance");
- skipUnusedKeys();
- checkEnd();
+ skipAndCheck();
if( !ok() && ++boundIndex_ < bounds_.size() )
initInterval();
return !bucket.isNull();
@@ -204,7 +334,7 @@ namespace mongo {
bool found;
/* TODO: Switch to keep indexdetails and do idx.head! */
- bucket = indexDetails.head.btree()->locate(indexDetails, indexDetails.head, keyAtKeyOfs, Ordering::make(order), keyOfs, found, locAtKeyOfs, direction);
+ bucket = indexDetails.head.btree()->locate(indexDetails, indexDetails.head, keyAtKeyOfs, _ordering, keyOfs, found, locAtKeyOfs, direction);
RARELY log() << " key seems to have moved in the index, refinding. found:" << found << endl;
if ( ! bucket.isNull() )
skipUnusedKeys();
View
2 db/dbcommands.cpp
@@ -998,7 +998,7 @@ namespace mongo {
if ( idx == 0 )
return false;
NamespaceDetails *d = nsdetails(ns.c_str());
- c.reset( new BtreeCursor( d, d->idxNo(*idx), *idx, min, max, false, 1 ) );
+ c.reset( new BtreeCursor( d, d->idxNo(*idx), *idx, min, max, false, 1, false ) );
}
long long maxSize = jsobj["maxSize"].numberLong();
View
7 db/queryoptimizer.cpp
@@ -64,7 +64,8 @@ namespace mongo {
endKeyInclusive_( endKey.isEmpty() ),
unhelpful_( false ),
_special( special ),
- _type(0){
+ _type(0),
+ _startOrEndSpec( !startKey.isEmpty() || !endKey.isEmpty() ){
if ( !fbs_.matchPossible() ) {
unhelpful_ = true;
@@ -159,7 +160,7 @@ namespace mongo {
exactKeyMatch_ = true;
}
indexBounds_ = fbs.indexBounds( idxKey, direction_ );
- if ( !startKey.isEmpty() || !endKey.isEmpty() ) {
+ if ( _startOrEndSpec ) {
BSONObj newStart, newEnd;
if ( !startKey.isEmpty() )
newStart = startKey;
@@ -201,7 +202,7 @@ namespace mongo {
if ( indexBounds_.size() < 2 ) {
// we are sure to spec endKeyInclusive_
- return shared_ptr<Cursor>( new BtreeCursor( d, idxNo, *index_, indexBounds_[ 0 ].first, indexBounds_[ 0 ].second, endKeyInclusive_, direction_ >= 0 ? 1 : -1 ) );
+ return shared_ptr<Cursor>( new BtreeCursor( d, idxNo, *index_, indexBounds_[ 0 ].first, indexBounds_[ 0 ].second, endKeyInclusive_, direction_ >= 0 ? 1 : -1, !_startOrEndSpec ) );
} else {
return shared_ptr<Cursor>( new BtreeCursor( d, idxNo, *index_, indexBounds_, direction_ >= 0 ? 1 : -1 ) );
}
View
1 db/queryoptimizer.h
@@ -78,6 +78,7 @@ namespace mongo {
bool unhelpful_;
string _special;
IndexType * _type;
+ bool _startOrEndSpec;
};
// Inherit from this interface to implement a new query operation.
View
2 jstests/explain2.js
@@ -19,7 +19,7 @@ q = { a : { $gt : 3 } }
go( q , 6 , 7 , 6 );
q.b = 5
-go( q , 1 , 6 , 1 );
+go( q , 1 , 1 , 1 );
delete q.b
q.c = 5
View
6 jstests/index1.js
@@ -17,9 +17,9 @@ assert( t.findOne( { z : { a : 17 } } ) == null);
o = { name : "bar" , z : { a : 18 } };
t.save( o );
-assert( t.find().length() == 2 );
-assert( t.find().sort( { "z.a" : 1 } ).length() == 2 );
-assert( t.find().sort( { "z.a" : -1 } ).length() == 2 );
+assert.eq.automsg( "2", "t.find().length()" );
+assert.eq.automsg( "2", "t.find().sort( { 'z.a' : 1 } ).length()" );
+assert.eq.automsg( "2", "t.find().sort( { 'z.a' : -1 } ).length()" );
// We are planning to phase out this syntax.
assert( t.find().sort( { z : { a : 1 } } ).length() == 2 );
assert( t.find().sort( { z : { a: -1 } } ).length() == 2 );
View
51 jstests/index_check6.js
@@ -13,5 +13,52 @@ for ( var age=10; age<50; age++ ){
assert.eq( 10 , t.find( { age : 30 } ).explain().nscanned , "A" );
assert.eq( 20 , t.find( { age : { $gte : 29 , $lte : 30 } } ).explain().nscanned , "B" );
-//assert.eq( 2 , t.find( { age : { $gte : 29 , $lte : 30 } , rating : 5 } ).explain().nscanned , "C" ); // SERVER-371
-//assert.eq( 4 , t.find( { age : { $gte : 29 , $lte : 30 } , rating : { $gte : 4 , $lte : 5 } } ).explain().nscanned , "D" ); // SERVER-371
+assert.eq( 2 , t.find( { age : { $gte : 29 , $lte : 30 } , rating : 5 } ).explain().nscanned , "C" ); // SERVER-371
+assert.eq( 4 , t.find( { age : { $gte : 29 , $lte : 30 } , rating : { $gte : 4 , $lte : 5 } } ).explain().nscanned , "D" ); // SERVER-371
+
+assert.eq.automsg( "2", "t.find( { age:30, rating:{ $gte:4, $lte:5} } ).explain().nscanned" );
+
+t.drop();
+
+for ( var a=1; a<10; a++ ){
+ for ( var b=0; b<10; b++ ){
+ for ( var c=0; c<10; c++ ) {
+ t.save( { a:a, b:b, c:c } );
+ }
+ }
+}
+
+function doTest( s ) {
+ sort = s;
+assert.eq.automsg( "1", "t.find( { a:5, b:5, c:5 } ).sort( sort ).explain().nscanned" );
+assert.eq.automsg( "2", "t.find( { a:5, b:5, c:{$gte:5,$lte:6} } ).sort( sort ).explain().nscanned" );
+assert.eq.automsg( "1", "t.find( { a:5, b:5, c:{$gte:5.5,$lte:6} } ).sort( sort ).explain().nscanned" );
+assert.eq.automsg( "1", "t.find( { a:5, b:5, c:{$gte:5,$lte:5.5} } ).sort( sort ).explain().nscanned" );
+assert.eq.automsg( "3", "t.find( { a:5, b:5, c:{$gte:5,$lte:7} } ).sort( sort ).explain().nscanned" );
+assert.eq.automsg( "2", "t.find( { a:5, b:{$gte:5,$lte:6}, c:5 } ).sort( sort ).explain().nscanned" );
+assert.eq.automsg( "1", "t.find( { a:5, b:{$gte:5.5,$lte:6}, c:5 } ).sort( sort ).explain().nscanned" );
+assert.eq.automsg( "1", "t.find( { a:5, b:{$gte:5,$lte:5.5}, c:5 } ).sort( sort ).explain().nscanned" );
+assert.eq.automsg( "3", "t.find( { a:5, b:{$gte:5,$lte:7}, c:5 } ).sort( sort ).explain().nscanned" );
+assert.eq.automsg( "2", "t.find( { a:{$gte:5,$lte:6}, b:5, c:5 } ).sort( sort ).explain().nscanned" );
+assert.eq.automsg( "1", "t.find( { a:{$gte:5.5,$lte:6}, b:5, c:5 } ).sort( sort ).explain().nscanned" );
+assert.eq.automsg( "1", "t.find( { a:{$gte:5,$lte:5.5}, b:5, c:5 } ).sort( sort ).explain().nscanned" );
+assert.eq.automsg( "3", "t.find( { a:{$gte:5,$lte:7}, b:5, c:5 } ).sort( sort ).explain().nscanned" );
+assert.eq.automsg( "4", "t.find( { a:{$gte:5,$lte:6}, b:5, c:{$gte:5,$lte:6} } ).sort( sort ).explain().nscanned" );
+assert.eq.automsg( "2", "t.find( { a:{$gte:5.5,$lte:6}, b:5, c:{$gte:5,$lte:6} } ).sort( sort ).explain().nscanned" );
+assert.eq.automsg( "4", "t.find( { a:5, b:{$gte:5,$lte:6}, c:{$gte:5,$lte:6} } ).sort( sort ).explain().nscanned" );
+assert.eq.automsg( "4", "t.find( { a:{$gte:5,$lte:6}, b:{$gte:5,$lte:6}, c:5 } ).sort( sort ).explain().nscanned" );
+assert.eq.automsg( "8", "t.find( { a:{$gte:5,$lte:6}, b:{$gte:5,$lte:6}, c:{$gte:5,$lte:6} } ).sort( sort ).explain().nscanned" );
+}
+
+for ( var a = -1; a <= 1; a += 2 ) {
+ for( var b = -1; b <= 1; b += 2 ) {
+ for( var c = -1; c <= 1; c += 2 ) {
+ t.dropIndexes();
+ var spec = {a:a,b:b,c:c};
+ t.ensureIndex( spec );
+ doTest( spec );
+ doTest( {a:-a,b:-b,c:-c} );
+ }
+ }
+}
+
View
2 mongo.xcodeproj/project.pbxproj
@@ -545,6 +545,7 @@
93BFA0E311330A8C0045D084 /* not2.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = not2.js; sourceTree = "<group>"; };
93C38E940FA66622007D6E4A /* basictests.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = basictests.cpp; sourceTree = "<group>"; };
93C529C511D047CF00CF42F7 /* repair2.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = repair2.js; path = disk/repair2.js; sourceTree = "<group>"; };
+ 93C5BA5111E4FBA400F9671C /* index_check9.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = index_check9.js; sourceTree = "<group>"; };
93C8E6FE11457D9000F28017 /* master1.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = master1.js; sourceTree = "<group>"; };
93C8E81C1145BCCA00F28017 /* regex7.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = regex7.js; sourceTree = "<group>"; };
93C8E9DF1146D39700F28017 /* arrayfind2.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = arrayfind2.js; sourceTree = "<group>"; };
@@ -827,6 +828,7 @@
934BEB9A10DFFA9600178102 /* jstests */ = {
isa = PBXGroup;
children = (
+ 93C5BA5111E4FBA400F9671C /* index_check9.js */,
938A74BF11D17ECE005265E1 /* numberlong.js */,
938A748A11D140EC005265E1 /* in4.js */,
93C529C511D047CF00CF42F7 /* repair2.js */,
View
4 s/d_split.cpp
@@ -66,9 +66,9 @@ namespace mongo {
int num = 0;
NamespaceDetails *d = nsdetails(ns);
int idxNo = d->idxNo(*id);
- for( BtreeCursor c( d, idxNo, *id, min, max, false, 1 ); c.ok(); c.advance(), ++num );
+ for( BtreeCursor c( d, idxNo, *id, min, max, false, 1, false ); c.ok(); c.advance(), ++num );
num /= 2;
- BtreeCursor c( d, idxNo, *id, min, max, false, 1 );
+ BtreeCursor c( d, idxNo, *id, min, max, false, 1, false );
for( ; num; c.advance(), --num );
ostringstream os;

0 comments on commit 4798e64

Please sign in to comment.
Something went wrong with that request. Please try again.