Skip to content

Commit 8081799

Browse files
authored
fix(loki): fix binary index in batch updates when not cloning (#78)
Batch updates will now temporarily disable adaptive indices (when not cloning) for the duration of the batch update if binary indices are defined. We will do a full lazy rebuild when batch update completes and re-enable adaptive indices. This fixes edge case where binary indices could become corrupt. If your batches are small or medium sized it will likely be faster to update docs individually, as they are modified instead. See techfort/LokiJS@0178e9d
1 parent 75afd67 commit 8081799

File tree

2 files changed

+66
-5
lines changed

2 files changed

+66
-5
lines changed

packages/loki/spec/generic/binaryidx.spec.ts

+48
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,54 @@ describe("binary indices", () => {
323323
});
324324
});
325325

326+
describe("adaptiveBinaryIndex batch updates work", () => {
327+
it("works", function() {
328+
const db = new Loki("idxtest");
329+
const items = db.addCollection<{a: number, b:boolean}>("items", {
330+
adaptiveBinaryIndices: true,
331+
indices: ["b"]
332+
});
333+
334+
// init 4 docs with bool 'b' all false
335+
const docs = [{a:8000, b:false}, {a:6000, b:false}, {a:4000, b: false}, {a:2000, b:false}];
336+
337+
items.insert(docs);
338+
339+
// update two docs to have 'b' true
340+
let results = items.find({a: {$in: [8000, 6000]}});
341+
results.forEach(function(obj) {
342+
obj.b = true;
343+
});
344+
items.update(results);
345+
346+
// should be 2 of each
347+
expect(items.find({b: true}).length).toEqual(2);
348+
expect(items.find({b: false}).length).toEqual(2);
349+
350+
// reset all bool 'b' props to false
351+
results = items.find({b: true});
352+
results.forEach(function(obj) {
353+
obj.b = false;
354+
});
355+
items.update(results);
356+
357+
// should be no true and 4 false
358+
expect(items.find({b: true}).length).toEqual(0);
359+
expect(items.find({b: false}).length).toEqual(4);
360+
361+
// update different 2 to be true
362+
results = items.find({a: {$in: [8000, 2000]}});
363+
results.forEach(function(obj) {
364+
obj.b = true;
365+
});
366+
items.update(results);
367+
368+
// should be 2 true and 2 false
369+
expect(items.find({b: true}).length).toEqual(2);
370+
expect(items.find({b: false}).length).toEqual(2);
371+
});
372+
});
373+
326374
describe("adaptiveBinaryIndexRemove works", () => {
327375
it("works", () => {
328376

packages/loki/src/collection.ts

+18-5
Original file line numberDiff line numberDiff line change
@@ -831,14 +831,27 @@ export class Collection<TData extends object = object, TNested extends object =
831831
*/
832832
public update(doc: Doc<TData> | Doc<TData>[]): void {
833833
if (Array.isArray(doc)) {
834-
let k = 0;
835-
const len = doc.length;
836-
for (k; k < len; k++) {
837-
this.update(doc[k]);
834+
835+
// If not cloning, disable adaptive binary indices for the duration of the batch update,
836+
// followed by lazy rebuild and re-enabling adaptive indices after batch update.
837+
const adaptiveBatchOverride = !this.cloneObjects && this.adaptiveBinaryIndices
838+
&& Object.keys(this.binaryIndices).length > 0;
839+
if (adaptiveBatchOverride) {
840+
this.adaptiveBinaryIndices = false;
838841
}
842+
843+
for (let i = 0; i < doc.length; i++) {
844+
this.update(doc[i]);
845+
}
846+
847+
if (adaptiveBatchOverride) {
848+
this.ensureAllIndexes();
849+
this.adaptiveBinaryIndices = true;
850+
}
851+
839852
return;
840853
}
841-
// verify object is a properly formed document
854+
// Verify object is a properly formed document.
842855
if (doc.$loki === undefined) {
843856
throw new Error("Trying to update unsynced document. Please save the document first by using insert() or addMany()");
844857
}

0 commit comments

Comments
 (0)