diff --git a/db/instance.cpp b/db/instance.cpp index 5a605b7a6b0..6bdd83238ea 100644 --- a/db/instance.cpp +++ b/db/instance.cpp @@ -502,6 +502,28 @@ namespace mongo { QueryResult* emptyMoreResult(long long); + void OpTime::waitForDifferent(unsigned long long millis){ + DEV dbMutex.assertAtLeastReadLocked(); + + if (*this != last) return; // check early + + boost::xtime timeout; + boost::xtime_get(&timeout, TIME_UTC); + + timeout.nsec += millis * 1000*1000; + if (timeout.nsec >= 1000*1000*1000){ + timeout.nsec -= 1000*1000*1000; + timeout.sec += 1; + } + + do { + dbtemprelease tmp; + boost::mutex::scoped_lock lk(notifyMutex()); + if (!notifier().timed_wait(lk, timeout)) + return; // timed out + } while (*this != last); + } + bool receivedGetMore(DbResponse& dbresponse, Message& m, CurOp& curop ) { bool ok = true; @@ -524,21 +546,15 @@ namespace mongo { try { readlock lk; - bool skip = false; if (str::startsWith(ns, "local.oplog.")){ if (pass == 0) last = OpTime::last_inlock(); - else if (pass < 1000 && last == OpTime::last_inlock()) - skip = true; // no new oplog writes since last pass + else + last.waitForDifferent(1000/*ms*/); } - if (skip) { - msgdata = 0; - } - else { - Client::Context ctx(ns); - msgdata = processGetMore(ns, ntoreturn, cursorid, curop, pass, exhaust); - } + Client::Context ctx(ns); + msgdata = processGetMore(ns, ntoreturn, cursorid, curop, pass, exhaust); } catch ( AssertionException& e ) { exhaust = false; @@ -554,9 +570,8 @@ namespace mongo { } else { if( time(0) - start >= 4 ) { - // after about 4 seconds, return. this is a sanity check. pass stops at 1000 normally - // for DEV this helps and also if sleep is highly inaccurate on a platform. we want to - // return occasionally so slave can checkpoint. + // after about 4 seconds, return. pass stops at 1000 normally. + // we want to return occasionally so slave can checkpoint. pass = 10000; } } diff --git a/util/optime.h b/util/optime.h index 0eef8e3f744..f485f01b7ee 100644 --- a/util/optime.h +++ b/util/optime.h @@ -42,6 +42,8 @@ namespace mongo { static OpTime skewed(); public: static void setLast(const Date_t &date) { + notifier().notify_all(); // won't really do anything until write-lock released + last = OpTime(date); } unsigned getSecs() const { @@ -74,6 +76,8 @@ namespace mongo { } // it isn't generally safe to not be locked for this. so use now(). some tests use this. static OpTime now_inlock() { + notifier().notify_all(); // won't really do anything until write-lock released + unsigned t = (unsigned) time(0); if ( last.secs == t ) { last.i++; @@ -95,6 +99,11 @@ namespace mongo { return last; } + // Waits for global OpTime to be different from *this + // Must be atLeastReadLocked + // Defined in instance.cpp (only current user) as it needs dbtemprelease + void waitForDifferent(unsigned long long millis); + /* We store OpTime's in the database as BSON Date datatype -- we needed some sort of 64 bit "container" for these values. While these are not really "Dates", that seems a better choice for now than say, Number, which is floating point. Note the BinData type @@ -151,6 +160,17 @@ namespace mongo { bool operator>=(const OpTime& r) const { return !(*this < r); } + private: + + // The following functions are to get around the need to define class-level statics in a cpp + static boost::condition_variable& notifier() { + static boost::condition_variable* holder = new boost::condition_variable(); + return *holder; + }; + static boost::mutex& notifyMutex() { + static boost::mutex* holder = new boost::mutex(); + return *holder; + }; }; #pragma pack()