-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathresolve-changes.js
120 lines (115 loc) · 4.57 KB
/
resolve-changes.js
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
var dartEvents = require('./shared/dart-events');
var async = require('async');
// Function that returns a function that should be called on each database
// change. It's job is to ensure the database is consistent. For example,
// suppose we have two offline users, A and B that both record the results of
// different matches. Assume A's match happen before B's. If B gets online and
// sync's before A the data would be incorrect. However, when A gets online
// we'll get an update and we can then look at all documents that come *after* A
// and fix any problems.
module.exports = function(db) {
return function(change, userCb) {
var doc = change.doc;
var changes = {docs: []};
// Does the following, in series:
//
// 1) Grabs the doc before the current one and ensures they are consistent
// 2) Grabs all teh docs after the current one and ensures they are all
// consistent.
// 3) Writes any changes back to the DB.
async.series([
function(cb) {
db.getPrevDoc(doc._id, function(err, prevDoc) {
if (prevDoc === null) {
cb();
return;
}
if (err) {
cb(err);
return;
}
var correctRanking = dartEvents.applyEvent(
prevDoc.ranking, doc.event);
if (dartEvents.rankingsEqual(correctRanking, doc.ranking)) {
console.log('%s is consistent with the previous doc, %s',
doc._id, prevDoc._id);
cb(null);
} else {
console.log('%s was not consistent with the previous doc, %s. ' +
'Correct ranking: %j, received ranking: %j', doc._id,
prevDoc._id, correctRanking, doc.ranking);
doc.ranking = correctRanking.slice(0);
console.assert(doc._rev);
changes.docs.push(doc);
cb(null);
}
});
},
function(cb) {
db.allDocs({include_docs: true, startkey: doc._id},
function(err, res) {
if (err) {
console.error('Unable to retrieve updated documents!', err);
cb(err);
} else {
console.log('%d documents exist after changed document %s',
res.rows.length - 1, doc._id);
if (res.rows.length <= 1) {
if (cb) cb(null, null);
return;
}
// Starting with the first document, apply the changes in the
// next document. If the computed rankings match the observed,
// we're done. If not, we need to fix that document.
var curRanking = res.rows[0].doc.ranking;
for (var i = 1; i < res.rows.length; ++i) {
console.log('Checking %s', res.rows[i].doc._id);
var nextDoc = res.rows[i].doc;
var newRanking =
dartEvents.applyEvent(curRanking, nextDoc['event']);
if (dartEvents.rankingsEqual(newRanking, nextDoc.ranking)) {
console.info('Change consistent.');
break;
} else {
console.info('Change requires update. ' +
'Computed ranking: %j. Old ranking: %j',
newRanking, nextDoc.ranking);
nextDoc.ranking = newRanking.slice(0);
console.assert(nextDoc._rev);
changes.docs.push(nextDoc);
}
curRanking = newRanking;
}
cb(null);
}
});
},
function(cb) {
if (changes.docs.length > 0) {
console.log('Applying %d database changes.', changes.docs.length);
db.bulkDocs(changes, function(err, response) {
if (err) {
cb(err);
return;
}
console.log('bulkDocs returned: %j', response);
if (response.every(function(x) {return x.ok;})) {
cb(null, null);
} else {
cb(new Error('There were some errors updating the db'));
}
});
} else {
cb(null, null);
}
}],
function(err) {
if (err) {
console.error('Error fixing up database: ', err);
if (userCb) userCb(err);
} else {
if (userCb) userCb();
}
});
};
};