summaryrefslogtreecommitdiff
path: root/jstests/noPassthrough/balancer_window.js
blob: 15df48c634f2a75a245186797c31483539c7f1a3 (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
126
127
128
129
130
131
132
133
134
/**
 * Tests that the balancer should not be moving chunks outside of the active window.
 * The outline of the test goes like this:
 * 1. Disable balancer to make sure that it will not try to move chunk on the setup phase.
 * 2. Setup the sharded collections by splitting it into 16 chunks. Since none of the chunks
 *    are being moved, all of them will end up on a single shard.
 * 3. Turn the balancer setting to on and set the active balancing window to a time that is
 *    outside of the current time at the same time.
 * 4. Make sure that no chunks have moved for at least one balancing round.
 * 5. Reset the active balancing window to a setting that overlaps the current time and make
 *    sure that some chunks are moved.
 */
(function() {
/**
 * Simple representation for wall clock time. Hour and minutes should be integers.
 */
var HourAndMinute = function(hour, minutes) {
    return {
        /**
         * Returns a new HourAndMinute object with the amount of hours added.
         * Amount can be negative.
         */
        addHour: function(amount) {
            var newHour = (hour + amount) % 24;
            if (newHour < 0) {
                newHour += 24;
            }

            return new HourAndMinute(newHour, minutes);
        },

        /**
         * Returns a string representation that is compatible with the format for the balancer
         * window settings.
         */
        toString: function() {
            var minStr = (minutes < 10) ? ('0' + minutes) : ('' + minutes);
            var hourStr = (hour < 10) ? ('0' + hour) : ('' + hour);
            return hourStr + ':' + minStr;
        }
    };
};

/**
 * Waits until at least one balancing round has passed.
 *
 * Note: This relies on the fact that the balancer pings the config.mongos document every round.
 */
var waitForAtLeastOneBalanceRound = function(mongosHost, timeoutMS) {
    var mongos = new Mongo(mongosHost);
    var configDB = mongos.getDB('config');

    // Wait for ts to change twice because:
    // 1st: for start of the balancing round.
    // 2nd: for the start of the next round, which implies that the previous one has ended.
    var waitForTSChangeNTimes = 2;
    var lastPing = new Date(0);

    assert.soon(function() {
        // Note: The balancer pings twice, once with { waiting: false } at the beginning
        // and another { waiting: true } at the end. Poll for the negative edge since
        // the smallest granurality should be a second, if for some reason the interval
        // became less than a second, it can cause this to miss the negative edge and
        // wake it wait longer than it should.
        var currentPing = configDB.mongos.findOne({ _id: mongosHost, waiting: true });
        if (currentPing == null) {
            return false;
        }

        if (currentPing.ping.valueOf() != lastPing.valueOf()) {
            waitForTSChangeNTimes--;
            lastPing = currentPing.ping;
        }

        return waitForTSChangeNTimes <= 0;
    }, 'Timed out waiting for mongos ping to change ' + waitForTSChangeNTimes + ' more times',
                timeoutMS, 500);
};

var st = new ShardingTest({ shards: 2 });
var configDB = st.s.getDB('config');
assert.commandWorked(configDB.adminCommand({ configureFailPoint: 'balancerRoundIntervalSetting',
                                             mode: 'alwaysOn',
                                             data: { sleepSecs: 1 }}));

configDB.adminCommand({ enableSharding: 'test' });
configDB.adminCommand({ shardCollection: 'test.user', key: { _id: 1 }});

// Disable balancer so it will not interfere with the chunk distribution setup.
st.stopBalancer();

for (var x = 0; x < 150; x += 10) {
    configDB.adminCommand({ split: 'test.user', middle: { _id: x }});
}

var shard0Chunks = configDB.chunks.find({ ns: 'test.user', shard: 'shard0000' }).count();

var startDate = new Date();
var hourMinStart = new HourAndMinute(startDate.getHours(), startDate.getMinutes());
configDB.settings.update({ _id: 'balancer' },
                         {
                             $set: {
                                 activeWindow: {
                                     start: hourMinStart.addHour(-2).toString(),
                                     stop: hourMinStart.addHour(-1).toString()
                                 },
                                 stopped: false
                             }
                         },
                         true);

waitForAtLeastOneBalanceRound(st.s.host, 60 * 1000);

var shard0ChunksAfter = configDB.chunks.find({ ns: 'test.user', shard: 'shard0000' }).count();
assert.eq(shard0Chunks, shard0ChunksAfter);

configDB.settings.update({ _id: 'balancer' },
                         {
                             $set: {
                                 activeWindow: {
                                     start: hourMinStart.toString(),
                                     stop: hourMinStart.addHour(2).toString()
                                 }
                             }
                         },
                         true);

waitForAtLeastOneBalanceRound(st.s.host, 60 * 1000);

shard0ChunksAfter = configDB.chunks.find({ ns: 'test.user', shard: 'shard0000' }).count();
assert.neq(shard0Chunks, shard0ChunksAfter);

st.stop();
})();