summaryrefslogtreecommitdiff
path: root/jstests/watchdog/lib/charybdefs_lib.js
blob: bd0d7440e0d61631f01fc1301b79e6c687238dc4 (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
// Exit code that the watchdog uses on exit
const EXIT_WATCHDOG = 61;

/**
 * Control the Charybdefs file system for Fault Injectiong testing
 *
 * @param {string} test_name unique name for test directories
 */
function CharybdefsControl(test_name) {
    'use strict';

    const python = "/opt/mongodbtoolchain/v3/bin/python3";
    let control_py = "/data/charybdefs/mongo/control.py";

    // Use the minimum watchdog period
    const wd_period_sec = 60;

    // Since the watchdog can take up to (2 x period) to detect failures, stall the write for that
    // amount of time plus a small buffer of time to account for thread scheduling, etc.
    const fs_delay_sec = wd_period_sec * 2 + 5;

    const mount_point = MongoRunner.toRealPath(test_name + '_mnt');
    const backing_path = MongoRunner.toRealPath(test_name + '_backing');

    this._runControl = function(cmd, ...args) {
        let cmd_args = [python, control_py, cmd];
        cmd_args = cmd_args.concat(args);
        let ret = run.apply(null, cmd_args);
        assert.eq(ret, 0);
    };

    /**
     * Get the path of the mounted Charybdefs file system.
     *
     * @return {string} mount point
     */
    this.getMountPath = function() {
        return mount_point;
    };

    /**
     * Get the Watchdog Period.
     *
     * @return {number} number of sections
     */
    this.getWatchdogPeriodSeconds = function() {
        return wd_period_sec;
    };

    /**
     *  Start the Charybdefs filesystem.
     */
    this.start = function() {
        this.cleanup();

        this._runControl("start",
                         "--fuse_mount=" + mount_point,
                         "--backing_path=" + backing_path,
                         "--log_file=foo_fs.log");
        print("Charybdefs sucessfully started.");
    };

    // Get the current check generation
    function _getGeneration(admin) {
        const result = admin.runCommand({"serverStatus": 1});

        assert.commandWorked(result);

        return result.watchdog.checkGeneration;
    }

    /**
     *  Wait for the watchdog to run some checks first.
     *
     * @param {object} MongoDB connection to admin database
     */
    this.waitForWatchdogToStart = function(admin) {
        print("Waiting for MongoDB watchdog to checks run twice.");
        assert.soon(function() {
            return _getGeneration(admin) > 2;
        }, "Watchdog did not start running", 5 * wd_period_sec * 1000);
    };

    /**
     *  Inject delay on write, and wait to MongoDB to get hung.
     *
     * @param {string} file_name - file name to inject fault on
     */
    this.addWriteDelayFaultAndWait = function(file_name) {
        // Convert seconds to microseconds for charybdefs
        const delay_us = fs_delay_sec * 1000000;
        this.addFault("write_buf", file_name, delay_us);

        // Wait for watchdog to stop
        print("Waiting for MongoDB to hang.");
        sleep(fs_delay_sec * 1000);
    };

    /**
     * Add a fault to inject.
     *
     * @param {string} method - name of fuse method to inject fault for
     * @param {string} file_name - file name to inject fault on
     * @param {number} delay_us - optional delay in microseconds to wait
     */
    this.addFault = function(method, file_name, delay_us) {
        this._runControl("set_fault",
                         "--methods=" + method,
                         "--errno=5",
                         "--probability=100000",
                         "--regexp=.*" + file_name,
                         "--delay_us=" + delay_us);
    };

    /**
     * Shutdown and clean up the Charybdefs filesystem.
     */
    this.cleanup = function() {
        this._runControl("stop_all", "--fuse_mount=" + mount_point);

        // Delete any remaining files
        resetDbpath(mount_point);
        resetDbpath(backing_path);
    };
}