leo-connector-common 5.0.0 → 5.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,401 +1,401 @@
1
- "use strict";
2
- const async = require("async");
3
- const createNibbler = require("./nibbler.js");
4
-
5
- let logger = require("leo-logger")("leo-checksum.nibbler");
6
- const BODY_TOO_LARGE_ERROR = '{ "errorMessage" : "body size is too long"}';
7
-
8
- module.exports = function(local, remote, opts) {
9
-
10
- let nibbler = createNibbler(local, opts);
11
- let data = Object.assign({
12
- progress: 0,
13
- totalCorrect: 0,
14
- totalMissing: 0,
15
- totalIncorrect: 0,
16
- totalExtra: 0,
17
- streak: 0,
18
- }, (opts || {}).totals);
19
- // logger.log("START VALUES", data);
20
-
21
- // Add extra param to this sync;
22
- let sync = nibbler.sync;
23
- nibbler.sync = function(opts, resultCallback, callback) {
24
- let asyncMethod = opts.inSeries ? "mapSeries" : "map";
25
- let fieldNames = opts.fieldNames || [];
26
- let update = function(nibble, obj, results) {
27
- obj.progress += results.qty;
28
- obj.totalCorrect += results.correct;
29
- obj.totalMissing += results.missing;
30
- obj.totalIncorrect += results.incorrect;
31
- obj.totalExtra += results.extra;
32
-
33
- if (!results.missing && !results.incorrect && !results.extra) {
34
- obj.streak += results.qty;
35
- } else {
36
- obj.streak = 0;
37
- }
38
-
39
- nibble.progress = data.progress;
40
- nibbler.log(`Correct: ${results.correct}, Incorrect: ${results.incorrect}, Missing: ${results.missing}, Extra: ${results.extra}, Start: ${nibble.start}, End: ${nibble.end}`);
41
- };
42
-
43
- let compare = function(start, end, callback) {
44
- if (opts.skipBatch) {
45
- return callback(true, {
46
- errors: ["Skipping"],
47
- [local.name]: {
48
- hash: []
49
- },
50
- [remote.name]: {
51
- hash: []
52
- },
53
- duration: 0,
54
- qty: undefined
55
- });
56
- }
57
- nibbler.timeLog("Running Master & Slave Batch Checksum");
58
- async [asyncMethod]([local, remote], (connector, done) => {
59
- connector.getChecksum({
60
- start,
61
- end
62
- }).then(result => {
63
- done(null, result);
64
- }, callback);
65
- }, (err, batchResults) => {
66
- if (err) {
67
- callback(err);
68
- return;
69
- }
70
- let localData = batchResults[0];
71
- let remoteData = batchResults[1];
72
- let result = {
73
- errors: []
74
- };
75
- result[local.name] = localData;
76
- result[remote.name] = remoteData;
77
-
78
- if (localData.qty > remoteData.qty) {
79
- result.errors.push(remote.name + " has too few");
80
- }
81
- if (localData.qty < remoteData.qty) {
82
- result.errors.push(remote.name + " has too many");
83
- }
84
- if (
85
- localData.hash[0] != remoteData.hash[0] ||
86
- localData.hash[1] != remoteData.hash[1] ||
87
- localData.hash[2] != remoteData.hash[2] ||
88
- localData.hash[3] != remoteData.hash[3]
89
- ) {
90
- result.errors.push("Hashes do not match");
91
- }
92
-
93
- result.duration = Math.max(localData.duration, remoteData.duration);
94
- result.qty = localData.qty;
95
-
96
- if (result.errors.length == 0) {
97
- callback(null, result);
98
- } else {
99
- callback(true, result);
100
- }
101
- });
102
- };
103
-
104
- let compareIndividual = function(start, end, callback) {
105
- // log("running individual", start, end);
106
- nibbler.timeLog("Running Master & Slave Individual Checksum");
107
- async [asyncMethod]([local, remote], (connector, done) => {
108
- connector.getIndividualChecksums({
109
- start,
110
- end
111
- }).then(result => done(null, result), (err) => done(null, {
112
- error: err
113
- }));
114
- }, (err, indivData) => {
115
- if (err) {
116
- callback(err);
117
- return;
118
- }
119
- let localData = indivData[0];
120
- let remoteData = indivData[1];
121
- if (localData.error || remoteData.error) {
122
- callback(localData.error || remoteData.error);
123
- return;
124
- }
125
- let results = {
126
- missing: [],
127
- extra: [],
128
- incorrect: [],
129
- map: {},
130
- qty: localData.checksums.length
131
- };
132
-
133
- let localLookup = {};
134
- let remoteLookup = {};
135
- localData.checksums.map((o, i) => {
136
- localLookup[o.id] = i;
137
- });
138
- remoteData.checksums.map((o, i) => {
139
- remoteLookup[o.id] = i;
140
- if (!(o.id in localLookup)) {
141
- if (o._id) {
142
- results.map[o.id] = o._id;
143
- }
144
- results.extra.push(o.id);
145
- }
146
- });
147
- localData.checksums.map((o, i) => {
148
- if (!(o.id in remoteLookup)) {
149
- if (o._id) {
150
- results.map[o.id] = o._id;
151
- }
152
- results.missing.push(o.id);
153
- } else if (o.hash != remoteData.checksums[remoteLookup[o.id]].hash) {
154
- if (o._id) {
155
- results.map[o.id] = o._id;
156
- }
157
- results.incorrect.push(o.id);
158
- }
159
- });
160
- callback(null, results);
161
- });
162
- };
163
- let sample = function(ids, callback) {
164
- if (local.sample && remote.sample) {
165
- nibbler.timeLog("Running Master & Slave Sample");
166
-
167
- async [asyncMethod]([local, remote], (connector, done) => {
168
- connector.sample({
169
- ids
170
- }).then(result => done(null, result), done);
171
- }, (err, responses) => {
172
- if (err) {
173
- callback(err);
174
- return;
175
- }
176
- // logger.log(JSON.stringify(responses, null, 2));
177
- let localData = responses[0];
178
- let remoteData = responses[1];
179
- let diffs = [];
180
- let paddedLocalName = local.name;
181
- let paddedRemoteName = remote.name;
182
- if (paddedRemoteName.length > paddedLocalName.length) {
183
- paddedLocalName = paddedLocalName + " ".repeat(paddedRemoteName.length - paddedLocalName.length);
184
- } else if (paddedLocalName.length > paddedRemoteName.length) {
185
- paddedRemoteName = paddedRemoteName + " ".repeat(paddedLocalName.length - paddedRemoteName.length);
186
- }
187
- localData.ids = localData.ids.sort();
188
- localData.checksums.forEach((l, i) => {
189
- let diff = {};
190
- let r = remoteData.checksums[i];
191
- if (!r) {
192
- return;
193
- }
194
- let offset = Math.max(0, l.length - fieldNames.length);
195
- l.forEach((v, k) => {
196
- if (r && v !== r[k]) {
197
- let name = fieldNames[k - offset] || k;
198
- diff[name] = {
199
- [paddedLocalName]: v,
200
- [paddedRemoteName]: r[k] || null
201
- };
202
- }
203
- });
204
- offset = Math.max(0, r.length - fieldNames.length);
205
- r.forEach((v, k) => {
206
- if (l && !(k in l)) {
207
- let name = fieldNames[k - offset] || k;
208
- diff[name] = {
209
- [paddedLocalName]: null,
210
- [paddedRemoteName]: v
211
- };
212
- }
213
- });
214
- diffs.push({
215
- id: localData.ids[i],
216
- diff
217
- });
218
- });
219
- diffs.map(r => {
220
- nibbler.normalLog(`${r.id}: ${JSON.stringify(r.diff, (k, v) => v===undefined?'!!!undefined':v,2).replace(/"!!!undefined"/g, 'undefined')}`);
221
- });
222
- if (opts.onSample) {
223
- opts.onSample('incorrect', diffs, () => callback());
224
- } else {
225
- callback();
226
- }
227
- });
228
- } else {
229
- callback();
230
- }
231
-
232
- };
233
-
234
- local._getIndividualChecksums = local.getIndividualChecksums;
235
- local.getIndividualChecksums = function(...args) {
236
- if (local.getIndividualChecksums.cache) {
237
- logger.log("*** Getting individual data from cache ***");
238
- return Promise.resolve(local.getIndividualChecksums.cache);
239
- }
240
- return local._getIndividualChecksums.apply(this, args).then(data => {
241
- local.getIndividualChecksums.cache = data;
242
- logger.log("*** cache set ***");
243
- return data;
244
- }).catch(err => {
245
- delete local.getIndividualChecksums.cache;
246
- return err;
247
- });
248
- };
249
-
250
- let until = opts.until;
251
- let stopReason = null;
252
- let nibblerOpts = {
253
- whilst: function(nibble) {
254
- let streak = (!opts.stopOnStreak || data.streak < opts.stopOnStreak) ? false : "streak";
255
- let other = (!until || until(nibble));
256
- stopReason = other || streak;
257
- return !streak && !other;
258
- },
259
- onInit: function(nibble) {
260
- nibble.progress = data.progress;
261
- },
262
- onEnd: function(err, nibble, callback) {
263
- logger.log(`Summary`);
264
- logger.log(`Correct: ${data.totalCorrect}, Incorrect:${data.totalIncorrect}, Missing:${data.totalMissing}, Extra:${data.totalExtra}`);
265
- callback();
266
- },
267
- onError: function(err, result, nibble, done) {
268
- if (err && !result) {
269
- return done(err);
270
- }
271
- let onErrorErr = err;
272
- if (nibble.limit <= 20000 || result.qty < 20000 || opts.skipBatch) { //It is small enough, we need to do individual checks
273
- compareIndividual(nibble.start, nibble.end, (err, dataResult) => {
274
- if (err) {
275
- if (err == BODY_TOO_LARGE_ERROR && result.shouldCleanup !== false) {
276
- result.shouldCleanup = false;
277
- let keepIds = local.getIndividualChecksums.cache.checksums.map(o => o.id);
278
- let remoteQty = result[remote.name].qty || 0;
279
- let localQty = result[local.name].qty || 0;
280
- logger.error(`${local.name} Quantity(${localQty}) to ${remote.name} Quantity(${remoteQty}) is too high. Cleaning up ${remote.name} system.`);
281
- result.extraCount = remoteQty - localQty;
282
- // Clean up
283
- remote.delete({
284
- start: nibble.start,
285
- end: nibble.end,
286
- not_ids: keepIds
287
- }).then(() => {
288
- nibblerOpts.onError(onErrorErr, result, nibble, done);
289
- }).catch((e) => {
290
- logger.error(`${remote.name} delete err`, e);
291
- done(err);
292
- });
293
- } else {
294
- done(err);
295
- }
296
- return;
297
- }
298
-
299
- // request was successful so clear out any cache data
300
- delete local.getIndividualChecksums.cache;
301
-
302
- //Submit them to be resent
303
- if (result.qty === undefined) {
304
- result.qty = dataResult.qty;
305
- }
306
- resultCallback(dataResult, () => {
307
- //We can now move on, as we have dealt with it
308
- dataResult.correct = result.qty - (dataResult.incorrect.length + dataResult.missing.length);
309
- nibble.move();
310
- update(nibble, data, {
311
- qty: result.qty,
312
- correct: dataResult.correct,
313
- incorrect: dataResult.incorrect.length,
314
- missing: dataResult.missing.length,
315
- extra: dataResult.extra.length + (result.extraCount || 0)
316
- });
317
- if (opts.stats) {
318
- let d = done;
319
- done = function() {
320
- opts.stats(nibble, dataResult, data, d);
321
- };
322
- }
323
-
324
- if (opts.sample && dataResult.missing.length) {
325
- nibbler.normalLog("Missing: " + dataResult.missing.slice(0, 10).join());
326
- }
327
- if (opts.onSample && dataResult.missing.length) {
328
- opts.onSample('missing', dataResult.missing);
329
- }
330
- if (opts.sample && dataResult.extra.length) {
331
- nibbler.normalLog("Extra: " + dataResult.extra.slice(0, 10).join());
332
- }
333
- if (opts.onSample && dataResult.extra.length) {
334
- opts.onSample('extra', dataResult.extra);
335
- }
336
- if (opts.shouldDelete && dataResult.extra.length) {
337
- remote.delete({
338
- ids: dataResult.extra
339
- }).then(result => {
340
- logger.log("deleted records");
341
- }, err => {
342
- logger.log(err);
343
- });
344
- }
345
-
346
- if (opts.sample && dataResult.incorrect.length) {
347
- sample(dataResult.incorrect.slice(0).sort(() => {
348
- return 0.5 - Math.random();
349
- }).slice(0, 4), () => {
350
- done();
351
- });
352
- } else {
353
- done();
354
- }
355
- });
356
-
357
- });
358
- } else {
359
- if (nibble.limit <= 200000) {
360
- nibble.limit = 20000;
361
- } else {
362
- nibble.limit = Math.max(20000, Math.round(nibble.limit / 2));
363
- }
364
- done();
365
- }
366
- },
367
- onBite: function(nibble, done) {
368
- compare(nibble.start, nibble.end, (err, result) => {
369
- if (err) {
370
- done(err, result);
371
- } else { //No problem, we want to move on to the next bucket
372
- result.correct = result.qty;
373
- update(nibble, data, {
374
- qty: result.qty,
375
- correct: result.correct,
376
- incorrect: 0,
377
- missing: 0,
378
- extra: 0
379
- });
380
-
381
- if (opts.stats) {
382
- let d = done;
383
- done = function() {
384
- opts.stats(nibble, result, data, d);
385
- };
386
- }
387
-
388
- done(null, result);
389
- }
390
- });
391
- }
392
- };
393
-
394
- opts = Object.assign(opts, nibblerOpts);
395
- return sync(opts, function(err) {
396
- callback(err, data, err || stopReason || "complete");
397
- });
398
- };
399
-
400
- return nibbler;
401
- };
1
+ "use strict";
2
+ const async = require("async");
3
+ const createNibbler = require("./nibbler.js");
4
+
5
+ let logger = require("leo-logger")("leo-checksum.nibbler");
6
+ const BODY_TOO_LARGE_ERROR = '{ "errorMessage" : "body size is too long"}';
7
+
8
+ module.exports = function(local, remote, opts) {
9
+
10
+ let nibbler = createNibbler(local, opts);
11
+ let data = Object.assign({
12
+ progress: 0,
13
+ totalCorrect: 0,
14
+ totalMissing: 0,
15
+ totalIncorrect: 0,
16
+ totalExtra: 0,
17
+ streak: 0,
18
+ }, (opts || {}).totals);
19
+ // logger.log("START VALUES", data);
20
+
21
+ // Add extra param to this sync;
22
+ let sync = nibbler.sync;
23
+ nibbler.sync = function(opts, resultCallback, callback) {
24
+ let asyncMethod = opts.inSeries ? "mapSeries" : "map";
25
+ let fieldNames = opts.fieldNames || [];
26
+ let update = function(nibble, obj, results) {
27
+ obj.progress += results.qty;
28
+ obj.totalCorrect += results.correct;
29
+ obj.totalMissing += results.missing;
30
+ obj.totalIncorrect += results.incorrect;
31
+ obj.totalExtra += results.extra;
32
+
33
+ if (!results.missing && !results.incorrect && !results.extra) {
34
+ obj.streak += results.qty;
35
+ } else {
36
+ obj.streak = 0;
37
+ }
38
+
39
+ nibble.progress = data.progress;
40
+ nibbler.log(`Correct: ${results.correct}, Incorrect: ${results.incorrect}, Missing: ${results.missing}, Extra: ${results.extra}, Start: ${nibble.start}, End: ${nibble.end}`);
41
+ };
42
+
43
+ let compare = function(start, end, callback) {
44
+ if (opts.skipBatch) {
45
+ return callback(true, {
46
+ errors: ["Skipping"],
47
+ [local.name]: {
48
+ hash: []
49
+ },
50
+ [remote.name]: {
51
+ hash: []
52
+ },
53
+ duration: 0,
54
+ qty: undefined
55
+ });
56
+ }
57
+ nibbler.timeLog("Running Master & Slave Batch Checksum");
58
+ async [asyncMethod]([local, remote], (connector, done) => {
59
+ connector.getChecksum({
60
+ start,
61
+ end
62
+ }).then(result => {
63
+ done(null, result);
64
+ }, callback);
65
+ }, (err, batchResults) => {
66
+ if (err) {
67
+ callback(err);
68
+ return;
69
+ }
70
+ let localData = batchResults[0];
71
+ let remoteData = batchResults[1];
72
+ let result = {
73
+ errors: []
74
+ };
75
+ result[local.name] = localData;
76
+ result[remote.name] = remoteData;
77
+
78
+ if (localData.qty > remoteData.qty) {
79
+ result.errors.push(remote.name + " has too few");
80
+ }
81
+ if (localData.qty < remoteData.qty) {
82
+ result.errors.push(remote.name + " has too many");
83
+ }
84
+ if (
85
+ localData.hash[0] != remoteData.hash[0] ||
86
+ localData.hash[1] != remoteData.hash[1] ||
87
+ localData.hash[2] != remoteData.hash[2] ||
88
+ localData.hash[3] != remoteData.hash[3]
89
+ ) {
90
+ result.errors.push("Hashes do not match");
91
+ }
92
+
93
+ result.duration = Math.max(localData.duration, remoteData.duration);
94
+ result.qty = localData.qty;
95
+
96
+ if (result.errors.length == 0) {
97
+ callback(null, result);
98
+ } else {
99
+ callback(true, result);
100
+ }
101
+ });
102
+ };
103
+
104
+ let compareIndividual = function(start, end, callback) {
105
+ // log("running individual", start, end);
106
+ nibbler.timeLog("Running Master & Slave Individual Checksum");
107
+ async [asyncMethod]([local, remote], (connector, done) => {
108
+ connector.getIndividualChecksums({
109
+ start,
110
+ end
111
+ }).then(result => done(null, result), (err) => done(null, {
112
+ error: err
113
+ }));
114
+ }, (err, indivData) => {
115
+ if (err) {
116
+ callback(err);
117
+ return;
118
+ }
119
+ let localData = indivData[0];
120
+ let remoteData = indivData[1];
121
+ if (localData.error || remoteData.error) {
122
+ callback(localData.error || remoteData.error);
123
+ return;
124
+ }
125
+ let results = {
126
+ missing: [],
127
+ extra: [],
128
+ incorrect: [],
129
+ map: {},
130
+ qty: localData.checksums.length
131
+ };
132
+
133
+ let localLookup = {};
134
+ let remoteLookup = {};
135
+ localData.checksums.map((o, i) => {
136
+ localLookup[o.id] = i;
137
+ });
138
+ remoteData.checksums.map((o, i) => {
139
+ remoteLookup[o.id] = i;
140
+ if (!(o.id in localLookup)) {
141
+ if (o._id) {
142
+ results.map[o.id] = o._id;
143
+ }
144
+ results.extra.push(o.id);
145
+ }
146
+ });
147
+ localData.checksums.map((o, i) => {
148
+ if (!(o.id in remoteLookup)) {
149
+ if (o._id) {
150
+ results.map[o.id] = o._id;
151
+ }
152
+ results.missing.push(o.id);
153
+ } else if (o.hash != remoteData.checksums[remoteLookup[o.id]].hash) {
154
+ if (o._id) {
155
+ results.map[o.id] = o._id;
156
+ }
157
+ results.incorrect.push(o.id);
158
+ }
159
+ });
160
+ callback(null, results);
161
+ });
162
+ };
163
+ let sample = function(ids, callback) {
164
+ if (local.sample && remote.sample) {
165
+ nibbler.timeLog("Running Master & Slave Sample");
166
+
167
+ async [asyncMethod]([local, remote], (connector, done) => {
168
+ connector.sample({
169
+ ids
170
+ }).then(result => done(null, result), done);
171
+ }, (err, responses) => {
172
+ if (err) {
173
+ callback(err);
174
+ return;
175
+ }
176
+ // logger.log(JSON.stringify(responses, null, 2));
177
+ let localData = responses[0];
178
+ let remoteData = responses[1];
179
+ let diffs = [];
180
+ let paddedLocalName = local.name;
181
+ let paddedRemoteName = remote.name;
182
+ if (paddedRemoteName.length > paddedLocalName.length) {
183
+ paddedLocalName = paddedLocalName + " ".repeat(paddedRemoteName.length - paddedLocalName.length);
184
+ } else if (paddedLocalName.length > paddedRemoteName.length) {
185
+ paddedRemoteName = paddedRemoteName + " ".repeat(paddedLocalName.length - paddedRemoteName.length);
186
+ }
187
+ localData.ids = localData.ids.sort();
188
+ localData.checksums.forEach((l, i) => {
189
+ let diff = {};
190
+ let r = remoteData.checksums[i];
191
+ if (!r) {
192
+ return;
193
+ }
194
+ let offset = Math.max(0, l.length - fieldNames.length);
195
+ l.forEach((v, k) => {
196
+ if (r && v !== r[k]) {
197
+ let name = fieldNames[k - offset] || k;
198
+ diff[name] = {
199
+ [paddedLocalName]: v,
200
+ [paddedRemoteName]: r[k] || null
201
+ };
202
+ }
203
+ });
204
+ offset = Math.max(0, r.length - fieldNames.length);
205
+ r.forEach((v, k) => {
206
+ if (l && !(k in l)) {
207
+ let name = fieldNames[k - offset] || k;
208
+ diff[name] = {
209
+ [paddedLocalName]: null,
210
+ [paddedRemoteName]: v
211
+ };
212
+ }
213
+ });
214
+ diffs.push({
215
+ id: localData.ids[i],
216
+ diff
217
+ });
218
+ });
219
+ diffs.map(r => {
220
+ nibbler.normalLog(`${r.id}: ${JSON.stringify(r.diff, (k, v) => v===undefined?'!!!undefined':v,2).replace(/"!!!undefined"/g, 'undefined')}`);
221
+ });
222
+ if (opts.onSample) {
223
+ opts.onSample('incorrect', diffs, () => callback());
224
+ } else {
225
+ callback();
226
+ }
227
+ });
228
+ } else {
229
+ callback();
230
+ }
231
+
232
+ };
233
+
234
+ local._getIndividualChecksums = local.getIndividualChecksums;
235
+ local.getIndividualChecksums = function(...args) {
236
+ if (local.getIndividualChecksums.cache) {
237
+ logger.log("*** Getting individual data from cache ***");
238
+ return Promise.resolve(local.getIndividualChecksums.cache);
239
+ }
240
+ return local._getIndividualChecksums.apply(this, args).then(data => {
241
+ local.getIndividualChecksums.cache = data;
242
+ logger.log("*** cache set ***");
243
+ return data;
244
+ }).catch(err => {
245
+ delete local.getIndividualChecksums.cache;
246
+ return err;
247
+ });
248
+ };
249
+
250
+ let until = opts.until;
251
+ let stopReason = null;
252
+ let nibblerOpts = {
253
+ whilst: function(nibble) {
254
+ let streak = (!opts.stopOnStreak || data.streak < opts.stopOnStreak) ? false : "streak";
255
+ let other = (!until || until(nibble));
256
+ stopReason = other || streak;
257
+ return !streak && !other;
258
+ },
259
+ onInit: function(nibble) {
260
+ nibble.progress = data.progress;
261
+ },
262
+ onEnd: function(err, nibble, callback) {
263
+ logger.log(`Summary`);
264
+ logger.log(`Correct: ${data.totalCorrect}, Incorrect:${data.totalIncorrect}, Missing:${data.totalMissing}, Extra:${data.totalExtra}`);
265
+ callback();
266
+ },
267
+ onError: function(err, result, nibble, done) {
268
+ if (err && !result) {
269
+ return done(err);
270
+ }
271
+ let onErrorErr = err;
272
+ if (nibble.limit <= 20000 || result.qty < 20000 || opts.skipBatch) { //It is small enough, we need to do individual checks
273
+ compareIndividual(nibble.start, nibble.end, (err, dataResult) => {
274
+ if (err) {
275
+ if (err == BODY_TOO_LARGE_ERROR && result.shouldCleanup !== false) {
276
+ result.shouldCleanup = false;
277
+ let keepIds = local.getIndividualChecksums.cache.checksums.map(o => o.id);
278
+ let remoteQty = result[remote.name].qty || 0;
279
+ let localQty = result[local.name].qty || 0;
280
+ logger.error(`${local.name} Quantity(${localQty}) to ${remote.name} Quantity(${remoteQty}) is too high. Cleaning up ${remote.name} system.`);
281
+ result.extraCount = remoteQty - localQty;
282
+ // Clean up
283
+ remote.delete({
284
+ start: nibble.start,
285
+ end: nibble.end,
286
+ not_ids: keepIds
287
+ }).then(() => {
288
+ nibblerOpts.onError(onErrorErr, result, nibble, done);
289
+ }).catch((e) => {
290
+ logger.error(`${remote.name} delete err`, e);
291
+ done(err);
292
+ });
293
+ } else {
294
+ done(err);
295
+ }
296
+ return;
297
+ }
298
+
299
+ // request was successful so clear out any cache data
300
+ delete local.getIndividualChecksums.cache;
301
+
302
+ //Submit them to be resent
303
+ if (result.qty === undefined) {
304
+ result.qty = dataResult.qty;
305
+ }
306
+ resultCallback(dataResult, () => {
307
+ //We can now move on, as we have dealt with it
308
+ dataResult.correct = result.qty - (dataResult.incorrect.length + dataResult.missing.length);
309
+ nibble.move();
310
+ update(nibble, data, {
311
+ qty: result.qty,
312
+ correct: dataResult.correct,
313
+ incorrect: dataResult.incorrect.length,
314
+ missing: dataResult.missing.length,
315
+ extra: dataResult.extra.length + (result.extraCount || 0)
316
+ });
317
+ if (opts.stats) {
318
+ let d = done;
319
+ done = function() {
320
+ opts.stats(nibble, dataResult, data, d);
321
+ };
322
+ }
323
+
324
+ if (opts.sample && dataResult.missing.length) {
325
+ nibbler.normalLog("Missing: " + dataResult.missing.slice(0, 10).join());
326
+ }
327
+ if (opts.onSample && dataResult.missing.length) {
328
+ opts.onSample('missing', dataResult.missing);
329
+ }
330
+ if (opts.sample && dataResult.extra.length) {
331
+ nibbler.normalLog("Extra: " + dataResult.extra.slice(0, 10).join());
332
+ }
333
+ if (opts.onSample && dataResult.extra.length) {
334
+ opts.onSample('extra', dataResult.extra);
335
+ }
336
+ if (opts.shouldDelete && dataResult.extra.length) {
337
+ remote.delete({
338
+ ids: dataResult.extra
339
+ }).then(result => {
340
+ logger.log("deleted records");
341
+ }, err => {
342
+ logger.log(err);
343
+ });
344
+ }
345
+
346
+ if (opts.sample && dataResult.incorrect.length) {
347
+ sample(dataResult.incorrect.slice(0).sort(() => {
348
+ return 0.5 - Math.random();
349
+ }).slice(0, 4), () => {
350
+ done();
351
+ });
352
+ } else {
353
+ done();
354
+ }
355
+ });
356
+
357
+ });
358
+ } else {
359
+ if (nibble.limit <= 200000) {
360
+ nibble.limit = 20000;
361
+ } else {
362
+ nibble.limit = Math.max(20000, Math.round(nibble.limit / 2));
363
+ }
364
+ done();
365
+ }
366
+ },
367
+ onBite: function(nibble, done) {
368
+ compare(nibble.start, nibble.end, (err, result) => {
369
+ if (err) {
370
+ done(err, result);
371
+ } else { //No problem, we want to move on to the next bucket
372
+ result.correct = result.qty;
373
+ update(nibble, data, {
374
+ qty: result.qty,
375
+ correct: result.correct,
376
+ incorrect: 0,
377
+ missing: 0,
378
+ extra: 0
379
+ });
380
+
381
+ if (opts.stats) {
382
+ let d = done;
383
+ done = function() {
384
+ opts.stats(nibble, result, data, d);
385
+ };
386
+ }
387
+
388
+ done(null, result);
389
+ }
390
+ });
391
+ }
392
+ };
393
+
394
+ opts = Object.assign(opts, nibblerOpts);
395
+ return sync(opts, function(err) {
396
+ callback(err, data, err || stopReason || "complete");
397
+ });
398
+ };
399
+
400
+ return nibbler;
401
+ };