msgpackr 2.0.2 → 2.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.
package/dist/test.js CHANGED
@@ -1410,7 +1410,14 @@
1410
1410
  let newSharedData = (packr._prepareStructures || prepareStructures)(structures, packr);
1411
1411
  if (!encodingError) { // TODO: If there is an encoding error, should make the structures as uninitialized so they get rebuilt next time
1412
1412
  if (packr.saveStructures(newSharedData, newSharedData.isCompatible) === false) {
1413
- // get updated structures and try again if the update failed
1413
+ // The save was declined (a concurrent writer updated the shared structures,
1414
+ // or the store transaction did not durably commit). Our in-memory
1415
+ // structures + transition trie may now reference record ids that were
1416
+ // never persisted; re-packing as-is would re-emit the same record pointing
1417
+ // at an unpersisted structure (-> "Record id is not defined" on decode).
1418
+ // Mark structures uninitialized so the re-pack reloads durable structures
1419
+ // via getStructures, rebuilds the transition trie, and re-mints + re-saves.
1420
+ structures.uninitialized = true;
1414
1421
  return packr.pack(value, encodeOptions);
1415
1422
  }
1416
1423
  packr.lastNamedStructuresLength = sharedLength;
@@ -3307,6 +3314,30 @@
3307
3314
  assert.deepEqual(inputData, outputData);
3308
3315
  });
3309
3316
 
3317
+ test('declined structure save re-packs against durable structures (no dangling record)', function() {
3318
+ // Regression: when saveStructures declines a save (a concurrent writer updated the shared
3319
+ // structures, or the store txn did not durably commit), the in-memory structures/transition
3320
+ // trie reference a record id that was never persisted. The re-pack must reload the durable
3321
+ // structures and re-mint/re-save — otherwise it re-emits the same record pointing at an
3322
+ // unsaved structure, and reads throw "Record id is not defined".
3323
+ const meta = new Packr();
3324
+ let store = null;
3325
+ let declinedOnce = false;
3326
+ const packr = new Packr({
3327
+ useRecords: true,
3328
+ getStructures() { return store ? meta.unpack(store) : undefined; },
3329
+ saveStructures(structures) {
3330
+ if (!declinedOnce) { declinedOnce = true; return false; } // decline the first save
3331
+ store = meta.pack(structures); return true;
3332
+ },
3333
+ });
3334
+ const a = packr.pack({ x: 9, y: 8 });
3335
+ const b = packr.pack({ x: 7, y: 6 });
3336
+ const reader = new Packr({ getStructures() { return store ? meta.unpack(store) : undefined; } });
3337
+ assert.deepEqual(reader.unpack(a), { x: 9, y: 8 });
3338
+ assert.deepEqual(reader.unpack(b), { x: 7, y: 6 });
3339
+ });
3340
+
3310
3341
  test('big buffer', function() {
3311
3342
  var size = 100000000;
3312
3343
  var data = new Uint8Array(size).fill(1);