void CollectionShardingState::checkShardVersionOrThrow(OperationContext* opCtx) { std::string errmsg; ChunkVersion received; ChunkVersion wanted; if (!_checkShardVersionOk(opCtx, &errmsg, &received, &wanted)) { uasserted(StaleConfigInfo(_nss.ns(), received, wanted), str::stream() << "shard version not ok: " << errmsg); } }
void CollectionShardingState::checkShardVersionOrThrow(OperationContext* opCtx) { const auto optReceivedShardVersion = getOperationReceivedVersion(opCtx, _nss); if (!optReceivedShardVersion) return; const auto& receivedShardVersion = *optReceivedShardVersion; if (ChunkVersion::isIgnoredVersion(receivedShardVersion)) { return; } // An operation with read concern 'available' should never have shardVersion set. invariant(repl::ReadConcernArgs::get(opCtx).getLevel() != repl::ReadConcernLevel::kAvailableReadConcern); const auto metadata = getCurrentMetadata(); const auto wantedShardVersion = metadata->isSharded() ? metadata->getShardVersion() : ChunkVersion::UNSHARDED(); auto criticalSectionSignal = [&] { auto csrLock = CSRLock::lock(opCtx, this); return _critSec.getSignal(opCtx->lockState()->isWriteLocked() ? ShardingMigrationCriticalSection::kWrite : ShardingMigrationCriticalSection::kRead); }(); if (criticalSectionSignal) { // Set migration critical section on operation sharding state: operation will wait for the // migration to finish before returning failure and retrying. auto& oss = OperationShardingState::get(opCtx); oss.setMigrationCriticalSectionSignal(criticalSectionSignal); uasserted(StaleConfigInfo(_nss, receivedShardVersion, wantedShardVersion), str::stream() << "migration commit in progress for " << _nss.ns()); } if (receivedShardVersion.isWriteCompatibleWith(wantedShardVersion)) { return; } // // Figure out exactly why not compatible, send appropriate error message // The versions themselves are returned in the error, so not needed in messages here // StaleConfigInfo sci(_nss, receivedShardVersion, wantedShardVersion); uassert(std::move(sci), str::stream() << "epoch mismatch detected for " << _nss.ns() << ", " << "the collection may have been dropped and recreated", wantedShardVersion.epoch() == receivedShardVersion.epoch()); if (!wantedShardVersion.isSet() && receivedShardVersion.isSet()) { uasserted(std::move(sci), str::stream() << "this shard no longer contains chunks for " << _nss.ns() << ", " << "the collection may have been dropped"); } if (wantedShardVersion.isSet() && !receivedShardVersion.isSet()) { uasserted(std::move(sci), str::stream() << "this shard contains chunks for " << _nss.ns() << ", " << "but the client expects unsharded collection"); } if (wantedShardVersion.majorVersion() != receivedShardVersion.majorVersion()) { // Could be > or < - wanted is > if this is the source of a migration, wanted < if this is // the target of a migration uasserted(std::move(sci), str::stream() << "version mismatch detected for " << _nss.ns()); } // Those are all the reasons the versions can mismatch MONGO_UNREACHABLE; }