File: server8070.js

package info (click to toggle)
mongodb 1%3A2.4.10-5
  • links: PTS, VCS
  • area: main
  • in suites: jessie-kfreebsd
  • size: 82,464 kB
  • sloc: cpp: 740,225; ansic: 152,098; sh: 13,820; python: 11,864; makefile: 1,012; perl: 922; pascal: 617; java: 452; lisp: 222; asm: 174
file content (143 lines) | stat: -rw-r--r-- 4,639 bytes parent folder | download | duplicates (3)
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
135
136
137
138
139
140
141
142
143
// Test for SERVER-8070: Flush buffer before changing sync targets to prevent unnecessary rollbacks
// This test writes 50 ops to one secondary's data (member2) and 25 ops to the other secondary's
// data (member3), then puts 50 more ops in member3's buffer and makes sure that member3 doesn't try
// to sync from member2.

var replSet = new ReplSetTest({name: 'testSet', nodes: 3});
replSet.startSet();
replSet.initiate(
    {
        _id:'testSet',
        members:
        [
            {_id: 0, host: getHostName()+":"+replSet.ports[0]},
            {_id: 1, host: getHostName()+":"+replSet.ports[1], priority: 0},
            {_id: 2, host: getHostName()+":"+replSet.ports[2], priority: 0}
        ]
    }
);

var checkRepl = function(db1, db2) {
    assert.soon(
        function() {
            var last1 = db1.getSisterDB("local").oplog.rs.find().sort({$natural:-1}).limit(1)
                .next();
            var last2 = db2.getSisterDB("local").oplog.rs.find().sort({$natural:-1}).limit(1)
                .next();
            print(tojson(last1)+" "+tojson(last2));

            return ((last1.ts.t === last2.ts.t) && (last1.ts.i === last2.ts.i))
        }
    );
};

// Do an initial write
var master = replSet.getMaster();
master.getDB("foo").bar.insert({x:1});
replSet.awaitReplication();

var primary = master.getDB("foo");
replSet.nodes[1].setSlaveOk();
replSet.nodes[2].setSlaveOk();
var member2 = replSet.nodes[1].getDB("admin");
var member3 = replSet.nodes[2].getDB("admin");

print("Make sure 2 & 3 are syncing from the primary");
member2.adminCommand({replSetSyncFrom : getHostName()+":"+replSet.ports[0]});
member3.adminCommand({replSetSyncFrom : getHostName()+":"+replSet.ports[0]});

print("Stop 2's replication");
member2.runCommand({configureFailPoint: 'rsSyncApplyStop', mode: 'alwaysOn'});

print("Do a few writes");
for (var i = 0; i < 25; i++) {
    primary.bar.insert({x: i});
}

print("Make sure 3 is at write #25");
checkRepl(primary, member3);
// This means 3's buffer is empty

print("Stop 3's replication");
member3.runCommand({configureFailPoint: 'rsSyncApplyStop', mode: 'alwaysOn'});

print("Start 2's replication");
member2.runCommand({configureFailPoint: 'rsSyncApplyStop', mode: 'off'});

print("Do some writes");
for (var i = 25; i < 50; i++) {
    primary.bar.insert({x: i});
}

print("Make sure 2 is at write #50");
checkRepl(primary, member2);
// This means 2's buffer is empty

print("Stop 2's replication");
member2.runCommand({configureFailPoint: 'rsSyncApplyStop', mode: 'alwaysOn'});

print("Do some writes - 2 & 3 should have up to write #75 in their buffers, but unapplied");
for (var i = 50; i < 75; i++) {
    primary.bar.insert({x: i});
}
var last = primary.getSisterDB("local").oplog.rs.find().sort({$natural:-1}).limit(1).next();

print("waiting a bit for the secondaries to get the write");
sleep(10000);

print("Shut down the primary");
replSet.stop(0);

// This was used before the server was fixed to prove that the code was broken
var unfixed = function() {
    print("3 should attempt to sync from 2, as 2 is 'ahead'");
    assert.soon(
        function() {
            var syncingTo = member3.adminCommand({replSetGetStatus:1}).syncingTo;
            return syncingTo == getHostName()+":"+replSet.ports[1];
        }
    );
};

var fixed = function() {
    print("3 should not attempt to sync from 2, as it cannot clear its buffer");
    assert.throws(
        function() {
            assert.soon(
                function() {
                    var syncingTo = member3.adminCommand({replSetGetStatus:1}).syncingTo;
                    return syncingTo == getHostName()+":"+replSet.ports[1];
                }
            );
        }
    );
};

//unfixed();
fixed();

print(" --- pause 3's bgsync thread ---");
member3.runCommand({configureFailPoint: 'rsBgSyncProduce', mode: 'alwaysOn'});

print("Allow 3 to apply ops 25-75");
member3.runCommand({configureFailPoint: 'rsSyncApplyStop', mode: 'off'});
assert.soon(
    function() {
        var last3 = member3.getSisterDB("local").oplog.rs.find().sort({$natural:-1}).limit(1)
            .next();
        print("primary: " + tojson(last.ts) + " secondary: " + tojson(last3.ts));
        return ((last.ts.t === last3.ts.t) && (last.ts.i === last3.ts.i))
    }
);

print(" --- start 3's bgsync thread ---");
member3.runCommand({configureFailPoint: 'rsBgSyncProduce', mode: 'off'});

print("Shouldn't hit rollback");
var end = (new Date()).getTime()+10000;
while ((new Date()).getTime() < end) {
    assert('ROLLBACK' != member3.runCommand({replSetGetStatus:1}).members[2].stateStr);
    sleep(30);
}

replSet.stopSet();