summaryrefslogtreecommitdiff
path: root/db/oplog.h
diff options
context:
space:
mode:
Diffstat (limited to 'db/oplog.h')
-rw-r--r--db/oplog.h133
1 files changed, 68 insertions, 65 deletions
diff --git a/db/oplog.h b/db/oplog.h
index 34c345f..d9073ab 100644
--- a/db/oplog.h
+++ b/db/oplog.h
@@ -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 );
}