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
|
'use strict';
/**
* This test runs many concurrent aggregations using $out, writing to the same time-series
* collection. While this is happening, other threads may be creating or dropping indexes, changing
* the collection options, or sharding the collection. We expect an aggregate with a $out stage to
* fail if another client executed one of these changes between the creation of $out's temporary
* collection and the eventual rename to the target collection.
*
* Unfortunately, there aren't very many assertions we can make here, so this is mostly to test that
* the server doesn't deadlock or crash, and that temporary namespaces are cleaned up.
*
* @tags: [
* requires_timeseries,
* does_not_support_transactions,
* does_not_support_stepdowns,
* requires_fcv_71,
* featureFlagAggOutTimeseries
* ]
*/
load('jstests/concurrency/fsm_workloads/agg_out.js'); // for $super state functions
var $config = extendWorkload($config, function($config, $super) {
const timeFieldName = 'time';
const metaFieldName = 'tag';
const numDocs = 100;
$config.data.outputCollName = 'timeseries_agg_out';
$config.data.shardKey = {[metaFieldName]: 1};
/**
* Runs an aggregate with a $out with time-series into '$config.data.outputCollName'.
*/
$config.states.query = function query(db, collName) {
const res = db[collName].runCommand({
aggregate: collName,
pipeline: [
{$set: {"time": new Date()}},
{
$out: {
db: db.getName(),
coll: this.outputCollName,
timeseries: {timeField: timeFieldName, metaField: metaFieldName}
}
}
],
cursor: {}
});
const allowedErrorCodes = [
ErrorCodes.CommandFailed, // indexes of target collection changed during processing.
ErrorCodes.IllegalOperation, // $out is not supported to an existing *sharded* output
// collection.
17152, // namespace is capped so it can't be used for $out.
28769, // $out collection cannot be sharded.
ErrorCodes.NamespaceExists, // $out tries to create a view when a buckets collection
// already exists. This error is not caught because the
// view is being dropped by a previous thread.
];
assertWhenOwnDB.commandWorkedOrFailedWithCode(res, allowedErrorCodes);
if (res.ok) {
const cursor = new DBCommandCursor(db, res);
assertAlways.eq(0, cursor.itcount()); // No matter how many documents were in the
// original input stream, $out should never return any results.
}
};
/**
* Changes the 'expireAfterSeconds' value for the time-series collection.
*/
$config.states.collMod = function collMod(db, unusedCollName) {
let expireAfterSeconds = "off";
if (Random.rand() < 0.5) {
// Change the expireAfterSeconds
expireAfterSeconds = Random.rand();
}
assertWhenOwnDB.commandWorkedOrFailedWithCode(
db.runCommand({collMod: this.outputCollName, expireAfterSeconds: expireAfterSeconds}),
[ErrorCodes.ConflictingOperationInProgress, ErrorCodes.NamespaceNotFound]);
};
/**
* 'convertToCapped' should always fail with a 'CommandNotSupportedOnView' error.
*/
$config.states.convertToCapped = function convertToCapped(db, unusedCollName) {
if (isMongos(db)) {
return; // convertToCapped can't be run against a mongos.
}
assertWhenOwnDB.commandFailedWithCode(
db.runCommand({convertToCapped: this.outputCollName, size: 100000}),
ErrorCodes.CommandNotSupportedOnView);
};
$config.teardown = function teardown(db) {
const collNames = db.getCollectionNames();
// Ensure that a temporary collection is not left behind.
assertAlways.eq(db.getCollectionNames()
.filter(col => col.includes('system.buckets.tmp.agg_out'))
.length,
0);
// Ensure that for the buckets collection there is a corresponding view.
assertAlways(!(collNames.includes('system.buckets.timeseries_agg_out') &&
!collNames.includes('timeseries_agg_out')));
};
/**
* Create a time-series collection and insert 100 documents.
*/
$config.setup = function setup(db, collName, cluster) {
db[collName].drop();
assertWhenOwnDB.commandWorked(db.createCollection(
collName, {timeseries: {timeField: timeFieldName, metaField: metaFieldName}}));
const docs = [];
for (let i = 0; i < numDocs; ++i) {
docs.push({
[timeFieldName]: ISODate(),
[metaFieldName]: (this.tid * numDocs) + i,
});
}
assertWhenOwnDB.commandWorked(
db.runCommand({insert: collName, documents: docs, ordered: false}));
};
return $config;
});
|