summaryrefslogtreecommitdiff
path: root/jstests/core/timeseries/timeseries_update_concurrent.js
blob: 3c9c1b5efb5c6db2e8c86d9c3591871303595e70 (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
123
124
125
126
/**
 * Tests running the update command on a time-series collection with concurrent modifications to the
 * collection.
 * @tags: [
 *   assumes_unsharded_collection, # TODO SERVER-60233: Remove this tag.
 *   does_not_support_stepdowns,
 *   does_not_support_transactions,
 *   # $currentOp can't run with a readConcern other than 'local'.
 *   assumes_read_concern_unchanged,
 *   # This test only synchronizes updates on the primary.
 *   assumes_read_preference_unchanged,
 *   # Fail points in this test do not exist on mongos.
 *   assumes_against_mongod_not_mongos,
 *   uses_parallel_shell,
 * ]
 */

(function() {
"use strict";

load("jstests/core/timeseries/libs/timeseries.js");
load("jstests/libs/curop_helpers.js");
load("jstests/libs/parallel_shell_helpers.js");

if (!TimeseriesTest.timeseriesUpdatesAndDeletesEnabled(db.getMongo())) {
    jsTestLog("Skipping test because the time-series updates and deletes feature flag is disabled");
    return;
}

const timeFieldName = "time";
const metaFieldName = "tag";
const collName = 't';
const dbName = jsTestName();

const testCases = {
    DROP_COLLECTION: 0,
    REPLACE_COLLECTION: 1,
    REPLACE_METAFIELD: 2
};

const validateUpdateIndex = (initialDocList,
                             updateList,
                             testType,
                             failCode,
                             newMetaField = null) => {
    const testDB = db.getSiblingDB(dbName);
    const awaitTestUpdate = startParallelShell(funWithArgs(
        function(
            dbName, collName, timeFieldName, metaFieldName, initialDocList, updateList, failCode) {
            const testDB = db.getSiblingDB(dbName);
            const coll = testDB.getCollection(collName);

            assert.commandWorked(testDB.createCollection(
                coll.getName(),
                {timeseries: {timeField: timeFieldName, metaField: metaFieldName}}));

            assert.commandWorked(coll.insert(initialDocList));

            assert.commandWorked(testDB.adminCommand(
                {configureFailPoint: "hangDuringBatchUpdate", mode: "alwaysOn"}));

            assert.commandFailedWithCode(
                testDB.runCommand({update: coll.getName(), updates: updateList}), failCode);

            coll.drop();
        },
        dbName,
        collName,
        timeFieldName,
        metaFieldName,
        initialDocList,
        updateList,
        failCode));

    const coll = testDB.getCollection(collName);
    const childOp = waitForCurOpByFailPoint(testDB, coll.getFullName(), "hangDuringBatchUpdate")[0];

    // Drop the collection in all test cases.
    assert(coll.drop());
    switch (testType) {
        case testCases.REPLACE_COLLECTION:
            assert.commandWorked(testDB.createCollection(coll.getName()));
            break;
        case testCases.REPLACE_METAFIELD:
            assert.commandWorked(testDB.createCollection(
                coll.getName(), {timeseries: {timeField: timeFieldName, metaField: newMetaField}}));
            break;
    }

    assert.commandWorked(
        testDB.adminCommand({configureFailPoint: "hangDuringBatchUpdate", mode: "off"}));

    // Wait for testUpdate to finish.
    awaitTestUpdate();
};

const docs = [
    {_id: 0, [timeFieldName]: ISODate(), [metaFieldName]: {a: "A"}, "measurement": {"m": 1}},
    {_id: 1, [timeFieldName]: ISODate(), [metaFieldName]: {a: "A"}, "measurement": {"n": 3}},
    {_id: 2, [timeFieldName]: ISODate(), [metaFieldName]: {a: "B"}},
];

// Attempt to update a document in a collection that has been dropped.
validateUpdateIndex(
    docs,
    [{q: {[metaFieldName]: {a: "B"}}, u: {$set: {[metaFieldName]: {c: "C"}}}, multi: true}],
    testCases.DROP_COLLECTION,
    ErrorCodes.NamespaceNotFound);

// Attempt to update a document in a collection that has been replaced with a non-time-series
// collection.
validateUpdateIndex(
    docs,
    [{q: {[metaFieldName]: {a: "B"}}, u: {$set: {[metaFieldName]: {c: "C"}}}, multi: true}],
    testCases.REPLACE_COLLECTION,
    ErrorCodes.NamespaceNotFound);

// Attempt to update a document in a collection that has been replaced with a new time-series
// collection with a different metaField.
validateUpdateIndex(
    docs,
    [{q: {[metaFieldName]: {a: "B"}}, u: {$set: {[metaFieldName]: {c: "C"}}}, multi: true}],
    testCases.REPLACE_METAFIELD,
    ErrorCodes.InvalidOptions,
    "meta");
})();