summaryrefslogtreecommitdiff
path: root/jstests/libs/check_shard_filtering_metadata_helpers.js
blob: 96da896e81af2a82da3c083ab0ab5e6bce6f44d7 (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
112
113
114
115
116
117
118
119
120
121
'use strict';

var CheckShardFilteringMetadataHelpers = (function() {
    function run(mongosConn, nodeConn, shardId, skipCheckShardedCollections = false) {
        function checkDatabase(configDatabasesEntry) {
            // No shard other than the db-primary shard can believe to be the db-primary. Non
            // db-primary shards are allowed to have a stale notion of the dbVersion, as long as
            // they believe they are not primary.

            const dbName = configDatabasesEntry._id;
            print(`CheckShardFilteringMetadata: checking database '${dbName}' on node '${
                nodeConn.host}' of shard '${shardId}'`);

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

            // Skip this test if isPrimaryShardForDb is not present. Multiversion incompatible.
            if (nodeMetadata.dbVersion.isPrimaryShardForDb === undefined) {
                return;
            }

            if (nodeMetadata.dbVersion.timestamp === undefined) {
                // Node has no knowledge of the database.
                return;
            }

            assert.eq(
                configDatabasesEntry.primary === shardId,
                nodeMetadata.isPrimaryShardForDb,
                `Unexpected isPrimaryShardForDb for db '${dbName}' on node '${nodeConn.host}'`);

            // If the node is the primary shard for the database, it should know the correct
            // database version.
            if (configDatabasesEntry.primary === shardId) {
                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 (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.
        configDB.databases.find().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,
    };
})();