summaryrefslogtreecommitdiff
path: root/jstests/libs/override_methods/check_indexes_consistent_across_cluster.js
blob: d30673b0c5a7d48bad9758f0f53393dd810d3f18 (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
/**
 * Provides a hook to check that indexes are consistent across the sharded cluster.
 *
 * The hook checks that for every collection, all the shards that own chunks for the
 * collection have the same indexes.
 */
"use strict";

load("jstests/sharding/libs/sharded_index_util.js");  // for findInconsistentIndexesAcrossShards

ShardingTest.prototype.checkIndexesConsistentAcrossCluster = function() {
    if (jsTest.options().skipCheckingIndexesConsistentAcrossCluster) {
        print("Skipping index consistency check across the cluster");
        return;
    }

    print("Checking consistency of indexes across the cluster");

    const mongos = new Mongo(this.s.host);
    mongos.fullOptions = this.s.fullOptions || {};
    mongos.forceReadMode("commands");
    mongos.setReadPref("primary");

    const keyFile = this.keyFile;

    /**
     * Returns an array of config.collections docs for undropped collections.
     */
    function getCollDocs() {
        return mongos.getDB("config")
            .collections.find({dropped: false})
            .readConcern("local")
            .toArray();
    }

    /**
     * Returns a function that returns an array of index docs for the namespace grouped
     * by shard.
     */
    function makeGetIndexDocsFunc(ns) {
        return () => {
            while (true) {
                try {
                    return ShardedIndexUtil.getPerShardIndexes(mongos.getCollection(ns));
                } catch (e) {
                    // Getting the indexes can fail with ShardNotFound if the router's ShardRegistry
                    // reloads after choosing which shards to target and a chosen shard is no longer
                    // in the cluster. This error should be transient, so it can be retried on.
                    if (e.code === ErrorCodes.ShardNotFound) {
                        print("Retrying $indexStats aggregation on ShardNotFound error: " +
                              tojson(e));
                        continue;
                    }
                    throw e;
                }
            }
        };
    }

    const requiresAuth = keyFile || (mongos.fullOptions.clusterAuthMode === 'x509');
    const collDocs =
        requiresAuth ? authutil.asCluster(mongos, keyFile, getCollDocs) : getCollDocs();
    for (const collDoc of collDocs) {
        const ns = collDoc._id;
        const getIndexDocsForNs = makeGetIndexDocsFunc(ns);
        print(`Checking that the indexes for ${ns} are consistent across shards...`);

        const indexDocs = requiresAuth ? authutil.asCluster(mongos, keyFile, getIndexDocsForNs)
                                       : getIndexDocsForNs();

        if (indexDocs.length == 0) {
            print(`Found no indexes for ${ns}, skipping index consistency check`);
            continue;
        }

        const inconsistentIndexes = ShardedIndexUtil.findInconsistentIndexesAcrossShards(indexDocs);

        for (const shard in inconsistentIndexes) {
            const shardInconsistentIndexes = inconsistentIndexes[shard];
            assert(shardInconsistentIndexes.length === 0,
                   `found inconsistent indexes for ${ns}: ${tojson(inconsistentIndexes)}`);
        }
    }
};