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);
})();
|