mirror of
https://github.com/mongodb/mongo.git
synced 2024-11-30 00:56:44 +01:00
SERVER-3448 prevent excessive scanning in BtreeCursor functions
This commit is contained in:
parent
b65d137c6a
commit
10dd86fb96
@ -1071,7 +1071,7 @@ namespace mongo {
|
||||
* Our btrees may (rarely) have "unused" keys when items are deleted.
|
||||
* Skip past them.
|
||||
*/
|
||||
virtual bool skipUnusedKeys( bool mayJump ) = 0;
|
||||
virtual bool skipUnusedKeys() = 0;
|
||||
|
||||
bool skipOutOfRangeKeysAndCheckEnd();
|
||||
void skipAndCheck();
|
||||
|
@ -68,7 +68,7 @@ namespace mongo {
|
||||
return !currKeyNode().prevChildBucket.isNull();
|
||||
}
|
||||
|
||||
bool skipUnusedKeys( bool mayJump ) {
|
||||
bool skipUnusedKeys() {
|
||||
int u = 0;
|
||||
while ( 1 ) {
|
||||
if ( !ok() )
|
||||
@ -80,9 +80,6 @@ namespace mongo {
|
||||
u++;
|
||||
//don't include unused keys in nscanned
|
||||
//++_nscanned;
|
||||
if ( mayJump && ( u % 10 == 0 ) ) {
|
||||
skipOutOfRangeKeysAndCheckEnd();
|
||||
}
|
||||
}
|
||||
if ( u > 10 )
|
||||
OCCASIONALLY log() << "btree unused skipped:" << u << '\n';
|
||||
@ -120,7 +117,7 @@ namespace mongo {
|
||||
if ( !kn.isUsed() ) {
|
||||
// we were deleted but still exist as an unused
|
||||
// marker key. advance.
|
||||
skipUnusedKeys( false );
|
||||
skipUnusedKeys();
|
||||
}
|
||||
return;
|
||||
}
|
||||
@ -149,7 +146,7 @@ namespace mongo {
|
||||
bucket = _locate(keyAtKeyOfs, locAtKeyOfs);
|
||||
RARELY log() << "key seems to have moved in the index, refinding. " << bucket.toString() << endl;
|
||||
if ( ! bucket.isNull() )
|
||||
skipUnusedKeys( false );
|
||||
skipUnusedKeys();
|
||||
|
||||
}
|
||||
|
||||
@ -329,18 +326,24 @@ namespace mongo {
|
||||
if ( ok() ) {
|
||||
_nscanned = 1;
|
||||
}
|
||||
skipUnusedKeys( false );
|
||||
skipUnusedKeys();
|
||||
checkEnd();
|
||||
}
|
||||
|
||||
void BtreeCursor::skipAndCheck() {
|
||||
skipUnusedKeys( true );
|
||||
int startNscanned = _nscanned;
|
||||
skipUnusedKeys();
|
||||
while( 1 ) {
|
||||
if ( !skipOutOfRangeKeysAndCheckEnd() ) {
|
||||
break;
|
||||
}
|
||||
while( skipOutOfRangeKeysAndCheckEnd() );
|
||||
if ( !skipUnusedKeys( true ) ) {
|
||||
do {
|
||||
if ( _nscanned > startNscanned + 20 ) {
|
||||
skipUnusedKeys();
|
||||
return;
|
||||
}
|
||||
} while( skipOutOfRangeKeysAndCheckEnd() );
|
||||
if ( !skipUnusedKeys() ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -395,7 +398,7 @@ namespace mongo {
|
||||
bucket = _advance(bucket, keyOfs, _direction, "BtreeCursor::advance");
|
||||
|
||||
if ( !_independentFieldRanges ) {
|
||||
skipUnusedKeys( false );
|
||||
skipUnusedKeys();
|
||||
checkEnd();
|
||||
if ( ok() ) {
|
||||
++_nscanned;
|
||||
|
@ -33,6 +33,7 @@ namespace CursorTests {
|
||||
|
||||
class Base {
|
||||
protected:
|
||||
static const char *ns() { return "unittests.cursortests.Base"; }
|
||||
FieldRangeVector *vec( int *vals, int len, int direction = 1 ) {
|
||||
FieldRangeSet s( "", BSON( "a" << 1 ), true );
|
||||
for( int i = 0; i < len; i += 2 ) {
|
||||
@ -49,6 +50,7 @@ namespace CursorTests {
|
||||
IndexSpec *idxSpec = new IndexSpec( BSON( "a" << 1 ) );
|
||||
return new FieldRangeVector( s, *idxSpec, direction );
|
||||
}
|
||||
DBDirectClient _c;
|
||||
private:
|
||||
vector< BSONObj > _objs;
|
||||
};
|
||||
@ -258,6 +260,29 @@ namespace CursorTests {
|
||||
}
|
||||
virtual BSONObj idx() const { return BSON( "a" << 1 << "b" << 1 ); }
|
||||
};
|
||||
|
||||
class AbortImplicitScan : public Base {
|
||||
public:
|
||||
void run() {
|
||||
dblock lk;
|
||||
IndexSpec idx( BSON( "a" << 1 << "b" << 1 ) );
|
||||
_c.ensureIndex( ns(), idx.keyPattern );
|
||||
for( int i = 0; i < 300; ++i ) {
|
||||
_c.insert( ns(), BSON( "a" << i << "b" << 5 ) );
|
||||
}
|
||||
FieldRangeSet frs( ns(), BSON( "b" << 3 ), true );
|
||||
shared_ptr<FieldRangeVector> frv( new FieldRangeVector( frs, idx, 1 ) );
|
||||
Client::Context ctx( ns() );
|
||||
scoped_ptr<BtreeCursor> c( BtreeCursor::make( nsdetails( ns() ), 1, nsdetails( ns() )->idx(1), frv, 1 ) );
|
||||
int initialNscanned = c->nscanned();
|
||||
ASSERT( initialNscanned < 200 );
|
||||
ASSERT( c->ok() );
|
||||
c->advance();
|
||||
ASSERT( c->nscanned() > initialNscanned );
|
||||
ASSERT( c->nscanned() < 200 );
|
||||
ASSERT( c->ok() );
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace BtreeCursorTests
|
||||
|
||||
@ -274,6 +299,7 @@ namespace CursorTests {
|
||||
add< BtreeCursorTests::EqIn >();
|
||||
add< BtreeCursorTests::RangeEq >();
|
||||
add< BtreeCursorTests::RangeIn >();
|
||||
add< BtreeCursorTests::AbortImplicitScan >();
|
||||
}
|
||||
} myall;
|
||||
} // namespace CursorTests
|
||||
|
Loading…
Reference in New Issue
Block a user