0
0
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:
Aaron 2011-07-31 08:49:21 -07:00
parent b65d137c6a
commit 10dd86fb96
3 changed files with 41 additions and 12 deletions

View File

@ -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();

View File

@ -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;

View File

@ -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