summaryrefslogtreecommitdiff
path: root/jstests/noPassthrough/timeseries_out_concurrent_sharding.js
blob: bd2128c0f8410fb0214e99fa0987b6e81b5c84ca (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
122
/*
 * Ensures that when $out is doing a rename collection operation and a concurrent 'shardCollection'
 * command is invoked, the operations are serialized. This is a targeted test to reproduce the
 * scenario described in SERVER-76626. We block the rename operation behind a DDL lock and validate
 * that a concurrent 'shardCollection' command cannot make progress.
 *
 * @tags: [
 *   # We need a timeseries collection.
 *   requires_timeseries,
 *   requires_fcv_71,
 *   featureFlagAggOutTimeseries
 * ]
 */
(function() {
"use strict";

load("jstests/libs/fail_point_util.js");  // for configureFailPoint.

const st = new ShardingTest({shards: 2});
const dbName = "test";
const testDB = st.s.getDB(dbName);
const targetCollName = "out_time";
const sourceCollName = "in";
const timeFieldName = 'time';
const metaFieldName = 'tag';
const numDocs = 40;

function setUpCollection(collName) {
    // Create a time-series collection to be the source for $out.
    testDB.createCollection(collName,
                            {timeseries: {timeField: timeFieldName, metaField: metaFieldName}});
    const docs = [];
    for (let i = 0; i < numDocs; ++i) {
        docs.push({
            [timeFieldName]: ISODate(),
            [metaFieldName]: (1 * numDocs) + i,
        });
    }
    assert.commandWorked(testDB[collName].insertMany(docs));
}

function runOutQuery() {
    assert.doesNotThrow(() => testDB[sourceCollName].aggregate([
        {$set: {"time": new Date()}},
        {
            $out: {
                db: testDB.getName(),
                coll: targetCollName,
                timeseries: {timeField: timeFieldName, metaField: metaFieldName}
            }
        }
    ]));
}

function checkMetadata() {
    const checkOptions = {'checkIndexes': 1};
    let inconsistencies = testDB.checkMetadataConsistency(checkOptions).toArray();
    assert.eq(0, inconsistencies, inconsistencies);
}

function runParallelShellTest() {
    // Set a failpoint in the internalRenameCollection command after the sharding check.
    const fp = configureFailPoint(st.shard0, 'blockBeforeInternalRenameIfOptionsAndIndexesMatch');

    // Run an $out aggregation pipeline in a parallel shell.
    let parallelFunction =
        `let cmdRes = db.runCommand({
        aggregate: "in",
        pipeline: [
            {
                $out: {
                    db: db.getName(),
                    coll: "out_time",
                    timeseries: {timeField: "time", metaField: "tag"}
                }
            }
        ], cursor: {}})
        assert(cmdRes.ok);`;
    let outShell = startParallelShell(parallelFunction, st.s.port);

    // Wait for the aggregation pipeline to hit the failpoint.
    fp.wait();

    // Validate the temporary collection exists, meaning we are in the middle of the $out stage.
    const collNames = testDB.getCollectionNames();
    assert.eq(collNames.filter(col => col.includes('tmp.agg_out')).length, 1, collNames);

    // Assert sharding the target collection fails, since the rename command has a lock on the
    // view namespace.
    jsTestLog("attempting to shard the target collection.");
    assert.commandFailedWithCode(
        testDB.adminCommand(
            {shardCollection: testDB[targetCollName].getFullName(), key: {[metaFieldName]: 1}}),
        ErrorCodes.LockBusy);

    // Turn off the failpoint and resume the $out aggregation pipeline.
    jsTestLog("turning the failpoint off.");
    fp.off();
    outShell();
    // Assert the metadata is consistent.
    checkMetadata();

    // Assert sharding the target collection succeeds, since there is no lock on the view
    // namespace.
    assert.commandWorked(testDB.adminCommand(
        {shardCollection: testDB[targetCollName].getFullName(), key: {[metaFieldName]: 1}}));

    // Assert the metadata is consistent.
    checkMetadata();
}

assert.commandWorked(st.s.adminCommand({enableSharding: dbName}));
st.ensurePrimaryShard(dbName, st.shard0.shardName);

// The target collection should exist to produce the metadata inconsistency scenario.
setUpCollection(sourceCollName);
setUpCollection(targetCollName);

runParallelShellTest();

st.stop();
}());