StatusWith<CursorId> ClusterCursorManager::registerCursor( std::unique_ptr<ClusterClientCursor> cursor, const NamespaceString& nss, CursorType cursorType, CursorLifetime cursorLifetime) { // Read the clock out of the lock. const auto now = _clockSource->now(); stdx::unique_lock<stdx::mutex> lk(_mutex); if (_inShutdown) { lk.unlock(); cursor->kill(); return Status(ErrorCodes::ShutdownInProgress, "Cannot register new cursors as we are in the process of shutting down"); } invariant(cursor); // Find the CursorEntryContainer for this namespace. If none exists, create one. auto nsToContainerIt = _namespaceToContainerMap.find(nss); if (nsToContainerIt == _namespaceToContainerMap.end()) { uint32_t containerPrefix = 0; do { // The server has always generated positive values for CursorId (which is a signed // type), so we use std::abs() here on the prefix for consistency with this historical // behavior. containerPrefix = static_cast<uint32_t>(std::abs(_pseudoRandom.nextInt32())); } while (_cursorIdPrefixToNamespaceMap.count(containerPrefix) > 0); _cursorIdPrefixToNamespaceMap[containerPrefix] = nss; auto emplaceResult = _namespaceToContainerMap.emplace(nss, CursorEntryContainer(containerPrefix)); invariant(emplaceResult.second); invariant(_namespaceToContainerMap.size() == _cursorIdPrefixToNamespaceMap.size()); nsToContainerIt = emplaceResult.first; } else { invariant(!nsToContainerIt->second.entryMap.empty()); // If exists, shouldn't be empty. } CursorEntryContainer& container = nsToContainerIt->second; // Generate a CursorId (which can't be the invalid value zero). CursorEntryMap& entryMap = container.entryMap; CursorId cursorId = 0; do { const uint32_t cursorSuffix = static_cast<uint32_t>(_pseudoRandom.nextInt32()); cursorId = createCursorId(container.containerPrefix, cursorSuffix); } while (cursorId == 0 || entryMap.count(cursorId) > 0); // Create a new CursorEntry and register it in the CursorEntryContainer's map. auto emplaceResult = entryMap.emplace(cursorId, CursorEntry(std::move(cursor), cursorType, cursorLifetime, now)); invariant(emplaceResult.second); return cursorId; }
ClusterCursorManager::PinnedCursor ClusterCursorManager::registerCursor( std::unique_ptr<ClusterClientCursor> cursor, const NamespaceString& nss, CursorType cursorType, CursorLifetime cursorLifetime) { stdx::lock_guard<stdx::mutex> lk(_mutex); invariant(cursor); // Find the CursorEntryContainer for this namespace. If none exists, create one. auto nsToContainerIt = _namespaceToContainerMap.find(nss); if (nsToContainerIt == _namespaceToContainerMap.end()) { uint32_t containerPrefix = 0; do { // The server has always generated positive values for CursorId (which is a signed // type), so we use std::abs() here on the prefix for consistency with this historical // behavior. containerPrefix = static_cast<uint32_t>(std::abs(_pseudoRandom.nextInt32())); } while (_cursorIdPrefixToNamespaceMap.count(containerPrefix) > 0); _cursorIdPrefixToNamespaceMap[containerPrefix] = nss; auto emplaceResult = _namespaceToContainerMap.emplace(nss, CursorEntryContainer(containerPrefix)); invariant(emplaceResult.second); invariant(_namespaceToContainerMap.size() == _cursorIdPrefixToNamespaceMap.size()); nsToContainerIt = emplaceResult.first; } else { invariant(!nsToContainerIt->second.entryMap.empty()); // If exists, shouldn't be empty. } CursorEntryContainer& container = nsToContainerIt->second; // Generate a CursorId (which can't be the invalid value zero). CursorEntryMap& entryMap = container.entryMap; CursorId cursorId = 0; do { const uint32_t cursorSuffix = static_cast<uint32_t>(_pseudoRandom.nextInt32()); cursorId = createCursorId(container.containerPrefix, cursorSuffix); } while (cursorId == 0 || entryMap.count(cursorId) > 0); // Create a new CursorEntry and register it in the CursorEntryContainer's map. auto emplaceResult = entryMap.emplace( cursorId, CursorEntry(std::move(cursor), cursorType, cursorLifetime, _clockSource->now())); invariant(emplaceResult.second); // Pin and return the cursor. Note that pinning a cursor transfers ownership of the underlying // ClusterClientCursor object to the pin; the CursorEntry is left with a null // ClusterClientCursor. CursorEntry& entry = emplaceResult.first->second; return PinnedCursor(this, entry.releaseCursor(), nss, cursorId); }