/** * Tests that * 1) the 'config.databases' schema gets upgraded/downgraded on setFCV * 2) shards' in-memory cached database versions get cleared on FCV downgrade (on both the primary and secondary nodes) * 3) shards only cache the database version in-memory in FCV 4.0. */ (function() { "use strict"; load("jstests/libs/feature_compatibility_version.js"); load("jstests/libs/database_versioning.js"); const st = new ShardingTest( {shards: {rs0: {nodes: [{rsConfig: {votes: 1}}, {rsConfig: {priority: 0, votes: 0}}]}}}); assert.commandWorked(st.s.adminCommand({setFeatureCompatibilityVersion: lastStableFCV})); const db1Name = "db1"; const db2Name = "db2"; const collName = "foo"; const ns = db1Name + "." + collName; // Create both databases in the sharding catalog. assert.commandWorked(st.s.adminCommand({enableSharding: db1Name})); assert.commandWorked(st.s.adminCommand({enableSharding: db2Name})); // Ensure neither database entry has a database version. const db1EntryOriginal = st.s.getDB("config").getCollection("databases").findOne({_id: db1Name}); const db2EntryOriginal = st.s.getDB("config").getCollection("databases").findOne({_id: db2Name}); assert.eq(null, db1EntryOriginal.version); assert.eq(null, db2EntryOriginal.version); // Ensure the shard does not have a cached entries in-memory or on-disk. checkInMemoryDatabaseVersion(st.rs0.getPrimary(), db1Name, {}); checkInMemoryDatabaseVersion(st.rs0.getSecondary(), db1Name, {}); checkInMemoryDatabaseVersion(st.rs0.getPrimary(), db2Name, {}); checkInMemoryDatabaseVersion(st.rs0.getSecondary(), db2Name, {}); checkOnDiskDatabaseVersion(st.shard0, db1Name, undefined); checkOnDiskDatabaseVersion(st.shard0, db2Name, undefined); // Create a collection in 'db1' to ensure 'db1' gets created on the primary shard. // TODO (SERVER-34431): Remove this once the DatabaseShardingState is in a standalone map. assert.commandWorked(st.s.getDB(db1Name).runCommand({create: collName})); // Force the shard database to refresh and ensure it writes a cache entry but does not cache the // version in memory. assert.commandWorked(st.rs0.getPrimary().adminCommand({_flushDatabaseCacheUpdates: db1Name})); checkInMemoryDatabaseVersion(st.rs0.getPrimary(), db1Name, {}); checkInMemoryDatabaseVersion(st.rs0.getSecondary(), db1Name, {}); checkInMemoryDatabaseVersion(st.rs0.getPrimary(), db2Name, {}); checkInMemoryDatabaseVersion(st.rs0.getSecondary(), db2Name, {}); checkOnDiskDatabaseVersion(st.shard0, db1Name, db1EntryOriginal); checkOnDiskDatabaseVersion(st.shard0, db2Name, undefined); // // setFCV 4.0 (upgrade) // assert.commandWorked(st.s.adminCommand({setFeatureCompatibilityVersion: latestFCV})); // Database versions should have been generated for the authoritative database entries. const db1EntryFCV40 = st.s.getDB("config").getCollection("databases").findOne({_id: db1Name}); const db2EntryFCV40 = st.s.getDB("config").getCollection("databases").findOne({_id: db2Name}); assert.neq(null, db1EntryFCV40.version); assert.neq(null, db2EntryFCV40.version); // Before the shard receives a versioned request, its in-memory and on-disk caches should not // have been refreshed. checkInMemoryDatabaseVersion(st.rs0.getPrimary(), db1Name, {}); checkInMemoryDatabaseVersion(st.rs0.getSecondary(), db1Name, {}); checkInMemoryDatabaseVersion(st.rs0.getPrimary(), db2Name, {}); checkInMemoryDatabaseVersion(st.rs0.getSecondary(), db2Name, {}); checkOnDiskDatabaseVersion(st.shard0, db1Name, db1EntryOriginal); checkOnDiskDatabaseVersion(st.shard0, db2Name, undefined); // After receiving a versioned request for a database, the shard should refresh its in-memory // and on-disk caches for that database. // This is needed because mongos will not automatically refresh its database entry after the // cluster's FCV changes to pick up the database version (see SERVER-34460). assert.commandWorked(st.s.adminCommand({flushRouterConfig: 1})); assert.commandWorked(st.s.getDB(db1Name).runCommand( {listCollections: 1, $readPreference: {mode: "secondary"}, readConcern: {level: "local"}})); checkInMemoryDatabaseVersion(st.rs0.getPrimary(), db1Name, db1EntryFCV40.version); checkInMemoryDatabaseVersion(st.rs0.getSecondary(), db1Name, db1EntryFCV40.version); checkInMemoryDatabaseVersion(st.rs0.getPrimary(), db2Name, {}); checkInMemoryDatabaseVersion(st.rs0.getSecondary(), db2Name, {}); checkOnDiskDatabaseVersion(st.shard0, db1Name, db1EntryFCV40); checkOnDiskDatabaseVersion(st.shard0, db2Name, undefined); // // setFCV 3.6 (downgrade) // assert.commandWorked(st.s.adminCommand({setFeatureCompatibilityVersion: lastStableFCV})); // Database versions should have been removed from the authoritative database entries. const db1EntryFCV36 = st.s.getDB("config").getCollection("databases").findOne({_id: db1Name}); const db2EntryFCV36 = st.s.getDB("config").getCollection("databases").findOne({_id: db2Name}); assert.docEq(db1EntryOriginal, db1EntryFCV36); assert.docEq(db2EntryOriginal, db2EntryFCV36); // The shard's in-memory database cache should have been cleared, but its on-disk cache left // untouched. checkInMemoryDatabaseVersion(st.rs0.getPrimary(), db1Name, {}); checkInMemoryDatabaseVersion(st.rs0.getSecondary(), db1Name, {}); checkInMemoryDatabaseVersion(st.rs0.getPrimary(), db2Name, {}); checkInMemoryDatabaseVersion(st.rs0.getSecondary(), db2Name, {}); checkOnDiskDatabaseVersion(st.shard0, db1Name, db1EntryFCV40); checkOnDiskDatabaseVersion(st.shard0, db2Name, undefined); st.stop(); })();