SERVER-117623 Revert SERVER-95330 + extend test for sharded txn and DDL interleaving (#47057)
GitOrigin-RevId: d4433faafb9ded7ac911e3c3116d43e4457421f8
This commit is contained in:
parent
5710e50f4f
commit
f55f2b459f
@ -325,13 +325,14 @@ const commands = ['find', 'aggregate', 'update', 'bulkWrite'];
|
||||
}));
|
||||
}
|
||||
|
||||
// Test transaction involving sharded collection with concurrent drop, where the transaction
|
||||
// attempts to read the dropped collection.
|
||||
// Test transaction involving sharded collection with concurrent drop or rename, where the
|
||||
// transaction attempts to read the dropped or renamed-from collection.
|
||||
{
|
||||
function runTest(readConcernLevel, command) {
|
||||
jsTest.log("Test transaction with concurrent drop. Command: " + command +
|
||||
" Read Concern: " + readConcernLevel);
|
||||
const dbName = 'test_txn_and_drop_with_' + command + '_and_' + readConcernLevel;
|
||||
function runTest(readConcernLevel, operation, command) {
|
||||
jsTest.log("Test transaction with concurrent " + operation + ". Command: " + command +
|
||||
", read concern: " + readConcernLevel);
|
||||
const dbName =
|
||||
'test_txn_and_' + operation + '_with_' + command + '_and_' + readConcernLevel;
|
||||
const collName1 = 'coll1';
|
||||
const collName2 = 'coll2';
|
||||
const ns1 = dbName + '.' + collName1;
|
||||
@ -339,8 +340,8 @@ const commands = ['find', 'aggregate', 'update', 'bulkWrite'];
|
||||
let coll1 = st.s.getDB(dbName)[collName1];
|
||||
let coll2 = st.s.getDB(dbName)[collName2];
|
||||
|
||||
jsTest.log("Running transaction + drop test with read concern " + readConcernLevel +
|
||||
" and command " + command);
|
||||
jsTest.log("Running transaction + " + operation + " test with read concern " +
|
||||
readConcernLevel + " and command " + command);
|
||||
assert(command === 'find' || command === 'aggregate' || command === 'update' ||
|
||||
command === 'bulkWrite');
|
||||
// Initial state:
|
||||
@ -348,7 +349,7 @@ const commands = ['find', 'aggregate', 'update', 'bulkWrite'];
|
||||
// shard1: collA(sharded)
|
||||
//
|
||||
// 1. Start txn, hit shard0 for collB
|
||||
// 2. Drop collA
|
||||
// 2. Drop or rename collA
|
||||
// 3. Read collA. Will target only shard0 because the router believes it is no longer
|
||||
// sharded, so it would read the sharded coll (but just half of it). Therefore, a
|
||||
// conflict must be raised.
|
||||
@ -374,8 +375,14 @@ const commands = ['find', 'aggregate', 'update', 'bulkWrite'];
|
||||
session.startTransaction({readConcern: {level: readConcernLevel}});
|
||||
assert.eq(1, sessionColl2.find().itcount()); // Targets shard0.
|
||||
|
||||
// While the transaction is still open, drop coll1.
|
||||
assert(coll1.drop());
|
||||
// While the transaction is still open, drop or rename coll1.
|
||||
if (operation === "drop") {
|
||||
assert(coll1.drop());
|
||||
} else if (operation === "rename") {
|
||||
assert.commandWorked(coll1.renameCollection("coll3"));
|
||||
} else {
|
||||
throw new Error("Unsupported operation: " + operation);
|
||||
}
|
||||
|
||||
// Refresh the router so that it doesn't send a stale SV to the shard, which would cause
|
||||
// the txn to be aborted.
|
||||
@ -407,9 +414,13 @@ const commands = ['find', 'aggregate', 'update', 'bulkWrite'];
|
||||
}
|
||||
}
|
||||
|
||||
readConcerns.forEach((readConcern) => commands.forEach((command) => {
|
||||
runTest(readConcern, command);
|
||||
}));
|
||||
["drop", "rename"].forEach(
|
||||
(operation) => readConcerns.forEach(
|
||||
(readConcern) => commands.forEach((command) => {
|
||||
runTest(readConcern, operation, command);
|
||||
}),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// Test transaction concurrent with reshardCollection.
|
||||
|
||||
@ -1836,30 +1836,6 @@ boost::optional<UUID> CollectionCatalog::lookupUUIDByNSS(OperationContext* opCtx
|
||||
return boost::none;
|
||||
}
|
||||
|
||||
bool CollectionCatalog::checkIfUUIDExistsAtLatest(OperationContext* opCtx, UUID uuid) const {
|
||||
// First look within uncommitted collection creations performed under the currently open storage
|
||||
// transaction (if any)...
|
||||
auto& uncommittedCatalogUpdates = UncommittedCatalogUpdates::get(opCtx);
|
||||
const auto& entries = uncommittedCatalogUpdates.entries();
|
||||
auto entriesIt = std::find_if(
|
||||
entries.begin(), entries.end(), [&uuid](const UncommittedCatalogUpdates::Entry& entry) {
|
||||
return (entry.collection && entry.collection->uuid() == uuid);
|
||||
});
|
||||
if (entriesIt != entries.end()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Then within the catalog instance itself...
|
||||
auto* coll = _catalog.find(uuid);
|
||||
if (coll) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// ... and finally within not-yet flushed past commits.
|
||||
coll = _pendingCommitUUIDs.find(uuid);
|
||||
return coll != nullptr;
|
||||
}
|
||||
|
||||
bool CollectionCatalog::isLatestCollection(OperationContext* opCtx,
|
||||
const Collection* collection) const {
|
||||
// Any writable Collection instance created under MODE_X lock is considered to belong to this
|
||||
|
||||
@ -407,20 +407,10 @@ public:
|
||||
* NOTE: the check is based on pointer equality between the 'collection' parameter and
|
||||
* the object stored by the catalog under the same UUID; this may lead to unexpected false
|
||||
* results when a different, but structurally equivalent parameter is passed in (like a
|
||||
* 'collection' obtained via read-through). Consider using checkIfUUIDExistsAtLatest when such a
|
||||
* behavior is not desirable.
|
||||
* 'collection' obtained via read-through).
|
||||
*/
|
||||
bool isLatestCollection(OperationContext* opCtx, const Collection* collection) const;
|
||||
|
||||
/**
|
||||
* Checks if the provided UUID is compatible with the latest version for this catalog version
|
||||
* (plus uncommitted catalog updates).
|
||||
* The function only returns a meaningful result when called against CollectionCatalog::latest()
|
||||
* and it is exclusively meant to support the ShardRole API in the resource acquisition for
|
||||
* unsharded collection.
|
||||
*/
|
||||
bool checkIfUUIDExistsAtLatest(OperationContext* opCtx, UUID uuid) const;
|
||||
|
||||
/**
|
||||
* Verifies that the provided collection name doesn't exist in the catalog and is exclusively
|
||||
* present in the uncommitted updates of the operation. For the check to be meaningful it should
|
||||
|
||||
@ -1979,109 +1979,6 @@ TEST_F(CollectionCatalogTimestampTest, OpenNewCollectionUsingDropPendingCollecti
|
||||
ASSERT_EQ(coll->getSharedIdent(), openedColl->getSharedIdent());
|
||||
}
|
||||
|
||||
TEST_F(CollectionCatalogTimestampTest, checkIfUUIDExistsAtLatest) {
|
||||
// A "committed on disk" collection UUID can be retrieved from the latest catalog snapshot.
|
||||
{
|
||||
const NamespaceString nssOnCatalog =
|
||||
NamespaceString::createNamespaceString_forTest("a.committed");
|
||||
const Timestamp createCollectionTs = Timestamp(10, 10);
|
||||
const auto collUuidOnCatalog =
|
||||
createCollection(opCtx.get(), nssOnCatalog, createCollectionTs);
|
||||
|
||||
auto catalog = CollectionCatalog::get(opCtx.get());
|
||||
auto match = catalog->checkIfUUIDExistsAtLatest(opCtx.get(), collUuidOnCatalog);
|
||||
ASSERT_TRUE(match);
|
||||
}
|
||||
|
||||
// The UUID of an uncommitted createCollection can be retrieved from the open storage
|
||||
// transaction.
|
||||
{
|
||||
const NamespaceString nssOnCatalog =
|
||||
NamespaceString::createNamespaceString_forTest("a.uncommitted");
|
||||
const Timestamp createCollectionTs = Timestamp(10, 10);
|
||||
const UUID uncommittedCollUUID = UUID::gen();
|
||||
boost::optional<WriteUnitOfWork> wuow;
|
||||
createCollectionWithUUIDAndLeaveUncommitted(
|
||||
opCtx.get(), nssOnCatalog, createCollectionTs, uncommittedCollUUID, wuow);
|
||||
|
||||
auto catalog = CollectionCatalog::get(opCtx.get());
|
||||
auto match = catalog->checkIfUUIDExistsAtLatest(opCtx.get(), uncommittedCollUUID);
|
||||
ASSERT_TRUE(match);
|
||||
wuow->commit();
|
||||
}
|
||||
|
||||
// The UUID of a commit-pending createCollection can be retrieved from the related data
|
||||
// structure.
|
||||
{
|
||||
const NamespaceString commitPendingNss =
|
||||
NamespaceString::createNamespaceString_forTest("a.createWithCommitPending");
|
||||
const UUID commitPendingColluuid = UUID::gen();
|
||||
const Timestamp createCollectionTs = Timestamp(10, 10);
|
||||
|
||||
concurrentCreateAndRunCatalogOperations(
|
||||
opCtx.get(),
|
||||
commitPendingNss,
|
||||
commitPendingColluuid,
|
||||
createCollectionTs,
|
||||
[this, &commitPendingColluuid](OperationContext* opCtx) {
|
||||
auto catalog = CollectionCatalog::get(opCtx);
|
||||
auto match = catalog->checkIfUUIDExistsAtLatest(opCtx, commitPendingColluuid);
|
||||
ASSERT_TRUE(match);
|
||||
});
|
||||
}
|
||||
|
||||
// The UUID of a commit-pending dropped collection can still be retrieved from the latest
|
||||
// catalog snapshot.
|
||||
{
|
||||
const NamespaceString nssOnCatalog =
|
||||
NamespaceString::createNamespaceString_forTest("a.dropWithCommitPending");
|
||||
const Timestamp createCollectionTs = Timestamp(10, 10);
|
||||
const Timestamp dropCollectionTs = Timestamp(20, 20);
|
||||
|
||||
const auto collUuidOnCatalog =
|
||||
createCollection(opCtx.get(), nssOnCatalog, createCollectionTs);
|
||||
|
||||
concurrentDropAndRunCatalogOperations(opCtx.get(),
|
||||
nssOnCatalog,
|
||||
dropCollectionTs,
|
||||
[this, &collUuidOnCatalog](OperationContext* opCtx) {
|
||||
auto catalog = CollectionCatalog::get(opCtx);
|
||||
auto match = catalog->checkIfUUIDExistsAtLatest(
|
||||
opCtx, collUuidOnCatalog);
|
||||
ASSERT_TRUE(match);
|
||||
});
|
||||
}
|
||||
|
||||
// A collection being dropped within the currently open storage transaction can still be
|
||||
// retrieved through the latest catalog snapshot.
|
||||
{
|
||||
const NamespaceString nssOnCatalog =
|
||||
NamespaceString::createNamespaceString_forTest("a.toBeDroppedInOpenTxn");
|
||||
const Timestamp createCollectionTs = Timestamp(10, 10);
|
||||
const Timestamp dropCollectionTs = Timestamp(20, 20);
|
||||
|
||||
const auto collUuidOnCatalog =
|
||||
createCollection(opCtx.get(), nssOnCatalog, createCollectionTs);
|
||||
|
||||
boost::optional<WriteUnitOfWork> wuow;
|
||||
|
||||
dropCollectionAndLeaveUncommitted(opCtx.get(), nssOnCatalog, dropCollectionTs, wuow);
|
||||
|
||||
auto catalog = CollectionCatalog::get(opCtx.get());
|
||||
auto match = catalog->checkIfUUIDExistsAtLatest(opCtx.get(), collUuidOnCatalog);
|
||||
ASSERT_TRUE(match);
|
||||
wuow->commit();
|
||||
}
|
||||
|
||||
// A non-existing collection UUID matches no collection.
|
||||
{
|
||||
const UUID nonExistingUuid = UUID::gen();
|
||||
auto catalog = CollectionCatalog::get(opCtx.get());
|
||||
auto match = catalog->checkIfUUIDExistsAtLatest(opCtx.get(), nonExistingUuid);
|
||||
ASSERT_FALSE(match);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(CollectionCatalogTimestampTest, CollectionLifetimeTiedToStorageTransactionLifetime) {
|
||||
const NamespaceString nss = NamespaceString::createNamespaceString_forTest("a.b");
|
||||
const Timestamp createCollectionTs = Timestamp(10, 10);
|
||||
|
||||
@ -2069,7 +2069,7 @@ void shard_role_details::checkLocalCatalogIsValidForUnshardedShardVersion(
|
||||
// The transaction sees a collection exists.
|
||||
uassert(ErrorCodes::SnapshotUnavailable,
|
||||
makeErrorMessage(),
|
||||
latestCatalog->checkIfUUIDExistsAtLatest(opCtx, collectionPtr->uuid()));
|
||||
latestCatalog->isLatestCollection(opCtx, collectionPtr.get()));
|
||||
} else if (const auto currentView = stashedCatalog.lookupView(opCtx, nss)) {
|
||||
// The transaction sees a view exists.
|
||||
uassert(ErrorCodes::SnapshotUnavailable,
|
||||
|
||||
@ -966,31 +966,6 @@ TEST_F(ShardRoleTest, ConflictIsThrownWhenShardVersionUnshardedButStashedCatalog
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(ShardRoleTest, NoExceptionIsThrownWhenShardVersionUnshardedButStashedIsEquivalentToLatest) {
|
||||
operationContext()->setInMultiDocumentTransaction();
|
||||
shard_role_details::getRecoveryUnit(operationContext())->preallocateSnapshot();
|
||||
CollectionCatalog::stash(operationContext(), CollectionCatalog::get(operationContext()));
|
||||
|
||||
// Re-open the local catalog at its latest version, simulating a rollback event that has no
|
||||
// effects on the metadata of the unsharded collection (although it does force the creation of a
|
||||
// new instance for the "most recent collection snapshot" held by the catalog).
|
||||
simulateReplicationRollbackEvent(operationContext());
|
||||
|
||||
// The acquisition of the unsharded collection is expected to succeed, even though the stashed
|
||||
// snapshot points to a different object than the one kept by the catalog.
|
||||
{
|
||||
ScopedSetShardRole setShardRole(
|
||||
operationContext(), nssUnshardedCollection1, ShardVersion::UNSHARDED(), boost::none);
|
||||
auto acquisition = acquireCollectionOrView(
|
||||
operationContext(),
|
||||
CollectionOrViewAcquisitionRequest::fromOpCtx(
|
||||
operationContext(), nssUnshardedCollection1, AcquisitionPrerequisites::kRead),
|
||||
MODE_IX);
|
||||
|
||||
ASSERT_TRUE(acquisition.collectionExists());
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// MaybeLockFree
|
||||
TEST_F(ShardRoleTest, AcquireCollectionMaybeLockFreeTakesLocksWhenInMultiDocTransaction) {
|
||||
|
||||
1
src/third_party/private/.placeholder
vendored
1
src/third_party/private/.placeholder
vendored
@ -1 +0,0 @@
|
||||
# Delete once this directory is populated
|
||||
Loading…
Reference in New Issue
Block a user