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); }
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()); 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(), bytesBuffered)) { 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 adding this object will cause us to exceed the BSON size limit, then we stash it for // later. By using BSONObjMaxUserSize, we ensure that there is enough room for the // "envelope" (e.g. the "ns" and "id" fields included in the response) before exceeding // BSONObjMaxInternalSize. int sizeEstimate = bytesBuffered + next.getValue()->objsize() + ((batch.size() + 1U) * kPerDocumentOverheadBytesUpperBound); if (sizeEstimate > BSONObjMaxUserSize && !batch.empty()) { pinnedCursor.getValue().queueResult(*next.getValue()); break; } // Add doc to the batch. bytesBuffered += next.getValue()->objsize(); 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); }
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()); 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(), bytesBuffered)) { 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; } // Add doc to the batch. bytesBuffered += next.getValue()->objsize(); 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); }