summaryrefslogtreecommitdiff
path: root/jstests/sharding/analyze_shard_key/persist_sampled_retryable_delete_queries.js
blob: e09b2be204fc7cc0a240cf6c087454fdb5ebd996 (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
127
128
129
130
131
132
133
134
135
136
137
138
139
/**
 * Tests that retrying a retryable delete doesn't cause it to have multiple sampled query documents.
 *
 * @tags: [requires_fcv_70]
 */
(function() {
"use strict";

load("jstests/libs/fail_point_util.js");
load("jstests/sharding/analyze_shard_key/libs/query_sampling_util.js");

// Make the periodic job for writing sampled queries have a period of 1 second to speed up the test.
const queryAnalysisWriterIntervalSecs = 1;

function testRetryExecutedWrite(rst) {
    const dbName = "testDb";
    const collName = "testCollExecutedWrite";
    const ns = dbName + "." + collName;

    const lsid = {id: UUID()};
    const txnNumber = NumberLong(1);

    const primary = rst.getPrimary();
    const db = primary.getDB(dbName);
    const coll = db.getCollection(collName);
    assert.commandWorked(coll.insert([{a: -1}, {a: 0}]));
    const collectionUuid = QuerySamplingUtil.getCollectionUuid(db, collName);

    const deleteOp0 = {q: {a: 0}, limit: 1, sampleId: UUID()};
    const deleteOp1 = {q: {a: {$lt: 1}}, limit: 1, sampleId: UUID()};

    const originalCmdObj = {delete: collName, deletes: [deleteOp0], lsid, txnNumber};
    const expectedSampledQueryDocs = [{
        sampleId: deleteOp0.sampleId,
        cmdName: "delete",
        cmdObj: QuerySamplingUtil.makeCmdObjIgnoreSessionInfo(originalCmdObj)
    }];

    const originalRes = assert.commandWorked(db.runCommand(originalCmdObj));
    assert.eq(originalRes.n, 1, originalRes);

    QuerySamplingUtil.assertSoonSampledQueryDocuments(
        primary, ns, collectionUuid, expectedSampledQueryDocs);

    // Retry deleteOp0 with the same sampleId but batched with the new deleteOp1.
    const retryCmdObj0 = Object.assign({}, originalCmdObj);
    retryCmdObj0.deletes = [deleteOp0, deleteOp1];
    expectedSampledQueryDocs.push({
        sampleId: deleteOp1.sampleId,
        cmdName: "delete",
        cmdObj: Object.assign(QuerySamplingUtil.makeCmdObjIgnoreSessionInfo(retryCmdObj0),
                              {deletes: [deleteOp1]})
    });

    const retryRes0 = assert.commandWorked(db.runCommand(retryCmdObj0));
    assert.eq(retryRes0.n, 2, retryRes0);

    QuerySamplingUtil.assertSoonSampledQueryDocuments(
        primary, ns, collectionUuid, expectedSampledQueryDocs);

    // Retry both deleteOp0 and deleteOp1 different sampleIds.
    const retryCmdObj1 = Object.assign({}, retryCmdObj0);
    retryCmdObj1.deletes = [
        Object.assign({}, deleteOp0, {sampleId: UUID()}),
        Object.assign({}, deleteOp1, {sampleId: UUID()})
    ];

    const retryRes1 = assert.commandWorked(db.runCommand(retryCmdObj1));
    assert.eq(retryRes1.n, 2, retryRes1);

    // Wait for one interval to verify that no writes occurred as a result of the retry.
    sleep(queryAnalysisWriterIntervalSecs * 1000);

    QuerySamplingUtil.assertSoonSampledQueryDocuments(
        primary, ns, collectionUuid, expectedSampledQueryDocs);
}

function testRetryUnExecutedWrite(rst) {
    const dbName = "testDb";
    const collName = "testCollUnExecutedWrite";
    const ns = dbName + "." + collName;

    const lsid = {id: UUID()};
    const txnNumber = NumberLong(1);

    const primary = rst.getPrimary();
    const db = primary.getDB(dbName);
    const coll = db.getCollection(collName);
    assert.commandWorked(coll.insert({a: 0}));
    const collectionUuid = QuerySamplingUtil.getCollectionUuid(db, collName);

    const deleteOp0 = {q: {a: 0}, limit: 1, sampleId: UUID()};
    const originalCmdObj = {delete: collName, deletes: [deleteOp0], lsid, txnNumber};
    const expectedSampledQueryDocs = [{
        sampleId: deleteOp0.sampleId,
        cmdName: "delete",
        cmdObj: QuerySamplingUtil.makeCmdObjIgnoreSessionInfo(originalCmdObj)
    }];

    const fp = configureFailPoint(primary, "failAllRemoves");

    // The delete fails after it has been added to the sample buffer.
    assert.commandFailedWithCode(db.runCommand(originalCmdObj), ErrorCodes.InternalError);

    QuerySamplingUtil.assertSoonSampledQueryDocuments(
        primary, ns, collectionUuid, expectedSampledQueryDocs);

    fp.off();

    // Retry with the same sampleId.
    const retryCmdObj = originalCmdObj;
    const retryRes = assert.commandWorked(db.runCommand(retryCmdObj));
    assert.eq(retryRes.n, 1, retryRes);

    // Wait for one interval to verify that no writes occurred as a result of the retry.
    sleep(queryAnalysisWriterIntervalSecs * 1000);

    QuerySamplingUtil.assertSoonSampledQueryDocuments(
        primary, ns, collectionUuid, expectedSampledQueryDocs);
}

const st = new ShardingTest({
    shards: 1,
    rs: {
        nodes: 2,
        // Make the periodic job for writing sampled queries have a period of 1 second to speed up
        // the test.
        setParameter: {queryAnalysisWriterIntervalSecs}
    }
});

// Force samples to get persisted even though query sampling is not enabled.
QuerySamplingUtil.skipActiveSamplingCheckWhenPersistingSamples(st);

testRetryExecutedWrite(st.rs0);
testRetryUnExecutedWrite(st.rs0);

st.stop();
})();