Esempio n. 1
0
bool BackgroundJob::wait(unsigned msTimeOut) {
    verify(!_selfDelete);  // you cannot call wait on a self-deleting job
    const auto deadline = Date_t::now() + Milliseconds(msTimeOut);
    stdx::unique_lock<stdx::mutex> l(_status->mutex);
    while (_status->state != Done) {
        if (msTimeOut) {
            if (stdx::cv_status::timeout ==
                _status->done.wait_until(l, deadline.toSystemTimePoint()))
                return false;
        } else {
            _status->done.wait(l);
        }
    }
    return true;
}
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();
    }
}
Esempio n. 3
0
void ThreadPool::_consumeTasks() {
    stdx::unique_lock<stdx::mutex> lk(_mutex);
    while (_state == running) {
        if (_pendingTasks.empty()) {
            if (_threads.size() > _options.minThreads) {
                // Since there are more than minThreads threads, this thread may be eligible for
                // retirement. If it isn't now, it may be later, so it must put a time limit on how
                // long it waits on _workAvailable.
                const auto now = Date_t::now();
                const auto nextThreadRetirementDate =
                    _lastFullUtilizationDate + _options.maxIdleThreadAge;
                if (now >= nextThreadRetirementDate) {
                    _lastFullUtilizationDate = now;
                    LOG(1) << "Reaping this thread; next thread reaped no earlier than "
                           << _lastFullUtilizationDate + _options.maxIdleThreadAge;
                    break;
                }

                LOG(3) << "Not reaping because the earliest retirement date is "
                       << nextThreadRetirementDate;
                _workAvailable.wait_until(lk, nextThreadRetirementDate.toSystemTimePoint());
            } else {
                // Since the number of threads is not more than minThreads, this thread is not
                // eligible for retirement. It is OK to sleep until _workAvailable is signaled,
                // because any new threads that put the number of total threads above minThreads
                // would be eligible for retirement once they had no work left to do.
                LOG(3) << "waiting for work; I am one of " << _threads.size() << " thread(s);"
                       << " the minimum number of threads is " << _options.minThreads;
                _workAvailable.wait(lk);
            }
            continue;
        }

        _doOneTask(&lk);
    }

    // We still hold the lock, but this thread is retiring. If the whole pool is shutting down, this
    // thread lends a hand in draining the work pool and returns so it can be joined. Otherwise, it
    // falls through to the detach code, below.

    if (_state == joinRequired || _state == joining) {
        // Drain the leftover pending tasks.
        while (!_pendingTasks.empty()) {
            _doOneTask(&lk);
        }
        --_numIdleThreads;
        return;
    }
    --_numIdleThreads;

    if (_state != running) {
        severe() << "State of pool " << _options.poolName << " is " << static_cast<int32_t>(_state)
                 << ", but expected " << static_cast<int32_t>(running);
        fassertFailedNoTrace(28701);
    }

    // This thread is ending because it was idle for too long.  Find self in _threads, remove self
    // from _threads, detach self.
    for (size_t i = 0; i < _threads.size(); ++i) {
        auto& t = _threads[i];
        if (t.get_id() != stdx::this_thread::get_id()) {
            continue;
        }
        t.detach();
        t.swap(_threads.back());
        _threads.pop_back();
        return;
    }
    severe().stream() << "Could not find this thread, with id " << stdx::this_thread::get_id()
                      << " in pool " << _options.poolName;
    fassertFailedNoTrace(28703);
}
Esempio n. 4
0
void FTDCController::doLoop() {
    try {
        // Update config
        {
            stdx::lock_guard<stdx::mutex> lock(_mutex);
            _config = _configTemp;
        }

        Client::initThread("ftdc");
        Client* client = &cc();

        auto swMgr = FTDCFileManager::create(&_config, _path, &_rotateCollectors, client);

        _mgr = uassertStatusOK(std::move(swMgr));

        while (true) {
            // Compute the next interval to run regardless of how we were woken up
            // Skipping an interval due to a race condition with a config signal is harmless.
            auto now = getGlobalServiceContext()->getClockSource()->now();

            // Get next time to run at
            auto next_time = FTDCUtil::roundTime(now, _config.period);

            // Wait for the next run or signal to shutdown
            {
                stdx::unique_lock<stdx::mutex> lock(_mutex);

                // We ignore spurious wakeups by just doing an iteration of the loop
                auto status = _condvar.wait_until(lock, next_time.toSystemTimePoint());

                // Are we done running?
                if (_state == State::kStopRequested) {
                    break;
                }

                // if we hit a timeout on the condvar, we need to do another collection
                // if we were signalled, then we have a config update only or were asked to stop
                if (status == stdx::cv_status::no_timeout) {
                    // Update the current configuration settings
                    _config = _configTemp;

                    continue;
                }
            }

            // TODO: consider only running this thread if we are enabled
            // for now, we just keep an idle thread as it is simplier
            if (_config.enabled) {
                BSONObj obj = _periodicCollectors.collect(client);

                Status s = _mgr->writeSampleAndRotateIfNeeded(client, obj);

                uassertStatusOK(s);
            }
        }
    } catch (...) {
        warning() << "Uncaught exception in '" << exceptionToStatus()
                  << "' in full-time diagnostic data capture subsystem. Shutting down the "
                     "full-time diagnostic data capture subsystem.";
    }
}