mirror of
https://github.com/mongodb/mongo.git
synced 2024-12-01 09:32:32 +01:00
SERVER-100 checkpoint btree cursor can take multiple ranges
This commit is contained in:
parent
d22866abff
commit
714de2af68
35
db/btree.h
35
db/btree.h
@ -215,15 +215,17 @@ namespace mongo {
|
||||
};
|
||||
|
||||
class BtreeCursor : public Cursor {
|
||||
friend class BtreeBucket;
|
||||
NamespaceDetails *d;
|
||||
int idxNo;
|
||||
BSONObj startKey;
|
||||
BSONObj endKey;
|
||||
bool endKeyInclusive_;
|
||||
bool multikey; // note this must be updated every getmore batch in case someone added a multikey...
|
||||
public:
|
||||
BtreeCursor( NamespaceDetails *_d, int _idxNo, const IndexDetails&, const BSONObj &startKey, const BSONObj &endKey, bool endKeyInclusive, int direction );
|
||||
|
||||
// a BoundList contains intervals specified by inclusive start
|
||||
// and end bounds. The intervals should be nonoverlapping and occur in
|
||||
// the specified direction of traversal. For example, given a simple index {i:1}
|
||||
// and direction +1, one valid BoundList is: (1, 2); (4, 6). The same BoundList
|
||||
// would be valid for index {i:-1} with direction -1.
|
||||
typedef vector< pair< BSONObj, BSONObj > > BoundList;
|
||||
BtreeCursor( NamespaceDetails *_d, int _idxNo, const IndexDetails& _id, const vector< pair< BSONObj, BSONObj > > &_bounds, int _direction );
|
||||
|
||||
virtual bool ok() {
|
||||
return !bucket.isNull();
|
||||
}
|
||||
@ -290,13 +292,14 @@ namespace mongo {
|
||||
virtual string toString() {
|
||||
string s = string("BtreeCursor ") + indexDetails.indexName();
|
||||
if ( direction < 0 ) s += " reverse";
|
||||
if ( bounds_.size() > 1 ) s += " multi";
|
||||
return s;
|
||||
}
|
||||
|
||||
BSONObj prettyKey( const BSONObj &key ) const {
|
||||
return key.replaceFieldNames( indexDetails.keyPattern() ).clientReadable();
|
||||
}
|
||||
|
||||
|
||||
virtual BSONObj prettyStartKey() const {
|
||||
return prettyKey( startKey );
|
||||
}
|
||||
@ -315,6 +318,20 @@ namespace mongo {
|
||||
/* Check if the current key is beyond endKey. */
|
||||
void checkEnd();
|
||||
|
||||
// selective audits on construction
|
||||
void audit();
|
||||
|
||||
// init start / end keys with a new range
|
||||
void init();
|
||||
|
||||
friend class BtreeBucket;
|
||||
NamespaceDetails *d;
|
||||
int idxNo;
|
||||
BSONObj startKey;
|
||||
BSONObj endKey;
|
||||
bool endKeyInclusive_;
|
||||
bool multikey; // note this must be updated every getmore batch in case someone added a multikey...
|
||||
|
||||
const IndexDetails& indexDetails;
|
||||
BSONObj order;
|
||||
DiskLoc bucket;
|
||||
@ -322,6 +339,8 @@ namespace mongo {
|
||||
int direction; // 1=fwd,-1=reverse
|
||||
BSONObj keyAtKeyOfs; // so we can tell if things moved around on us between the query and the getMore call
|
||||
DiskLoc locAtKeyOfs;
|
||||
BoundList bounds_;
|
||||
unsigned boundIndex_;
|
||||
};
|
||||
|
||||
#pragma pack()
|
||||
|
@ -34,14 +34,37 @@ namespace mongo {
|
||||
startKey( _startKey ),
|
||||
endKey( _endKey ),
|
||||
endKeyInclusive_( endKeyInclusive ),
|
||||
multikey( d->isMultikey( idxNo ) ),
|
||||
indexDetails( _id ),
|
||||
order( _id.keyPattern() ),
|
||||
direction( _direction )
|
||||
direction( _direction ),
|
||||
boundIndex_()
|
||||
{
|
||||
dassert( d->idxNo((IndexDetails&) indexDetails) == idxNo );
|
||||
multikey = d->isMultikey(idxNo);
|
||||
audit();
|
||||
init();
|
||||
}
|
||||
|
||||
BtreeCursor::BtreeCursor( NamespaceDetails *_d, int _idxNo, const IndexDetails& _id, const vector< pair< BSONObj, BSONObj > > &_bounds, int _direction )
|
||||
:
|
||||
d(_d), idxNo(_idxNo),
|
||||
endKeyInclusive_( true ),
|
||||
multikey( d->isMultikey( idxNo ) ),
|
||||
indexDetails( _id ),
|
||||
order( _id.keyPattern() ),
|
||||
direction( _direction ),
|
||||
bounds_( _bounds ),
|
||||
boundIndex_()
|
||||
{
|
||||
assert( !bounds_.empty() );
|
||||
startKey = bounds_[ 0 ].first;
|
||||
endKey = bounds_[ 0 ].second;
|
||||
audit();
|
||||
init();
|
||||
}
|
||||
|
||||
void BtreeCursor::audit() {
|
||||
dassert( d->idxNo((IndexDetails&) indexDetails) == idxNo );
|
||||
|
||||
bool found;
|
||||
if ( otherTraceLevel >= 12 ) {
|
||||
if ( otherTraceLevel >= 200 ) {
|
||||
out() << "::BtreeCursor() qtl>200. validating entire index." << endl;
|
||||
@ -52,7 +75,10 @@ namespace mongo {
|
||||
indexDetails.head.btree()->dump();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BtreeCursor::init() {
|
||||
bool found;
|
||||
bucket = indexDetails.head.btree()->
|
||||
locate(indexDetails, indexDetails.head, startKey, order, keyOfs, found, direction > 0 ? minDiskLoc : maxDiskLoc, direction);
|
||||
|
||||
@ -104,6 +130,11 @@ namespace mongo {
|
||||
bucket = bucket.btree()->advance(bucket, keyOfs, direction, "BtreeCursor::advance");
|
||||
skipUnusedKeys();
|
||||
checkEnd();
|
||||
while( !ok() && ++boundIndex_ < bounds_.size() ) {
|
||||
startKey = bounds_[ boundIndex_ ].first;
|
||||
endKey = bounds_[ boundIndex_ ].second;
|
||||
init();
|
||||
}
|
||||
return !bucket.isNull();
|
||||
}
|
||||
|
||||
|
@ -18,6 +18,8 @@
|
||||
*/
|
||||
|
||||
#include "../db/clientcursor.h"
|
||||
#include "../db/instance.h"
|
||||
#include "../db/btree.h"
|
||||
|
||||
#include "dbtests.h"
|
||||
|
||||
@ -103,12 +105,103 @@ namespace CursorTests {
|
||||
};
|
||||
|
||||
} // namespace IdSetTests
|
||||
|
||||
namespace BtreeCursorTests {
|
||||
|
||||
class MultiRange {
|
||||
public:
|
||||
void run() {
|
||||
dblock lk;
|
||||
const char *ns = "unittests.cursortests.BtreeCursorTests.MultiRange";
|
||||
{
|
||||
DBDirectClient c;
|
||||
for( int i = 0; i < 10; ++i )
|
||||
c.insert( ns, BSON( "a" << i ) );
|
||||
ASSERT( c.ensureIndex( ns, BSON( "a" << 1 ) ) );
|
||||
}
|
||||
BtreeCursor::BoundList b;
|
||||
b.push_back( pair< BSONObj, BSONObj >( BSON( "" << 1 ), BSON( "" << 2 ) ) );
|
||||
b.push_back( pair< BSONObj, BSONObj >( BSON( "" << 4 ), BSON( "" << 6 ) ) );
|
||||
setClient( ns );
|
||||
BtreeCursor c( nsdetails( ns ), 1, nsdetails( ns )->indexes[ 1 ], b, 1 );
|
||||
ASSERT_EQUALS( "BtreeCursor a_1 multi", c.toString() );
|
||||
double expected[] = { 1, 2, 4, 5, 6 };
|
||||
for( int i = 0; i < 5; ++i ) {
|
||||
ASSERT( c.ok() );
|
||||
ASSERT_EQUALS( expected[ i ], c.currKey().firstElement().number() );
|
||||
c.advance();
|
||||
}
|
||||
ASSERT( !c.ok() );
|
||||
}
|
||||
};
|
||||
|
||||
class MultiRangeGap {
|
||||
public:
|
||||
void run() {
|
||||
dblock lk;
|
||||
const char *ns = "unittests.cursortests.BtreeCursorTests.MultiRangeGap";
|
||||
{
|
||||
DBDirectClient c;
|
||||
for( int i = 0; i < 10; ++i )
|
||||
c.insert( ns, BSON( "a" << i ) );
|
||||
for( int i = 100; i < 110; ++i )
|
||||
c.insert( ns, BSON( "a" << i ) );
|
||||
ASSERT( c.ensureIndex( ns, BSON( "a" << 1 ) ) );
|
||||
}
|
||||
BtreeCursor::BoundList b;
|
||||
b.push_back( pair< BSONObj, BSONObj >( BSON( "" << -50 ), BSON( "" << 2 ) ) );
|
||||
b.push_back( pair< BSONObj, BSONObj >( BSON( "" << 40 ), BSON( "" << 60 ) ) );
|
||||
b.push_back( pair< BSONObj, BSONObj >( BSON( "" << 109 ), BSON( "" << 200 ) ) );
|
||||
setClient( ns );
|
||||
BtreeCursor c( nsdetails( ns ), 1, nsdetails( ns )->indexes[ 1 ], b, 1 );
|
||||
ASSERT_EQUALS( "BtreeCursor a_1 multi", c.toString() );
|
||||
double expected[] = { 0, 1, 2, 109 };
|
||||
for( int i = 0; i < 4; ++i ) {
|
||||
ASSERT( c.ok() );
|
||||
ASSERT_EQUALS( expected[ i ], c.currKey().firstElement().number() );
|
||||
c.advance();
|
||||
}
|
||||
ASSERT( !c.ok() );
|
||||
}
|
||||
};
|
||||
|
||||
class MultiRangeReverse {
|
||||
public:
|
||||
void run() {
|
||||
dblock lk;
|
||||
const char *ns = "unittests.cursortests.BtreeCursorTests.MultiRangeReverse";
|
||||
{
|
||||
DBDirectClient c;
|
||||
for( int i = 0; i < 10; ++i )
|
||||
c.insert( ns, BSON( "a" << i ) );
|
||||
ASSERT( c.ensureIndex( ns, BSON( "a" << 1 ) ) );
|
||||
}
|
||||
BtreeCursor::BoundList b;
|
||||
b.push_back( pair< BSONObj, BSONObj >( BSON( "" << 6 ), BSON( "" << 4 ) ) );
|
||||
b.push_back( pair< BSONObj, BSONObj >( BSON( "" << 2 ), BSON( "" << 1 ) ) );
|
||||
setClient( ns );
|
||||
BtreeCursor c( nsdetails( ns ), 1, nsdetails( ns )->indexes[ 1 ], b, -1 );
|
||||
ASSERT_EQUALS( "BtreeCursor a_1 reverse multi", c.toString() );
|
||||
double expected[] = { 6, 5, 4, 2, 1 };
|
||||
for( int i = 0; i < 5; ++i ) {
|
||||
ASSERT( c.ok() );
|
||||
ASSERT_EQUALS( expected[ i ], c.currKey().firstElement().number() );
|
||||
c.advance();
|
||||
}
|
||||
ASSERT( !c.ok() );
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace MultiBtreeCursorTests
|
||||
|
||||
class All : public Suite {
|
||||
class All : public ::Suite {
|
||||
public:
|
||||
All() {
|
||||
add< IdSetTests::BasicSize >();
|
||||
add< IdSetTests::Upgrade >();
|
||||
add< BtreeCursorTests::MultiRange >();
|
||||
add< BtreeCursorTests::MultiRangeGap >();
|
||||
add< BtreeCursorTests::MultiRangeReverse >();
|
||||
}
|
||||
};
|
||||
} // namespace CursorTests
|
||||
|
Loading…
Reference in New Issue
Block a user