bool MigrationSourceManager::transferMods(OperationContext* txn, const MigrationSessionId& sessionId, string& errmsg, BSONObjBuilder& b) { long long size = 0; { AutoGetCollectionForRead ctx(txn, _getNS()); stdx::lock_guard<stdx::mutex> sl(_mutex); if (!_sessionId) { errmsg = "no active migration!"; return false; } // TODO after 3.4 release, !sessionId.isEmpty() can be removed: versions >= 3.2 will // all have sessionId implemented. (two more instances below). // A mongod version < v3.2 will not have sessionId, in which case it is empty and ignored. if (!sessionId.isEmpty() && !_sessionId->matches(sessionId)) { errmsg = str::stream() << "requested migration session id " << sessionId.toString() << " does not match active session id " << _sessionId->toString(); return false; } // TODO: fix SERVER-16540 race _xfer(txn, _nss.ns(), ctx.getDb(), &_deleted, b, "deleted", size, false); _xfer(txn, _nss.ns(), ctx.getDb(), &_reload, b, "reload", size, true); } b.append("size", size); return true; }
void StartChunkCloneRequest::appendAsCommand( BSONObjBuilder* builder, const NamespaceString& nss, const MigrationSessionId& sessionId, const ConnectionString& configServerConnectionString, const ConnectionString& fromShardConnectionString, const ShardId& fromShardId, const ShardId& toShardId, const BSONObj& chunkMinKey, const BSONObj& chunkMaxKey, const BSONObj& shardKeyPattern, const MigrationSecondaryThrottleOptions& secondaryThrottle) { invariant(builder->asTempObj().isEmpty()); invariant(nss.isValid()); invariant(fromShardConnectionString.isValid()); builder->append(kRecvChunkStart, nss.ns()); sessionId.append(builder); builder->append(kConfigServerConnectionString, configServerConnectionString.toString()); builder->append(kFromShardConnectionString, fromShardConnectionString.toString()); builder->append(kFromShardId, fromShardId.toString()); builder->append(kToShardId, toShardId.toString()); builder->append(kChunkMinKey, chunkMinKey); builder->append(kChunkMaxKey, chunkMaxKey); builder->append(kShardKeyPattern, shardKeyPattern); secondaryThrottle.append(builder); }
/** * Create the migration transfer mods request BSON object to send to the source shard. * * 'sessionId' unique identifier for this migration. */ BSONObj createTransferModsRequest(const NamespaceString& nss, const MigrationSessionId& sessionId) { BSONObjBuilder builder; builder.append("_transferMods", nss.ns()); sessionId.append(&builder); return builder.obj(); }
/** * Create the migration clone request BSON object to send to the source shard. * * 'sessionId' unique identifier for this migration. */ BSONObj createMigrateCloneRequest(const NamespaceString& nss, const MigrationSessionId& sessionId) { BSONObjBuilder builder; builder.append("_migrateClone", nss.ns()); sessionId.append(&builder); return builder.obj(); }
bool MigrationSourceManager::clone(OperationContext* txn, const MigrationSessionId& sessionId, string& errmsg, BSONObjBuilder& result) { ElapsedTracker tracker(internalQueryExecYieldIterations, internalQueryExecYieldPeriodMS); int allocSize = 0; { AutoGetCollection autoColl(txn, _getNS(), MODE_IS); stdx::lock_guard<stdx::mutex> sl(_mutex); if (!_sessionId) { errmsg = "not active"; return false; } // A mongod version < v3.2 will not have sessionId, in which case it is empty and ignored. if (!sessionId.isEmpty() && !_sessionId->matches(sessionId)) { errmsg = str::stream() << "requested migration session id " << sessionId.toString() << " does not match active session id " << _sessionId->toString(); return false; } Collection* collection = autoColl.getCollection(); if (!collection) { errmsg = str::stream() << "collection " << _nss.toString() << " does not exist"; return false; } allocSize = std::min( BSONObjMaxUserSize, static_cast<int>((12 + collection->averageObjectSize(txn)) * cloneLocsRemaining())); } bool isBufferFilled = false; BSONArrayBuilder clonedDocsArrayBuilder(allocSize); while (!isBufferFilled) { AutoGetCollection autoColl(txn, _getNS(), MODE_IS); stdx::lock_guard<stdx::mutex> sl(_mutex); if (!_sessionId) { errmsg = "not active"; return false; } // A mongod version < v3.2 will not have sessionId, in which case it is empty and ignored. if (!sessionId.isEmpty() && !_sessionId->matches(sessionId)) { errmsg = str::stream() << "migration session id changed from " << sessionId.toString() << " to " << _sessionId->toString() << " while initial clone was active"; return false; } // TODO: fix SERVER-16540 race Collection* collection = autoColl.getCollection(); if (!collection) { errmsg = str::stream() << "collection " << _nss.toString() << " does not exist"; return false; } stdx::lock_guard<stdx::mutex> lk(_cloneLocsMutex); std::set<RecordId>::iterator cloneLocsIter = _cloneLocs.begin(); for (; cloneLocsIter != _cloneLocs.end(); ++cloneLocsIter) { if (tracker.intervalHasElapsed()) // should I yield? break; RecordId recordId = *cloneLocsIter; Snapshotted<BSONObj> doc; if (!collection->findDoc(txn, recordId, &doc)) { // doc was deleted continue; } // Use the builder size instead of accumulating 'doc's size so that we take // into consideration the overhead of BSONArray indices, and *always* // append one doc. if (clonedDocsArrayBuilder.arrSize() != 0 && (clonedDocsArrayBuilder.len() + doc.value().objsize() + 1024) > BSONObjMaxUserSize) { isBufferFilled = true; // break out of outer while loop break; } clonedDocsArrayBuilder.append(doc.value()); } _cloneLocs.erase(_cloneLocs.begin(), cloneLocsIter); // Note: must be holding _cloneLocsMutex, don't move this inside while condition! if (_cloneLocs.empty()) { break; } } result.appendArray("objects", clonedDocsArrayBuilder.arr()); return true; }