StatusWith<std::unique_ptr<ClusterClientCursor>> ClusterCursorManager::detachCursor_inlock( const NamespaceString& nss, CursorId cursorId) { CursorEntry* entry = getEntry_inlock(nss, cursorId); if (!entry) { return cursorNotFoundStatus(nss, cursorId); } std::unique_ptr<ClusterClientCursor> cursor = entry->releaseCursor(); if (!cursor) { return cursorInUseStatus(nss, cursorId); } auto nsToContainerIt = _namespaceToContainerMap.find(nss); invariant(nsToContainerIt != _namespaceToContainerMap.end()); CursorEntryMap& entryMap = nsToContainerIt->second.entryMap; size_t eraseResult = entryMap.erase(cursorId); invariant(1 == eraseResult); if (entryMap.empty()) { // This was the last cursor remaining in the given namespace. Erase all state associated // with this namespace. size_t numDeleted = _cursorIdPrefixToNamespaceMap.erase(nsToContainerIt->second.containerPrefix); invariant(numDeleted == 1); _namespaceToContainerMap.erase(nsToContainerIt); invariant(_namespaceToContainerMap.size() == _cursorIdPrefixToNamespaceMap.size()); } return std::move(cursor); }
void ClusterCursorManager::checkInCursor(std::unique_ptr<ClusterClientCursor> cursor, const NamespaceString& nss, CursorId cursorId, CursorState cursorState) { stdx::unique_lock<stdx::mutex> lk(_mutex); invariant(cursor); const bool remotesExhausted = cursor->remotesExhausted(); CursorEntry* entry = getEntry_inlock(nss, cursorId); invariant(entry); entry->returnCursor(std::move(cursor)); if (cursorState == CursorState::NotExhausted || entry->getKillPending()) { return; } if (!remotesExhausted) { // The cursor still has open remote cursors that need to be cleaned up. Schedule for // deletion by the reaper thread by setting the kill pending flag. entry->setKillPending(); return; } // The cursor is exhausted, is not already scheduled for deletion, and does not have any // remote cursor state left to clean up. We can delete the cursor right away. auto detachedCursor = detachCursor_inlock(nss, cursorId); invariantOK(detachedCursor.getStatus()); // Deletion of the cursor can happen out of the lock. lk.unlock(); detachedCursor.getValue().reset(); }
StatusWith<ClusterCursorManager::PinnedCursor> ClusterCursorManager::checkOutCursor( const NamespaceString& nss, CursorId cursorId) { // Read the clock out of the lock. const auto now = _clockSource->now(); stdx::lock_guard<stdx::mutex> lk(_mutex); if (_inShutdown) { return Status(ErrorCodes::ShutdownInProgress, "Cannot check out cursor as we are in the process of shutting down"); } CursorEntry* entry = getEntry_inlock(nss, cursorId); if (!entry) { return cursorNotFoundStatus(nss, cursorId); } if (entry->getKillPending()) { return cursorNotFoundStatus(nss, cursorId); } std::unique_ptr<ClusterClientCursor> cursor = entry->releaseCursor(); if (!cursor) { return cursorInUseStatus(nss, cursorId); } entry->setLastActive(now); // Note that pinning a cursor transfers ownership of the underlying ClusterClientCursor object // to the pin; the CursorEntry is left with a null ClusterClientCursor. return PinnedCursor(this, std::move(cursor), nss, cursorId); }
Status ClusterCursorManager::killCursor(const NamespaceString& nss, CursorId cursorId) { stdx::lock_guard<stdx::mutex> lk(_mutex); CursorEntry* entry = getEntry_inlock(nss, cursorId); if (!entry) { return cursorNotFoundStatus(nss, cursorId); } entry->setKillPending(); return Status::OK(); }
void ClusterCursorManager::checkInCursor(std::unique_ptr<ClusterClientCursor> cursor, const NamespaceString& nss, CursorId cursorId, CursorState cursorState) { stdx::lock_guard<stdx::mutex> lk(_mutex); invariant(cursor); CursorEntry* entry = getEntry_inlock(nss, cursorId); invariant(entry); entry->returnCursor(std::move(cursor)); if (cursorState == CursorState::NotExhausted || entry->getKillPending()) { return; } // The cursor is exhausted, and the cursor doesn't already have a pending kill. Schedule for // deletion by setting the kill pending flag. entry->setKillPending(); }
StatusWith<ClusterCursorManager::PinnedCursor> ClusterCursorManager::checkOutCursor( const NamespaceString& nss, CursorId cursorId) { stdx::lock_guard<stdx::mutex> lk(_mutex); CursorEntry* entry = getEntry_inlock(nss, cursorId); if (!entry) { return cursorNotFoundStatus(nss, cursorId); } if (entry->getKillPending()) { return cursorNotFoundStatus(nss, cursorId); } std::unique_ptr<ClusterClientCursor> cursor = entry->releaseCursor(); if (!cursor) { return cursorInUseStatus(nss, cursorId); } entry->setLastActive(_clockSource->now()); // Note that pinning a cursor transfers ownership of the underlying ClusterClientCursor object // to the pin; the CursorEntry is left with a null ClusterClientCursor. return PinnedCursor(this, std::move(cursor), nss, cursorId); }