本文整理汇总了C++中MONGO_FAIL_POINT函数的典型用法代码示例。如果您正苦于以下问题:C++ MONGO_FAIL_POINT函数的具体用法?C++ MONGO_FAIL_POINT怎么用?C++ MONGO_FAIL_POINT使用的例子?那么恭喜您, 这里精选的函数代码示例或许可以为您提供帮助。
在下文中一共展示了MONGO_FAIL_POINT函数的15个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于系统推荐出更棒的C++代码示例。
示例1: while
void Socket::recv( char * buf , int len ) {
int retries = 0;
while( len > 0 ) {
int ret = -1;
if (MONGO_FAIL_POINT(throwSockExcep)) {
#if defined(_WIN32)
WSASetLastError(WSAENETUNREACH);
#else
errno = ENETUNREACH;
#endif
}
else {
ret = unsafe_recv(buf, len);
}
if (ret <= 0) {
_handleRecvError(ret, len, &retries);
continue;
}
if ( len <= 4 && ret != len )
LOG(_logLevel) << "Socket recv() got " << ret <<
" bytes wanted len=" << len << endl;
fassert(16508, ret <= len);
len -= ret;
buf += ret;
}
}
示例2: invariant
StatusWith<CursorResponse> ClusterFind::runGetMore(OperationContext* txn,
const GetMoreRequest& request) {
auto cursorManager = grid.getCursorManager();
auto pinnedCursor = cursorManager->checkOutCursor(request.nss, request.cursorid);
if (!pinnedCursor.isOK()) {
return pinnedCursor.getStatus();
}
invariant(request.cursorid == pinnedCursor.getValue().getCursorId());
// If the fail point is enabled, busy wait until it is disabled.
while (MONGO_FAIL_POINT(keepCursorPinnedDuringGetMore)) {
}
if (request.awaitDataTimeout) {
auto status = pinnedCursor.getValue().setAwaitDataTimeout(*request.awaitDataTimeout);
if (!status.isOK()) {
return status;
}
}
std::vector<BSONObj> batch;
int bytesBuffered = 0;
long long batchSize = request.batchSize.value_or(0);
long long startingFrom = pinnedCursor.getValue().getNumReturnedSoFar();
auto cursorState = ClusterCursorManager::CursorState::NotExhausted;
while (!FindCommon::enoughForGetMore(batchSize, batch.size())) {
auto next = pinnedCursor.getValue().next();
if (!next.isOK()) {
return next.getStatus();
}
if (!next.getValue()) {
// We reached end-of-stream.
if (!pinnedCursor.getValue().isTailable()) {
cursorState = ClusterCursorManager::CursorState::Exhausted;
}
break;
}
if (!FindCommon::haveSpaceForNext(*next.getValue(), batch.size(), bytesBuffered)) {
pinnedCursor.getValue().queueResult(*next.getValue());
break;
}
// Add doc to the batch. Account for the space overhead associated with returning this doc
// inside a BSON array.
bytesBuffered += (next.getValue()->objsize() + kPerDocumentOverheadBytesUpperBound);
batch.push_back(std::move(*next.getValue()));
}
// Transfer ownership of the cursor back to the cursor manager.
pinnedCursor.getValue().returnCursor(cursorState);
CursorId idToReturn = (cursorState == ClusterCursorManager::CursorState::Exhausted)
? CursorId(0)
: request.cursorid;
return CursorResponse(request.nss, idToReturn, std::move(batch), startingFrom);
}
示例3: LOG
void NetworkInterfaceASIO::_asyncRunCommand(AsyncOp* op, NetworkOpHandler handler) {
LOG(2) << "Starting asynchronous command " << op->request().id << " on host "
<< op->request().target.toString();
if (MONGO_FAIL_POINT(NetworkInterfaceASIOasyncRunCommandFail)) {
_validateAndRun(op, asio::error::basic_errors::network_unreachable, [] {});
return;
}
// We invert the following steps below to run a command:
// 1 - send the given command
// 2 - receive a header for the response
// 3 - validate and receive response body
// 4 - advance the state machine by calling handler()
auto cmd = op->command();
// Step 4
auto recvMessageCallback = [this, cmd, handler, op](std::error_code ec, size_t bytes) {
// We don't call _validateAndRun here as we assume the caller will.
handler(ec, bytes);
};
// Step 3
auto recvHeaderCallback = [this, cmd, handler, recvMessageCallback, op](std::error_code ec,
size_t bytes) {
// The operation could have been canceled after starting the command, but before
// receiving the header
_validateAndRun(op, ec, [this, op, recvMessageCallback, ec, bytes, cmd, handler] {
// validate response id
uint32_t expectedId = cmd->toSend().header().getId();
uint32_t actualId = cmd->header().constView().getResponseToMsgId();
if (actualId != expectedId) {
LOG(3) << "got wrong response:"
<< " expected response id: " << expectedId
<< ", got response id: " << actualId;
return handler(make_error_code(ErrorCodes::ProtocolError), bytes);
}
asyncRecvMessageBody(cmd->conn().stream(),
&cmd->header(),
&cmd->toRecv(),
std::move(recvMessageCallback));
});
};
// Step 2
auto sendMessageCallback = [this, cmd, handler, recvHeaderCallback, op](std::error_code ec,
size_t bytes) {
_validateAndRun(op, ec, [this, cmd, op, recvHeaderCallback] {
asyncRecvMessageHeader(
cmd->conn().stream(), &cmd->header(), std::move(recvHeaderCallback));
});
};
// Step 1
asyncSendMessage(cmd->conn().stream(), &cmd->toSend(), std::move(sendMessageCallback));
}
示例4: hasDeadlineExpired
bool OperationContext::hasDeadlineExpired() const {
if (!hasDeadline()) {
return false;
}
if (MONGO_FAIL_POINT(maxTimeNeverTimeOut)) {
return false;
}
if (MONGO_FAIL_POINT(maxTimeAlwaysTimeOut)) {
return true;
}
// TODO: Remove once all OperationContexts are properly connected to Clients and ServiceContexts
// in tests.
if (MONGO_unlikely(!getClient() || !getServiceContext())) {
return false;
}
const auto now = getServiceContext()->getFastClockSource()->now();
return now >= getDeadline();
}
示例5: lock
void CollectionCloner::_insertDocumentsCallback(
const executor::TaskExecutor::CallbackArgs& cbd,
bool lastBatch,
std::shared_ptr<OnCompletionGuard> onCompletionGuard) {
if (!cbd.status.isOK()) {
stdx::lock_guard<stdx::mutex> lock(_mutex);
onCompletionGuard->setResultAndCancelRemainingWork_inlock(lock, cbd.status);
return;
}
UniqueLock lk(_mutex);
std::vector<BSONObj> docs;
if (_documentsToInsert.size() == 0) {
warning() << "_insertDocumentsCallback, but no documents to insert for ns:" << _destNss;
if (lastBatch) {
onCompletionGuard->setResultAndCancelRemainingWork_inlock(lk, Status::OK());
}
return;
}
_documentsToInsert.swap(docs);
_stats.documentsCopied += docs.size();
++_stats.fetchBatches;
_progressMeter.hit(int(docs.size()));
invariant(_collLoader);
const auto status = _collLoader->insertDocuments(docs.cbegin(), docs.cend());
if (!status.isOK()) {
onCompletionGuard->setResultAndCancelRemainingWork_inlock(lk, status);
return;
}
MONGO_FAIL_POINT_BLOCK(initialSyncHangDuringCollectionClone, options) {
const BSONObj& data = options.getData();
if (data["namespace"].String() == _destNss.ns() &&
static_cast<int>(_stats.documentsCopied) >= data["numDocsToClone"].numberInt()) {
lk.unlock();
log() << "initial sync - initialSyncHangDuringCollectionClone fail point "
"enabled. Blocking until fail point is disabled.";
while (MONGO_FAIL_POINT(initialSyncHangDuringCollectionClone) && !_isShuttingDown()) {
mongo::sleepsecs(1);
}
lk.lock();
}
}
if (lastBatch) {
// Clean up resources once the last batch has been copied over and set the status to OK.
onCompletionGuard->setResultAndCancelRemainingWork_inlock(lk, Status::OK());
}
}
示例6: while
// sends all data or throws an exception
void Socket::send( const char * data , int len, const char *context ) {
while( len > 0 ) {
int ret = _send( data , len );
if (ret == -1 || MONGO_FAIL_POINT(throwSockExcep)) {
_handleSendError(ret, context);
}
_bytesOut += ret;
fassert(16507, ret <= len);
len -= ret;
data += ret;
}
}
示例7: invariant
void WriteUnitOfWork::commit() {
invariant(!_committed);
invariant(!_released);
invariant(_opCtx->_ruState == RecoveryUnitState::kActiveUnitOfWork);
if (_toplevel) {
if (MONGO_FAIL_POINT(sleepBeforeCommit)) {
sleepFor(Milliseconds(100));
}
_opCtx->recoveryUnit()->commitUnitOfWork();
_opCtx->_ruState = RecoveryUnitState::kNotInUnitOfWork;
}
_opCtx->lockState()->endWriteUnitOfWork();
_committed = true;
}
示例8: _recordForV1
RecordFetcher* MmapV1ExtentManager::recordNeedsFetch( const DiskLoc& loc ) const {
Record* record = _recordForV1( loc );
// For testing: if failpoint is enabled we randomly request fetches without
// going to the RecordAccessTracker.
if ( MONGO_FAIL_POINT( recordNeedsFetchFail ) ) {
needsFetchFailCounter.increment();
if ( ( needsFetchFailCounter.get() % kNeedsFetchFailFreq ) == 0 ) {
return new MmapV1RecordFetcher( record );
}
}
if ( !_recordAccessTracker->checkAccessedAndMark( record ) ) {
return new MmapV1RecordFetcher( record );
}
return NULL;
}
示例9: _recordForV1
std::unique_ptr<RecordFetcher> MmapV1ExtentManager::recordNeedsFetch(const DiskLoc& loc) const {
if (loc.isNull()) return {};
MmapV1RecordHeader* record = _recordForV1( loc );
// For testing: if failpoint is enabled we randomly request fetches without
// going to the RecordAccessTracker.
if ( MONGO_FAIL_POINT( recordNeedsFetchFail ) ) {
needsFetchFailCounter.increment();
if ( ( needsFetchFailCounter.get() % kNeedsFetchFailFreq ) == 0 ) {
return stdx::make_unique<MmapV1RecordFetcher>( record );
}
}
if ( !_recordAccessTracker->checkAccessedAndMark( record ) ) {
return stdx::make_unique<MmapV1RecordFetcher>( record );
}
return {};
}
示例10: while
void Socket::recv(char* buf, int len) {
while (len > 0) {
int ret = -1;
if (MONGO_FAIL_POINT(throwSockExcep)) {
#if defined(_WIN32)
WSASetLastError(WSAENETUNREACH);
#else
errno = ENETUNREACH;
#endif
if (ret <= 0) {
handleRecvError(ret, len);
continue;
}
} else {
ret = unsafe_recv(buf, len);
}
fassert(16508, ret <= len);
len -= ret;
buf += ret;
}
}
示例11: MONGO_FAIL_POINT
int Balancer::_moveChunks(OperationContext* txn,
const BalancerChunkSelectionPolicy::MigrateInfoVector& candidateChunks,
const MigrationSecondaryThrottleOptions& secondaryThrottle,
bool waitForDelete) {
int movedCount = 0;
for (const auto& migrateInfo : candidateChunks) {
// If the balancer was disabled since we started this round, don't start new chunks
// moves.
if (!Grid::get(txn)->getBalancerConfiguration()->isBalancerActive() ||
MONGO_FAIL_POINT(skipBalanceRound)) {
LOG(1) << "Stopping balancing round early as balancing was disabled";
return movedCount;
}
// Changes to metadata, borked metadata, and connectivity problems between shards
// should cause us to abort this chunk move, but shouldn't cause us to abort the entire
// round of chunks.
//
// TODO(spencer): We probably *should* abort the whole round on issues communicating
// with the config servers, but its impossible to distinguish those types of failures
// at the moment.
//
// TODO: Handle all these things more cleanly, since they're expected problems
const NamespaceString nss(migrateInfo.ns);
try {
shared_ptr<DBConfig> cfg =
uassertStatusOK(grid.catalogCache()->getDatabase(txn, nss.db().toString()));
// NOTE: We purposely do not reload metadata here, since _getCandidateChunks already
// tried to do so once
shared_ptr<ChunkManager> cm = cfg->getChunkManager(txn, migrateInfo.ns);
uassert(28628,
str::stream()
<< "Collection " << migrateInfo.ns
<< " was deleted while balancing was active. Aborting balancing round.",
cm);
shared_ptr<Chunk> c = cm->findIntersectingChunk(txn, migrateInfo.minKey);
if (c->getMin().woCompare(migrateInfo.minKey) ||
c->getMax().woCompare(migrateInfo.maxKey)) {
// Likely a split happened somewhere, so force reload the chunk manager
cm = cfg->getChunkManager(txn, migrateInfo.ns, true);
invariant(cm);
c = cm->findIntersectingChunk(txn, migrateInfo.minKey);
if (c->getMin().woCompare(migrateInfo.minKey) ||
c->getMax().woCompare(migrateInfo.maxKey)) {
log() << "chunk mismatch after reload, ignoring will retry issue "
<< migrateInfo;
continue;
}
}
BSONObj res;
if (c->moveAndCommit(txn,
migrateInfo.to,
Grid::get(txn)->getBalancerConfiguration()->getMaxChunkSizeBytes(),
secondaryThrottle,
waitForDelete,
0, /* maxTimeMS */
res)) {
movedCount++;
continue;
}
log() << "balancer move failed: " << res << ", migrate: " << migrateInfo;
Status moveStatus = getStatusFromCommandResult(res);
if (moveStatus == ErrorCodes::ChunkTooBig || res["chunkTooBig"].trueValue()) {
// Reload just to be safe
cm = cfg->getChunkManager(txn, migrateInfo.ns);
invariant(cm);
c = cm->findIntersectingChunk(txn, migrateInfo.minKey);
log() << "performing a split because migrate failed for size reasons";
auto splitStatus = c->split(txn, Chunk::normal, NULL);
if (!splitStatus.isOK()) {
log() << "marking chunk as jumbo: " << c->toString();
c->markAsJumbo(txn);
// We increment moveCount so we do another round right away
movedCount++;
}
}
} catch (const DBException& ex) {
log() << "balancer move " << migrateInfo << " failed" << causedBy(ex);
}
}
return movedCount;
//.........这里部分代码省略.........
示例12: while
void Balancer::run() {
Client::initThread("Balancer");
// This is the body of a BackgroundJob so if we throw here we're basically ending the balancer
// thread prematurely.
while (!inShutdown()) {
auto txn = cc().makeOperationContext();
if (!_init(txn.get())) {
log() << "will retry to initialize balancer in one minute";
sleepsecs(60);
continue;
}
break;
}
Seconds balanceRoundInterval(kBalanceRoundDefaultInterval);
while (!inShutdown()) {
auto txn = cc().makeOperationContext();
BalanceRoundDetails roundDetails;
try {
// ping has to be first so we keep things in the config server in sync
_ping(txn.get(), false);
MONGO_FAIL_POINT_BLOCK(balancerRoundIntervalSetting, scopedBalancerRoundInterval) {
const BSONObj& data = scopedBalancerRoundInterval.getData();
balanceRoundInterval = Seconds(data["sleepSecs"].numberInt());
}
// Use fresh shard state and balancer settings
Grid::get(txn.get())->shardRegistry()->reload(txn.get());
auto balancerConfig = Grid::get(txn.get())->getBalancerConfiguration();
Status refreshStatus = balancerConfig->refreshAndCheck(txn.get());
if (!refreshStatus.isOK()) {
warning() << "Skipping balancing round" << causedBy(refreshStatus);
sleepFor(balanceRoundInterval);
continue;
}
// now make sure we should even be running
if (!balancerConfig->isBalancerActive() || MONGO_FAIL_POINT(skipBalanceRound)) {
LOG(1) << "skipping balancing round because balancing is disabled";
// Ping again so scripts can determine if we're active without waiting
_ping(txn.get(), true);
sleepFor(balanceRoundInterval);
continue;
}
uassert(13258, "oids broken after resetting!", _checkOIDs(txn.get()));
{
auto scopedDistLock = grid.catalogManager(txn.get())
->distLock(txn.get(),
"balancer",
"doing balance round",
DistLockManager::kSingleLockAttemptTimeout);
if (!scopedDistLock.isOK()) {
LOG(1) << "skipping balancing round" << causedBy(scopedDistLock.getStatus());
// Ping again so scripts can determine if we're active without waiting
_ping(txn.get(), true);
sleepFor(balanceRoundInterval); // no need to wake up soon
continue;
}
LOG(1) << "*** start balancing round. "
<< "waitForDelete: " << balancerConfig->waitForDelete()
<< ", secondaryThrottle: "
<< balancerConfig->getSecondaryThrottle().toBSON();
OCCASIONALLY warnOnMultiVersion(
uassertStatusOK(_clusterStats->getStats(txn.get())));
Status status = _enforceTagRanges(txn.get());
if (!status.isOK()) {
warning() << "Failed to enforce tag ranges" << causedBy(status);
} else {
LOG(1) << "Done enforcing tag range boundaries.";
}
const auto candidateChunks = uassertStatusOK(
_chunkSelectionPolicy->selectChunksToMove(txn.get(), _balancedLastTime));
if (candidateChunks.empty()) {
LOG(1) << "no need to move any chunk";
_balancedLastTime = 0;
} else {
_balancedLastTime = _moveChunks(txn.get(),
candidateChunks,
balancerConfig->getSecondaryThrottle(),
balancerConfig->waitForDelete());
//.........这里部分代码省略.........
示例13: LOG
void Socket::_handleSendError(int ret, const char* context) {
#ifdef MONGO_SSL
if (_ssl) {
LOG(_logLevel) << "SSL Error ret: " << ret << " err: " << SSL_get_error(_ssl , ret)
<< " " << ERR_error_string(ERR_get_error(), NULL)
<< endl;
throw SocketException(SocketException::SEND_ERROR , remoteString());
}
#endif
#if defined(_WIN32)
const int mongo_errno = WSAGetLastError();
if ( mongo_errno == WSAETIMEDOUT && _timeout != 0 ) {
#else
const int mongo_errno = errno;
if ( ( mongo_errno == EAGAIN || mongo_errno == EWOULDBLOCK ) && _timeout != 0 ) {
#endif
LOG(_logLevel) << "Socket " << context <<
" send() timed out " << remoteString() << endl;
throw SocketException(SocketException::SEND_TIMEOUT , remoteString());
}
else {
LOG(_logLevel) << "Socket " << context << " send() "
<< errnoWithDescription(mongo_errno) << ' ' << remoteString() << endl;
throw SocketException(SocketException::SEND_ERROR , remoteString());
}
}
void Socket::_handleRecvError(int ret, int len, int* retries) {
if (ret == 0 || MONGO_FAIL_POINT(throwSockExcep)) {
LOG(3) << "Socket recv() conn closed? " << remoteString() << endl;
throw SocketException(SocketException::CLOSED , remoteString());
}
// ret < 0
#ifdef MONGO_SSL
if (_ssl) {
LOG(_logLevel) << "SSL Error ret: " << ret << " err: " << SSL_get_error(_ssl , ret)
<< " " << ERR_error_string(ERR_get_error(), NULL)
<< endl;
throw SocketException(SocketException::RECV_ERROR, remoteString());
}
#endif
#if defined(_WIN32)
int e = WSAGetLastError();
#else
int e = errno;
# if defined(EINTR)
if (e == EINTR) {
LOG(_logLevel) << "EINTR retry " << ++*retries << endl;
return;
}
# endif
#endif
#if defined(_WIN32)
// Windows
if ((e == EAGAIN || e == WSAETIMEDOUT) && _timeout > 0) {
#else
if (e == EAGAIN && _timeout > 0) {
#endif
// this is a timeout
LOG(_logLevel) << "Socket recv() timeout " << remoteString() <<endl;
throw SocketException(SocketException::RECV_TIMEOUT, remoteString());
}
LOG(_logLevel) << "Socket recv() " <<
errnoWithDescription(e) << " " << remoteString() <<endl;
throw SocketException(SocketException::RECV_ERROR , remoteString());
}
void Socket::setTimeout( double secs ) {
setSockTimeouts( _fd, secs );
}
#if defined(_WIN32)
struct WinsockInit {
WinsockInit() {
WSADATA d;
if ( WSAStartup(MAKEWORD(2,2), &d) != 0 ) {
out() << "ERROR: wsastartup failed " << errnoWithDescription() << endl;
problem() << "ERROR: wsastartup failed " << errnoWithDescription() << endl;
_exit(EXIT_NTSERVICE_ERROR);
}
}
} winsock_init;
#endif
} // namespace mongo
示例14: _send
/** sends all data or throws an exception
* @param context descriptive for logging
*/
void Socket::send( const vector< pair< char *, int > > &data, const char *context ) {
#ifdef MONGO_SSL
if ( _ssl ) {
_send( data , context );
return;
}
#endif
#if defined(_WIN32)
// TODO use scatter/gather api
_send( data , context );
#else
vector<struct iovec> d( data.size() );
int i = 0;
for (vector< pair<char *, int> >::const_iterator j = data.begin();
j != data.end();
++j) {
if ( j->second > 0 ) {
d[ i ].iov_base = j->first;
d[ i ].iov_len = j->second;
++i;
_bytesOut += j->second;
}
}
struct msghdr meta;
memset( &meta, 0, sizeof( meta ) );
meta.msg_iov = &d[ 0 ];
meta.msg_iovlen = d.size();
while( meta.msg_iovlen > 0 ) {
int ret = ::sendmsg( _fd , &meta , portSendFlags );
if ( ret == -1 || MONGO_FAIL_POINT(throwSockExcep)) {
if ( errno != EAGAIN || _timeout == 0 ) {
LOG(_logLevel) << "Socket " << context <<
" send() " << errnoWithDescription() << ' ' << remoteString() << endl;
throw SocketException( SocketException::SEND_ERROR , remoteString() );
}
else {
LOG(_logLevel) << "Socket " << context <<
" send() remote timeout " << remoteString() << endl;
throw SocketException( SocketException::SEND_TIMEOUT , remoteString() );
}
}
else {
struct iovec *& i = meta.msg_iov;
while( ret > 0 ) {
if ( i->iov_len > unsigned( ret ) ) {
i->iov_len -= ret;
i->iov_base = (char*)(i->iov_base) + ret;
ret = 0;
}
else {
ret -= i->iov_len;
++i;
--(meta.msg_iovlen);
}
}
}
}
#endif
}
示例15: while
void WiredTigerOplogManager::_oplogJournalThreadLoop(WiredTigerSessionCache* sessionCache,
WiredTigerRecordStore* oplogRecordStore,
const bool updateOldestTimestamp) noexcept {
Client::initThread("WTOplogJournalThread");
// This thread updates the oplog read timestamp, the timestamp used to read from the oplog with
// forward cursors. The timestamp is used to hide oplog entries that might be committed but
// have uncommitted entries ahead of them.
while (true) {
stdx::unique_lock<stdx::mutex> lk(_oplogVisibilityStateMutex);
{
MONGO_IDLE_THREAD_BLOCK;
_opsWaitingForJournalCV.wait(lk,
[&] { return _shuttingDown || _opsWaitingForJournal; });
// If we're not shutting down and nobody is actively waiting for the oplog to become
// durable, delay journaling a bit to reduce the sync rate.
auto journalDelay = Milliseconds(storageGlobalParams.journalCommitIntervalMs.load());
if (journalDelay == Milliseconds(0)) {
journalDelay = Milliseconds(WiredTigerKVEngine::kDefaultJournalDelayMillis);
}
auto now = Date_t::now();
auto deadline = now + journalDelay;
auto shouldSyncOpsWaitingForJournal = [&] {
return _shuttingDown || _opsWaitingForVisibility ||
oplogRecordStore->haveCappedWaiters();
};
// Eventually it would be more optimal to merge this with the normal journal flushing
// and block for either oplog tailers or operations waiting for oplog visibility. For
// now this loop will poll once a millisecond up to the journalDelay to see if we have
// any waiters yet. This reduces sync-related I/O on the primary when secondaries are
// lagged, but will avoid significant delays in confirming majority writes on replica
// sets with infrequent writes.
// Callers of waitForAllEarlierOplogWritesToBeVisible() like causally consistent reads
// will preempt this delay.
while (now < deadline &&
!_opsWaitingForJournalCV.wait_until(
lk, now.toSystemTimePoint(), shouldSyncOpsWaitingForJournal)) {
now += Milliseconds(1);
}
}
while (!_shuttingDown && MONGO_FAIL_POINT(WTPausePrimaryOplogDurabilityLoop)) {
lk.unlock();
sleepmillis(10);
lk.lock();
}
if (_shuttingDown) {
log() << "oplog journal thread loop shutting down";
return;
}
invariant(_opsWaitingForJournal);
_opsWaitingForJournal = false;
lk.unlock();
const uint64_t newTimestamp = fetchAllCommittedValue(sessionCache->conn());
// The newTimestamp may actually go backward during secondary batch application,
// where we commit data file changes separately from oplog changes, so ignore
// a non-incrementing timestamp.
if (newTimestamp <= _oplogReadTimestamp.load()) {
LOG(2) << "no new oplog entries were made visible: " << newTimestamp;
continue;
}
// In order to avoid oplog holes after an unclean shutdown, we must ensure this proposed
// oplog read timestamp's documents are durable before publishing that timestamp.
sessionCache->waitUntilDurable(/*forceCheckpoint=*/false, false);
lk.lock();
// Publish the new timestamp value. Avoid going backward.
auto oldTimestamp = getOplogReadTimestamp();
if (newTimestamp > oldTimestamp) {
_setOplogReadTimestamp(lk, newTimestamp);
}
lk.unlock();
if (updateOldestTimestamp) {
const bool force = false;
sessionCache->getKVEngine()->setOldestTimestamp(Timestamp(newTimestamp), force);
}
// Wake up any await_data cursors and tell them more data might be visible now.
oplogRecordStore->notifyCappedWaitersIfNeeded();
}
}