summaryrefslogtreecommitdiff
path: root/jstests/libs/check_shard_filtering_metadata_helpers.js
blob: ca096e3c5fd28c2b813df6bdd0dbdaf127360c64 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
'use strict';

var CheckShardFilteringMetadataHelpers = (function() {
    function run(mongosConn, nodeConn, shardId, skipCheckShardedCollections = false) {
        function checkDatabase(configDatabasesEntry) {
            const dbName = configDatabasesEntry._id;
            print(`CheckShardFilteringMetadata: checking database '${dbName}' on node '${
                nodeConn.host}' of shard '${shardId}'`);

            const nodeMetadata =
                assert.commandWorked(nodeConn.adminCommand({getDatabaseVersion: dbName}));

            if (nodeMetadata.dbVersion.timestamp === undefined) {
                // Shards are allowed to not know the dbVersion.
                return;
            }

            assert.eq(nodeMetadata.dbVersion.uuid,
                      configDatabasesEntry.version.uuid,
                      `Unexpected dbVersion.uuid for db '${dbName}' on node '${nodeConn.host}'`);
            assert.eq(timestampCmp(nodeMetadata.dbVersion.timestamp,
                                   configDatabasesEntry.version.timestamp),
                      0,
                      `Unexpected dbVersion timestamp for db '${dbName}' on node '${
                          nodeConn.host}'. Found '${
                          tojson(nodeMetadata.dbVersion.timestamp)}'; expected '${
                          tojson(configDatabasesEntry.version.timestamp)}'`);
            assert.eq(nodeMetadata.dbVersion.lastMod,
                      configDatabasesEntry.version.lastMod,
                      `Unexpected dbVersion lastMod for db '${dbName}' on node '${nodeConn.host}'`);

            print(`CheckShardFilteringMetadata: Database '${dbName}' on '${nodeConn.host}' OK`);
        }

        function checkShardedCollection(coll, nodeShardingState) {
            const ns = coll._id;
            print(`CheckShardFilteringMetadata: checking collection '${ns} ' on node '${
                nodeConn.host}' of shard '${shardId}'`);

            const configDB = mongosConn.getDB('config');

            const highestChunkOnShard = configDB.chunks.find({uuid: coll.uuid, shard: shardId})
                                            .sort({lastmod: -1})
                                            .limit(1)
                                            .toArray()[0];

            const expectedShardVersion =
                highestChunkOnShard ? highestChunkOnShard.lastmod : Timestamp(0, 0);
            const expectedTimestamp = coll.timestamp;

            const collectionMetadataOnNode = nodeShardingState.versions[ns];
            if (collectionMetadataOnNode === undefined) {
                // Shards are not authoritative. It is okay that they don't know their filtering
                // info.
                return;
            }

            if (collectionMetadataOnNode.timestamp === undefined) {
                // Versions earlier than v6.3 did not report the timestamp on shardingState command
                // (SERVER-70790). This early exit can be removed after v6.0 is no longer tested in
                // multiversion suites.
                return;
            }

            if (timestampCmp(collectionMetadataOnNode.timestamp, Timestamp(0, 0)) === 0) {
                // The metadata reflects an unsharded collection. It is okay for a node to have this
                // stale metadata, as long as the node knows the correct dbVersion.
                return;
            }

            // If the node knows its filtering info, then assert that it is correct.
            assert.eq(timestampCmp(collectionMetadataOnNode.timestamp, expectedTimestamp),
                      0,
                      `Unexpected timestamp for ns '${ns}' on node '${nodeConn.host}'. Found '${
                          tojson(collectionMetadataOnNode.timestamp)}', expected '${
                          tojson(expectedTimestamp)}'`);
            // Only check the major version because some operations (such as resharding or
            // setAllowMigrations) bump the minor version without the shards knowing. This does not
            // affect placement, so it is okay.
            assert.eq(collectionMetadataOnNode.placementVersion.t,
                      expectedShardVersion.t,
                      `Unexpected shardVersion for ns '${ns}' on node '${nodeConn.host}'`);

            print(`CheckShardFilteringMetadata: ns '${ns}' on '${nodeConn.host}' OK`);
        }

        const configDB = mongosConn.getDB('config');

        // Check shards know correct database versions.
        // Note: We can only check the dbVersion on the primary shards because non-primary shards
        // can have stale dbVersions cached (for versions on which they were not primary.). TODO:
        // Once shards became authoritative for their dbVersions, we can check all shards.
        configDB.databases.find({primary: shardId}).forEach(configDatabasesEntry => {
            checkDatabase(configDatabasesEntry);
        });

        // Check that shards have correct filtering metadata for sharded collections.
        if (!skipCheckShardedCollections) {
            const nodeShardingState = nodeConn.adminCommand({shardingState: 1});
            configDB.collections.find().forEach(coll => {
                checkShardedCollection(coll, nodeShardingState);
            });
        }

        print("CheckShardFilteringMetadata: finished");
    }

    return {
        run: run,
    };
})();