summaryrefslogtreecommitdiff
path: root/jstests/concurrency/fsm_workloads/update_inc.js
blob: adc1c536fdde27c742bffadf80234b6f9026e3ec (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
'use strict';

/**
 * update_inc.js
 *
 * Inserts a single document into a collection. Each thread performs an
 * update operation to select the document and increment a particular
 * field. Asserts that the field has the correct value based on the number
 * of increments performed.
 */
load('jstests/concurrency/fsm_workload_helpers/server_types.js'); // for isMongod and isMMAPv1

var $config = (function() {

    var data = {
        // uses the workload name as _id on the document.
        // assumes this name will be unique.
        id: 'update_inc'
    };

    var states = {
        init: function init(db, collName) {
            this.fieldName = 't' + this.tid;
            this.count = 0;
        },

        update: function update(db, collName) {
            var updateDoc = { $inc: {} };
            updateDoc.$inc[this.fieldName] = 1;

            var res = db[collName].update({ _id: this.id }, updateDoc);
            assertAlways.eq(0, res.nUpserted, tojson(res));

            if (isMongod(db) && !isMMAPv1(db)) {
                // For non-mmap storage engines we can have a strong assertion that exactly one doc
                // will be modified.
                assertWhenOwnColl.eq(res.nMatched, 1, tojson(res));
                if (db.getMongo().writeMode() === 'commands') {
                    assertWhenOwnColl.eq(res.nModified, 1, tojson(res));
                }
            }
            else {
                // Zero matches are possible for MMAP v1 because the update will skip a document
                // that was invalidated during a yield.
                assertWhenOwnColl.contains(res.nMatched, [0, 1], tojson(res));
                if (db.getMongo().writeMode() === 'commands') {
                    assertWhenOwnColl.contains(res.nModified, [0, 1], tojson(res));
                    assertAlways.eq(res.nModified, res.nMatched, tojson(res));
                }
            }

            // The $inc operator always modifies the matched document, so if we matched something,
            // then we must have updated it.
            this.count += (res.nMatched >= 1);
        },

        find: function find(db, collName) {
            var docs = db[collName].find().toArray();
            assertWhenOwnColl.eq(1, docs.length);
            assertWhenOwnColl(() => {
                // If the document hasn't been updated at all, then the field won't exist.
                var doc = docs[0];
                if (doc.hasOwnProperty(this.fieldName)) {
                    assertWhenOwnColl.eq(this.count, doc[this.fieldName]);
                } else {
                    assertWhenOwnColl.eq(this.count, 0);
                }
            });
        }
    };

    var transitions = {
        init: { update: 1 },
        update: { find: 1 },
        find: { update: 1 }
    };

    function setup(db, collName, cluster) {
        var doc = { _id: this.id };

        // Pre-populate the fields we need to avoid size change for capped collections.
        for (var i = 0; i < this.threadCount; ++i) {
            doc['t' + i] = 0;
        }
        db[collName].insert(doc);
    }

    return {
        threadCount: 5,
        iterations: 10,
        data: data,
        states: states,
        transitions: transitions,
        setup: setup
    };

})();