diff options
Diffstat (limited to 'db/oplog.h')
-rw-r--r-- | db/oplog.h | 133 |
1 files changed, 68 insertions, 65 deletions
@@ -16,7 +16,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -/* +/* local.oplog.$main is the default */ @@ -30,6 +30,7 @@ #include "queryoptimizer.h" #include "../client/dbclient.h" #include "../util/optime.h" +#include "../util/timer.h" namespace mongo { @@ -38,7 +39,7 @@ namespace mongo { void _logOpObjRS(const BSONObj& op); /** Write operation to the log (local.oplog.$main) - + @param opstr "i" insert "u" update @@ -47,89 +48,88 @@ namespace mongo { "n" no-op "db" declares presence of a database (ns is set to the db name + '.') - See _logOp() in oplog.cpp for more details. + See _logOp() in oplog.cpp for more details. */ void logOp(const char *opstr, const char *ns, const BSONObj& obj, BSONObj *patt = 0, bool *b = 0); void logKeepalive(); - /** puts obj in the oplog as a comment (a no-op). Just for diags. - convention is + /** puts obj in the oplog as a comment (a no-op). Just for diags. + convention is { msg : "text", ... } */ void logOpComment(const BSONObj& obj); void oplogCheckCloseDatabase( Database * db ); - - extern int __findingStartInitialTimeout; // configurable for testing + + extern int __findingStartInitialTimeout; // configurable for testing class FindingStartCursor { public: - FindingStartCursor( const QueryPlan & qp ) : - _qp( qp ), - _findingStart( true ), - _findingStartMode(), - _findingStartTimer( 0 ), - _findingStartCursor( 0 ) + FindingStartCursor( const QueryPlan & qp ) : + _qp( qp ), + _findingStart( true ), + _findingStartMode(), + _findingStartTimer( 0 ) { init(); } bool done() const { return !_findingStart; } shared_ptr<Cursor> cRelease() { return _c; } void next() { - if ( !_findingStartCursor || !_findingStartCursor->c->ok() ) { + if ( !_findingStartCursor || !_findingStartCursor->ok() ) { _findingStart = false; _c = _qp.newCursor(); // on error, start from beginning destroyClientCursor(); return; } switch( _findingStartMode ) { - case Initial: { - if ( !_matcher->matches( _findingStartCursor->c->currKey(), _findingStartCursor->c->currLoc() ) ) { - _findingStart = false; // found first record out of query range, so scan normally - _c = _qp.newCursor( _findingStartCursor->c->currLoc() ); - destroyClientCursor(); - return; - } - _findingStartCursor->c->advance(); - RARELY { - if ( _findingStartTimer.seconds() >= __findingStartInitialTimeout ) { - createClientCursor( startLoc( _findingStartCursor->c->currLoc() ) ); - _findingStartMode = FindExtent; - return; - } - } + case Initial: { + if ( !_matcher->matches( _findingStartCursor->currKey(), _findingStartCursor->currLoc() ) ) { + _findingStart = false; // found first record out of query range, so scan normally + _c = _qp.newCursor( _findingStartCursor->currLoc() ); + destroyClientCursor(); return; } - case FindExtent: { - if ( !_matcher->matches( _findingStartCursor->c->currKey(), _findingStartCursor->c->currLoc() ) ) { - _findingStartMode = InExtent; - return; - } - DiskLoc prev = prevLoc( _findingStartCursor->c->currLoc() ); - if ( prev.isNull() ) { // hit beginning, so start scanning from here - createClientCursor(); - _findingStartMode = InExtent; + _findingStartCursor->advance(); + RARELY { + if ( _findingStartTimer.seconds() >= __findingStartInitialTimeout ) { + createClientCursor( startLoc( _findingStartCursor->currLoc() ) ); + _findingStartMode = FindExtent; return; } - // There might be a more efficient implementation than creating new cursor & client cursor each time, - // not worrying about that for now - createClientCursor( prev ); + } + return; + } + case FindExtent: { + if ( !_matcher->matches( _findingStartCursor->currKey(), _findingStartCursor->currLoc() ) ) { + _findingStartMode = InExtent; return; } - case InExtent: { - if ( _matcher->matches( _findingStartCursor->c->currKey(), _findingStartCursor->c->currLoc() ) ) { - _findingStart = false; // found first record in query range, so scan normally - _c = _qp.newCursor( _findingStartCursor->c->currLoc() ); - destroyClientCursor(); - return; - } - _findingStartCursor->c->advance(); + DiskLoc prev = prevLoc( _findingStartCursor->currLoc() ); + if ( prev.isNull() ) { // hit beginning, so start scanning from here + createClientCursor(); + _findingStartMode = InExtent; return; } - default: { - massert( 12600, "invalid _findingStartMode", false ); + // There might be a more efficient implementation than creating new cursor & client cursor each time, + // not worrying about that for now + createClientCursor( prev ); + return; + } + case InExtent: { + if ( _matcher->matches( _findingStartCursor->currKey(), _findingStartCursor->currLoc() ) ) { + _findingStart = false; // found first record in query range, so scan normally + _c = _qp.newCursor( _findingStartCursor->currLoc() ); + destroyClientCursor(); + return; } - } - } + _findingStartCursor->advance(); + return; + } + default: { + massert( 12600, "invalid _findingStartMode", false ); + } + } + } bool prepareToYield() { if ( _findingStartCursor ) { return _findingStartCursor->prepareToYield( _yieldData ); @@ -139,10 +139,10 @@ namespace mongo { void recoverFromYield() { if ( _findingStartCursor ) { if ( !ClientCursor::recoverFromYield( _yieldData ) ) { - _findingStartCursor = 0; + _findingStartCursor.reset( 0 ); } } - } + } private: enum FindingStartMode { Initial, FindExtent, InExtent }; const QueryPlan &_qp; @@ -150,7 +150,7 @@ namespace mongo { FindingStartMode _findingStartMode; auto_ptr< CoveredIndexMatcher > _matcher; Timer _findingStartTimer; - ClientCursor * _findingStartCursor; + ClientCursor::CleanupPointer _findingStartCursor; shared_ptr<Cursor> _c; ClientCursor::YieldData _yieldData; DiskLoc startLoc( const DiskLoc &rec ) { @@ -162,7 +162,7 @@ namespace mongo { // doesn't matter if we start the extent scan with capFirstNewRecord. return _qp.nsd()->capFirstNewRecord; } - + // should never have an empty extent in the oplog, so don't worry about that case DiskLoc prevLoc( const DiskLoc &rec ) { Extent *e = rec.rec()->myExtent( rec ); @@ -173,7 +173,8 @@ namespace mongo { e = e->xprev.ext(); if ( e->myLoc != _qp.nsd()->capExtent ) return e->firstRecord; - } else { + } + else { if ( !e->xprev.isNull() ) { e = e->xprev.ext(); return e->firstRecord; @@ -183,19 +184,16 @@ namespace mongo { } void createClientCursor( const DiskLoc &startLoc = DiskLoc() ) { shared_ptr<Cursor> c = _qp.newCursor( startLoc ); - _findingStartCursor = new ClientCursor(QueryOption_NoCursorTimeout, c, _qp.ns()); + _findingStartCursor.reset( new ClientCursor(QueryOption_NoCursorTimeout, c, _qp.ns()) ); } void destroyClientCursor() { - if ( _findingStartCursor ) { - ClientCursor::erase( _findingStartCursor->cursorid ); - _findingStartCursor = 0; - } + _findingStartCursor.reset( 0 ); } void init() { // Use a ClientCursor here so we can release db mutex while scanning // oplog (can take quite a while with large oplogs). shared_ptr<Cursor> c = _qp.newReverseCursor(); - _findingStartCursor = new ClientCursor(QueryOption_NoCursorTimeout, c, _qp.ns(), BSONObj()); + _findingStartCursor.reset( new ClientCursor(QueryOption_NoCursorTimeout, c, _qp.ns(), BSONObj()) ); _findingStartTimer.reset(); _findingStartMode = Initial; BSONElement tsElt = _qp.originalQuery()[ "ts" ]; @@ -210,5 +208,10 @@ namespace mongo { void pretouchOperation(const BSONObj& op); void pretouchN(vector<BSONObj>&, unsigned a, unsigned b); - void applyOperation_inlock(const BSONObj& op); + /** + * take an op and apply locally + * used for applying from an oplog + * @param fromRepl really from replication or for testing/internal/command/etc... + */ + void applyOperation_inlock(const BSONObj& op , bool fromRepl = true ); } |