summaryrefslogtreecommitdiff
path: root/jstests/noPassthrough/timeseries_expires_with_partial_index.js
blob: c5bd39b2387307b6b5757ca6912ed3dbd28970fe (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
/**
 * Tests that a time-series collection created with the 'expireAfterSeconds' option will remove
 * buckets older than 'expireAfterSeconds' based on the bucket creation time while also regarding
 * the partial filter on the metafield.
 *
 * @tags: [
 *   does_not_support_stepdowns,
 *   does_not_support_transactions,
 *   featureFlagTimeseriesScalabilityImprovements
 * ]
 */
(function() {
"use strict";

load('jstests/libs/fixture_helpers.js');  // For 'FixtureHelpers'
load("jstests/libs/clustered_collections/clustered_collection_util.js");
load("jstests/core/timeseries/libs/timeseries.js");

const conn = MongoRunner.runMongod({setParameter: 'ttlMonitorSleepSecs=1'});
const testDB = conn.getDB(jsTestName());
assert.commandWorked(testDB.dropDatabase());

TimeseriesTest.run((insert) => {
    const coll = testDB.timeseries_expires_with_partial_index;
    const bucketsColl = testDB.getCollection('system.buckets.' + coll.getName());

    const timeFieldName = 'tm';
    const metaFieldName = "mm";
    const indexName = "partialTTLIndex";
    const timeSpec = {[timeFieldName]: 1};
    const expireAfterSecond = NumberLong(1);
    const expireAfterSeconds = NumberLong(10000);

    const startDate = new Date();
    const expiredDate = new Date(startDate - ((expireAfterSeconds / 2) * 1000));
    const collectionTTLExpiredDate = new Date(startDate - ((expireAfterSeconds * 2) * 1000));
    const futureDate = new Date(startDate.getTime() + (10000 * 10));

    assert.lt(expiredDate, startDate);
    assert.gt(futureDate, startDate);

    const expiredDoc = {_id: 0, [timeFieldName]: expiredDate, [metaFieldName]: 8, x: 0};
    const expiredDocLowMeta = {_id: 1, [timeFieldName]: expiredDate, [metaFieldName]: 0, x: 1};
    const collectionTTLExpiredDocLowMeta =
        {_id: 2, [timeFieldName]: collectionTTLExpiredDate, [metaFieldName]: 0, x: 2};
    const futureDoc = {_id: 3, [timeFieldName]: futureDate, [metaFieldName]: 10, x: 3};

    const partialIndexOptions = {
        name: indexName,
        partialFilterExpression: {[metaFieldName]: {$gt: 5}},
        expireAfterSeconds: expireAfterSecond
    };

    const checkInsertion = function(coll, doc, expectDeletion) {
        jsTestLog("Inserting doc into collection.");
        const prevCount = bucketsColl.find().itcount();
        assert.commandWorked(insert(coll, doc), 'failed to insert doc: ' + tojson(doc));

        // Wait for the TTL monitor to process the indexes.
        jsTestLog("Waiting for TTL monitor to process...");
        ClusteredCollectionUtil.waitForTTL(testDB);

        // Check the number of bucket documents.
        const expectedCount = (expectDeletion) ? prevCount : prevCount + 1;
        const bucketDocs = bucketsColl.find().sort({'control.min._id': 1}).toArray();

        assert.eq(expectedCount, bucketDocs.length, bucketDocs);
        jsTestLog("Doc deleted: " + expectDeletion + ".");
    };

    const testTTLIndex = function(coll) {
        // Inserts a measurement with a time in the past to ensure the measurement will be removed
        // immediately.
        checkInsertion(coll, expiredDoc, true);

        // Inserts a measurement that does not meet the partialFilterExpression to ensure it will
        // not be removed (even though it is 'expired').
        checkInsertion(coll, expiredDocLowMeta, false);

        // Inserts a measurement with a time in the future to ensure the measurement is not removed.
        checkInsertion(coll, futureDoc, false);
    };

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

        // Create a TTL index on time, with a partial filter expression on the metaField.
        assert.commandWorked(coll.createIndex(timeSpec, partialIndexOptions));
    }

    // Test the TTL Deleter on a time-series collection with a TTL index and partialFilter.
    testTTLIndex(coll);

    {
        coll.drop();
        assert.commandWorked(testDB.createCollection(coll.getName(), {
            timeseries: {timeField: timeFieldName, metaField: metaFieldName},
            expireAfterSeconds: expireAfterSeconds
        }));
        assert.contains(bucketsColl.getName(), testDB.getCollectionNames());

        // Create a secondary TTL index on time, with a partial filter expression on the metaField.
        assert.commandWorked(coll.createIndex(timeSpec, partialIndexOptions));
    }

    // Test the TTL Deleter on a time-series collection with a TTL index and partialFilter and a
    // pre-existing TTL index.
    testTTLIndex(coll);

    // As a sanity check, check that the TTL deleter deletes a document that does not match partial
    // filter but is expired, with respect to the collection TTL index.
    checkInsertion(coll, collectionTTLExpiredDocLowMeta, true);
});

MongoRunner.stopMongod(conn);
})();