@luvio/environments 0.109.0 → 0.109.1
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/es/es2018/environments.js +79 -43
- package/dist/umd/es2018/environments.js +79 -43
- package/dist/umd/es5/environments.js +113 -63
- package/package.json +2 -2
|
@@ -365,18 +365,19 @@ function buildIngestStagingStore(environment) {
|
|
|
365
365
|
|
|
366
366
|
const AdapterContextSegment = 'ADAPTER-CONTEXT';
|
|
367
367
|
const ADAPTER_CONTEXT_ID_SUFFIX = '__NAMED_CONTEXT';
|
|
368
|
-
function reviveOrCreateContext(adapterId, durableStore, durableStoreErrorHandler, onContextLoaded) {
|
|
368
|
+
async function reviveOrCreateContext(adapterId, durableStore, durableStoreErrorHandler, contextStores, pendingContextStoreKeys, onContextLoaded) {
|
|
369
369
|
// initialize empty context store
|
|
370
|
-
|
|
370
|
+
contextStores[adapterId] = create(null);
|
|
371
371
|
const context = {
|
|
372
372
|
set(key, value) {
|
|
373
|
-
|
|
373
|
+
contextStores[adapterId][key] = value;
|
|
374
374
|
durableStore.setEntries({
|
|
375
|
-
[adapterId]: { data:
|
|
375
|
+
[adapterId]: { data: contextStores[adapterId] },
|
|
376
376
|
}, AdapterContextSegment);
|
|
377
|
+
pendingContextStoreKeys.add(adapterId);
|
|
377
378
|
},
|
|
378
379
|
get(key) {
|
|
379
|
-
return
|
|
380
|
+
return contextStores[adapterId][key];
|
|
380
381
|
},
|
|
381
382
|
};
|
|
382
383
|
const contextReturn = () => {
|
|
@@ -387,17 +388,17 @@ function reviveOrCreateContext(adapterId, durableStore, durableStoreErrorHandler
|
|
|
387
388
|
}
|
|
388
389
|
return context;
|
|
389
390
|
};
|
|
390
|
-
|
|
391
|
-
|
|
391
|
+
try {
|
|
392
|
+
const entries = await durableStore.getEntries([adapterId], AdapterContextSegment);
|
|
392
393
|
if (entries !== undefined && entries[adapterId] !== undefined) {
|
|
393
|
-
|
|
394
|
+
// if durable store has a saved context then load it in the store
|
|
395
|
+
contextStores[adapterId] = entries[adapterId].data;
|
|
394
396
|
}
|
|
395
|
-
|
|
396
|
-
|
|
397
|
+
}
|
|
398
|
+
catch (error) {
|
|
397
399
|
durableStoreErrorHandler(error);
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
});
|
|
400
|
+
}
|
|
401
|
+
return contextReturn();
|
|
401
402
|
}
|
|
402
403
|
function isUnfulfilledSnapshot(cachedSnapshotResult) {
|
|
403
404
|
if (cachedSnapshotResult === undefined) {
|
|
@@ -420,6 +421,11 @@ function makeDurable(environment, { durableStore, instrumentation }) {
|
|
|
420
421
|
let ingestStagingStore = null;
|
|
421
422
|
const durableTTLStore = new DurableTTLStore(durableStore);
|
|
422
423
|
const mergeKeysPromiseMap = new Map();
|
|
424
|
+
// When a context store is mutated we write it to L2, which causes DS on change
|
|
425
|
+
// event. If this instance of makeDurable caused that L2 write we can ignore that
|
|
426
|
+
// on change event. This Set helps us do that.
|
|
427
|
+
const pendingContextStoreKeys = new Set();
|
|
428
|
+
const contextStores = create(null);
|
|
423
429
|
let initializationPromise = new Promise((resolve) => {
|
|
424
430
|
const finish = () => {
|
|
425
431
|
resolve();
|
|
@@ -436,38 +442,68 @@ function makeDurable(environment, { durableStore, instrumentation }) {
|
|
|
436
442
|
}
|
|
437
443
|
};
|
|
438
444
|
const unsubscribe = durableStore.registerOnChangedListener((changes) => {
|
|
439
|
-
const
|
|
445
|
+
const defaultSegmentKeys = [];
|
|
446
|
+
const adapterContextSegmentKeys = [];
|
|
447
|
+
for (let i = 0, len = changes.length; i < len; i++) {
|
|
448
|
+
const change = changes[i];
|
|
440
449
|
// we only care about changes to the data which is stored in the default
|
|
441
|
-
// segment
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
let allKeys = [];
|
|
448
|
-
for (let i = 0, len = applicableChanges.length; i < len; i++) {
|
|
449
|
-
const change = applicableChanges[i];
|
|
450
|
-
allKeys.push(...change.ids);
|
|
451
|
-
}
|
|
452
|
-
const keysLength = allKeys.length;
|
|
453
|
-
if (keysLength === 0) {
|
|
454
|
-
// if no keys changed then no need to broadcast
|
|
455
|
-
return;
|
|
456
|
-
}
|
|
457
|
-
for (let i = 0; i < keysLength; i++) {
|
|
458
|
-
const key = allKeys[i];
|
|
459
|
-
const canonical = environment.storeGetCanonicalKey(key);
|
|
460
|
-
if (canonical !== key) {
|
|
461
|
-
continue;
|
|
450
|
+
// segment or the adapter context
|
|
451
|
+
if (change.segment === DefaultDurableSegment) {
|
|
452
|
+
defaultSegmentKeys.push(...change.ids);
|
|
453
|
+
}
|
|
454
|
+
else if (change.segment === AdapterContextSegment) {
|
|
455
|
+
adapterContextSegmentKeys.push(...change.ids);
|
|
462
456
|
}
|
|
463
|
-
// TODO: W-8909393 If expiration is the only thing that changed we should not evict the data... so
|
|
464
|
-
// if we stored expiration and data at different keys (or same keys in different segments)
|
|
465
|
-
// then we could know if only the expiration has changed and we wouldn't need to evict
|
|
466
|
-
// and go through an entire broadcast/revive cycle for unchanged data
|
|
467
|
-
// call base environment storeEvict so this evict is not tracked for durable deletion
|
|
468
|
-
environment.storeEvict(key);
|
|
469
457
|
}
|
|
470
|
-
|
|
458
|
+
// process adapter context changes
|
|
459
|
+
const adapterContextKeysFromDifferentInstance = [];
|
|
460
|
+
for (const key of adapterContextSegmentKeys) {
|
|
461
|
+
if (pendingContextStoreKeys.has(key)) {
|
|
462
|
+
// if this instance caused the L2 write then remove from the
|
|
463
|
+
// "pending" Set and move on
|
|
464
|
+
pendingContextStoreKeys.delete(key);
|
|
465
|
+
}
|
|
466
|
+
else {
|
|
467
|
+
// else it came from another luvio instance and we need to
|
|
468
|
+
// read from L2
|
|
469
|
+
adapterContextKeysFromDifferentInstance.push(key);
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
if (adapterContextKeysFromDifferentInstance.length > 0) {
|
|
473
|
+
// change handlers are sync, so kick off L2 read of the changed
|
|
474
|
+
// segment keys but we can't await it
|
|
475
|
+
durableStore
|
|
476
|
+
.getEntries(adapterContextKeysFromDifferentInstance, AdapterContextSegment)
|
|
477
|
+
.then((entries) => {
|
|
478
|
+
if (entries !== undefined) {
|
|
479
|
+
const entryKeys = keys(entries);
|
|
480
|
+
for (let i = 0, len = entryKeys.length; i < len; i++) {
|
|
481
|
+
const entryKey = entryKeys[i];
|
|
482
|
+
const entry = entries[entryKey];
|
|
483
|
+
contextStores[entryKey] = entry.data;
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
})
|
|
487
|
+
.catch(durableStoreErrorHandler);
|
|
488
|
+
}
|
|
489
|
+
// process default segment changes
|
|
490
|
+
const defaultSegmentKeysLength = defaultSegmentKeys.length;
|
|
491
|
+
if (defaultSegmentKeysLength > 0) {
|
|
492
|
+
for (let i = 0; i < defaultSegmentKeysLength; i++) {
|
|
493
|
+
const key = defaultSegmentKeys[i];
|
|
494
|
+
const canonical = environment.storeGetCanonicalKey(key);
|
|
495
|
+
if (canonical !== key) {
|
|
496
|
+
continue;
|
|
497
|
+
}
|
|
498
|
+
// TODO: W-8909393 If expiration is the only thing that changed we should not evict the data... so
|
|
499
|
+
// if we stored expiration and data at different keys (or same keys in different segments)
|
|
500
|
+
// then we could know if only the expiration has changed and we wouldn't need to evict
|
|
501
|
+
// and go through an entire broadcast/revive cycle for unchanged data
|
|
502
|
+
// call base environment storeEvict so this evict is not tracked for durable deletion
|
|
503
|
+
environment.storeEvict(key);
|
|
504
|
+
}
|
|
505
|
+
environment.storeBroadcast(rebuildSnapshot, environment.snapshotAvailable);
|
|
506
|
+
}
|
|
471
507
|
});
|
|
472
508
|
const dispose = function () {
|
|
473
509
|
validateNotDisposed();
|
|
@@ -583,7 +619,7 @@ function makeDurable(environment, { durableStore, instrumentation }) {
|
|
|
583
619
|
validateNotDisposed();
|
|
584
620
|
const { contextId, onContextLoaded } = options;
|
|
585
621
|
let context = undefined;
|
|
586
|
-
const contextAsPromise = reviveOrCreateContext(`${contextId}${ADAPTER_CONTEXT_ID_SUFFIX}`, durableStore, durableStoreErrorHandler, onContextLoaded);
|
|
622
|
+
const contextAsPromise = reviveOrCreateContext(`${contextId}${ADAPTER_CONTEXT_ID_SUFFIX}`, durableStore, durableStoreErrorHandler, contextStores, pendingContextStoreKeys, onContextLoaded);
|
|
587
623
|
return (config, requestContext) => {
|
|
588
624
|
if (context === undefined) {
|
|
589
625
|
return contextAsPromise.then((revivedContext) => {
|
|
@@ -369,18 +369,19 @@
|
|
|
369
369
|
|
|
370
370
|
const AdapterContextSegment = 'ADAPTER-CONTEXT';
|
|
371
371
|
const ADAPTER_CONTEXT_ID_SUFFIX = '__NAMED_CONTEXT';
|
|
372
|
-
function reviveOrCreateContext(adapterId, durableStore, durableStoreErrorHandler, onContextLoaded) {
|
|
372
|
+
async function reviveOrCreateContext(adapterId, durableStore, durableStoreErrorHandler, contextStores, pendingContextStoreKeys, onContextLoaded) {
|
|
373
373
|
// initialize empty context store
|
|
374
|
-
|
|
374
|
+
contextStores[adapterId] = create(null);
|
|
375
375
|
const context = {
|
|
376
376
|
set(key, value) {
|
|
377
|
-
|
|
377
|
+
contextStores[adapterId][key] = value;
|
|
378
378
|
durableStore.setEntries({
|
|
379
|
-
[adapterId]: { data:
|
|
379
|
+
[adapterId]: { data: contextStores[adapterId] },
|
|
380
380
|
}, AdapterContextSegment);
|
|
381
|
+
pendingContextStoreKeys.add(adapterId);
|
|
381
382
|
},
|
|
382
383
|
get(key) {
|
|
383
|
-
return
|
|
384
|
+
return contextStores[adapterId][key];
|
|
384
385
|
},
|
|
385
386
|
};
|
|
386
387
|
const contextReturn = () => {
|
|
@@ -391,17 +392,17 @@
|
|
|
391
392
|
}
|
|
392
393
|
return context;
|
|
393
394
|
};
|
|
394
|
-
|
|
395
|
-
|
|
395
|
+
try {
|
|
396
|
+
const entries = await durableStore.getEntries([adapterId], AdapterContextSegment);
|
|
396
397
|
if (entries !== undefined && entries[adapterId] !== undefined) {
|
|
397
|
-
|
|
398
|
+
// if durable store has a saved context then load it in the store
|
|
399
|
+
contextStores[adapterId] = entries[adapterId].data;
|
|
398
400
|
}
|
|
399
|
-
|
|
400
|
-
|
|
401
|
+
}
|
|
402
|
+
catch (error) {
|
|
401
403
|
durableStoreErrorHandler(error);
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
});
|
|
404
|
+
}
|
|
405
|
+
return contextReturn();
|
|
405
406
|
}
|
|
406
407
|
function isUnfulfilledSnapshot(cachedSnapshotResult) {
|
|
407
408
|
if (cachedSnapshotResult === undefined) {
|
|
@@ -424,6 +425,11 @@
|
|
|
424
425
|
let ingestStagingStore = null;
|
|
425
426
|
const durableTTLStore = new DurableTTLStore(durableStore);
|
|
426
427
|
const mergeKeysPromiseMap = new Map();
|
|
428
|
+
// When a context store is mutated we write it to L2, which causes DS on change
|
|
429
|
+
// event. If this instance of makeDurable caused that L2 write we can ignore that
|
|
430
|
+
// on change event. This Set helps us do that.
|
|
431
|
+
const pendingContextStoreKeys = new Set();
|
|
432
|
+
const contextStores = create(null);
|
|
427
433
|
let initializationPromise = new Promise((resolve) => {
|
|
428
434
|
const finish = () => {
|
|
429
435
|
resolve();
|
|
@@ -440,38 +446,68 @@
|
|
|
440
446
|
}
|
|
441
447
|
};
|
|
442
448
|
const unsubscribe = durableStore.registerOnChangedListener((changes) => {
|
|
443
|
-
const
|
|
449
|
+
const defaultSegmentKeys = [];
|
|
450
|
+
const adapterContextSegmentKeys = [];
|
|
451
|
+
for (let i = 0, len = changes.length; i < len; i++) {
|
|
452
|
+
const change = changes[i];
|
|
444
453
|
// we only care about changes to the data which is stored in the default
|
|
445
|
-
// segment
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
let allKeys = [];
|
|
452
|
-
for (let i = 0, len = applicableChanges.length; i < len; i++) {
|
|
453
|
-
const change = applicableChanges[i];
|
|
454
|
-
allKeys.push(...change.ids);
|
|
455
|
-
}
|
|
456
|
-
const keysLength = allKeys.length;
|
|
457
|
-
if (keysLength === 0) {
|
|
458
|
-
// if no keys changed then no need to broadcast
|
|
459
|
-
return;
|
|
460
|
-
}
|
|
461
|
-
for (let i = 0; i < keysLength; i++) {
|
|
462
|
-
const key = allKeys[i];
|
|
463
|
-
const canonical = environment.storeGetCanonicalKey(key);
|
|
464
|
-
if (canonical !== key) {
|
|
465
|
-
continue;
|
|
454
|
+
// segment or the adapter context
|
|
455
|
+
if (change.segment === DefaultDurableSegment) {
|
|
456
|
+
defaultSegmentKeys.push(...change.ids);
|
|
457
|
+
}
|
|
458
|
+
else if (change.segment === AdapterContextSegment) {
|
|
459
|
+
adapterContextSegmentKeys.push(...change.ids);
|
|
466
460
|
}
|
|
467
|
-
// TODO: W-8909393 If expiration is the only thing that changed we should not evict the data... so
|
|
468
|
-
// if we stored expiration and data at different keys (or same keys in different segments)
|
|
469
|
-
// then we could know if only the expiration has changed and we wouldn't need to evict
|
|
470
|
-
// and go through an entire broadcast/revive cycle for unchanged data
|
|
471
|
-
// call base environment storeEvict so this evict is not tracked for durable deletion
|
|
472
|
-
environment.storeEvict(key);
|
|
473
461
|
}
|
|
474
|
-
|
|
462
|
+
// process adapter context changes
|
|
463
|
+
const adapterContextKeysFromDifferentInstance = [];
|
|
464
|
+
for (const key of adapterContextSegmentKeys) {
|
|
465
|
+
if (pendingContextStoreKeys.has(key)) {
|
|
466
|
+
// if this instance caused the L2 write then remove from the
|
|
467
|
+
// "pending" Set and move on
|
|
468
|
+
pendingContextStoreKeys.delete(key);
|
|
469
|
+
}
|
|
470
|
+
else {
|
|
471
|
+
// else it came from another luvio instance and we need to
|
|
472
|
+
// read from L2
|
|
473
|
+
adapterContextKeysFromDifferentInstance.push(key);
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
if (adapterContextKeysFromDifferentInstance.length > 0) {
|
|
477
|
+
// change handlers are sync, so kick off L2 read of the changed
|
|
478
|
+
// segment keys but we can't await it
|
|
479
|
+
durableStore
|
|
480
|
+
.getEntries(adapterContextKeysFromDifferentInstance, AdapterContextSegment)
|
|
481
|
+
.then((entries) => {
|
|
482
|
+
if (entries !== undefined) {
|
|
483
|
+
const entryKeys = keys(entries);
|
|
484
|
+
for (let i = 0, len = entryKeys.length; i < len; i++) {
|
|
485
|
+
const entryKey = entryKeys[i];
|
|
486
|
+
const entry = entries[entryKey];
|
|
487
|
+
contextStores[entryKey] = entry.data;
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
})
|
|
491
|
+
.catch(durableStoreErrorHandler);
|
|
492
|
+
}
|
|
493
|
+
// process default segment changes
|
|
494
|
+
const defaultSegmentKeysLength = defaultSegmentKeys.length;
|
|
495
|
+
if (defaultSegmentKeysLength > 0) {
|
|
496
|
+
for (let i = 0; i < defaultSegmentKeysLength; i++) {
|
|
497
|
+
const key = defaultSegmentKeys[i];
|
|
498
|
+
const canonical = environment.storeGetCanonicalKey(key);
|
|
499
|
+
if (canonical !== key) {
|
|
500
|
+
continue;
|
|
501
|
+
}
|
|
502
|
+
// TODO: W-8909393 If expiration is the only thing that changed we should not evict the data... so
|
|
503
|
+
// if we stored expiration and data at different keys (or same keys in different segments)
|
|
504
|
+
// then we could know if only the expiration has changed and we wouldn't need to evict
|
|
505
|
+
// and go through an entire broadcast/revive cycle for unchanged data
|
|
506
|
+
// call base environment storeEvict so this evict is not tracked for durable deletion
|
|
507
|
+
environment.storeEvict(key);
|
|
508
|
+
}
|
|
509
|
+
environment.storeBroadcast(rebuildSnapshot, environment.snapshotAvailable);
|
|
510
|
+
}
|
|
475
511
|
});
|
|
476
512
|
const dispose = function () {
|
|
477
513
|
validateNotDisposed();
|
|
@@ -587,7 +623,7 @@
|
|
|
587
623
|
validateNotDisposed();
|
|
588
624
|
const { contextId, onContextLoaded } = options;
|
|
589
625
|
let context = undefined;
|
|
590
|
-
const contextAsPromise = reviveOrCreateContext(`${contextId}${ADAPTER_CONTEXT_ID_SUFFIX}`, durableStore, durableStoreErrorHandler, onContextLoaded);
|
|
626
|
+
const contextAsPromise = reviveOrCreateContext(`${contextId}${ADAPTER_CONTEXT_ID_SUFFIX}`, durableStore, durableStoreErrorHandler, contextStores, pendingContextStoreKeys, onContextLoaded);
|
|
591
627
|
return (config, requestContext) => {
|
|
592
628
|
if (context === undefined) {
|
|
593
629
|
return contextAsPromise.then((revivedContext) => {
|
|
@@ -460,39 +460,53 @@
|
|
|
460
460
|
|
|
461
461
|
var AdapterContextSegment = 'ADAPTER-CONTEXT';
|
|
462
462
|
var ADAPTER_CONTEXT_ID_SUFFIX = '__NAMED_CONTEXT';
|
|
463
|
-
function reviveOrCreateContext(adapterId, durableStore, durableStoreErrorHandler, onContextLoaded) {
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
463
|
+
function reviveOrCreateContext(adapterId, durableStore, durableStoreErrorHandler, contextStores, pendingContextStoreKeys, onContextLoaded) {
|
|
464
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
465
|
+
var context, contextReturn, entries, error_1;
|
|
466
|
+
return __generator(this, function (_a) {
|
|
467
|
+
switch (_a.label) {
|
|
468
|
+
case 0:
|
|
469
|
+
// initialize empty context store
|
|
470
|
+
contextStores[adapterId] = create(null);
|
|
471
|
+
context = {
|
|
472
|
+
set: function (key, value) {
|
|
473
|
+
var _a;
|
|
474
|
+
contextStores[adapterId][key] = value;
|
|
475
|
+
durableStore.setEntries((_a = {},
|
|
476
|
+
_a[adapterId] = { data: contextStores[adapterId] },
|
|
477
|
+
_a), AdapterContextSegment);
|
|
478
|
+
pendingContextStoreKeys.add(adapterId);
|
|
479
|
+
},
|
|
480
|
+
get: function (key) {
|
|
481
|
+
return contextStores[adapterId][key];
|
|
482
|
+
},
|
|
483
|
+
};
|
|
484
|
+
contextReturn = function () {
|
|
485
|
+
if (onContextLoaded !== undefined) {
|
|
486
|
+
return onContextLoaded(context).then(function () {
|
|
487
|
+
return context;
|
|
488
|
+
});
|
|
489
|
+
}
|
|
490
|
+
return context;
|
|
491
|
+
};
|
|
492
|
+
_a.label = 1;
|
|
493
|
+
case 1:
|
|
494
|
+
_a.trys.push([1, 3, , 4]);
|
|
495
|
+
return [4 /*yield*/, durableStore.getEntries([adapterId], AdapterContextSegment)];
|
|
496
|
+
case 2:
|
|
497
|
+
entries = _a.sent();
|
|
498
|
+
if (entries !== undefined && entries[adapterId] !== undefined) {
|
|
499
|
+
// if durable store has a saved context then load it in the store
|
|
500
|
+
contextStores[adapterId] = entries[adapterId].data;
|
|
501
|
+
}
|
|
502
|
+
return [3 /*break*/, 4];
|
|
503
|
+
case 3:
|
|
504
|
+
error_1 = _a.sent();
|
|
505
|
+
durableStoreErrorHandler(error_1);
|
|
506
|
+
return [3 /*break*/, 4];
|
|
507
|
+
case 4: return [2 /*return*/, contextReturn()];
|
|
508
|
+
}
|
|
509
|
+
});
|
|
496
510
|
});
|
|
497
511
|
}
|
|
498
512
|
function isUnfulfilledSnapshot(cachedSnapshotResult) {
|
|
@@ -517,6 +531,11 @@
|
|
|
517
531
|
var ingestStagingStore = null;
|
|
518
532
|
var durableTTLStore = new DurableTTLStore(durableStore);
|
|
519
533
|
var mergeKeysPromiseMap = new Map();
|
|
534
|
+
// When a context store is mutated we write it to L2, which causes DS on change
|
|
535
|
+
// event. If this instance of makeDurable caused that L2 write we can ignore that
|
|
536
|
+
// on change event. This Set helps us do that.
|
|
537
|
+
var pendingContextStoreKeys = new Set();
|
|
538
|
+
var contextStores = create(null);
|
|
520
539
|
var initializationPromise = new Promise(function (resolve) {
|
|
521
540
|
var finish = function () {
|
|
522
541
|
resolve();
|
|
@@ -533,38 +552,69 @@
|
|
|
533
552
|
}
|
|
534
553
|
};
|
|
535
554
|
var unsubscribe = durableStore.registerOnChangedListener(function (changes) {
|
|
536
|
-
var
|
|
555
|
+
var defaultSegmentKeys = [];
|
|
556
|
+
var adapterContextSegmentKeys = [];
|
|
557
|
+
for (var i = 0, len = changes.length; i < len; i++) {
|
|
558
|
+
var change = changes[i];
|
|
537
559
|
// we only care about changes to the data which is stored in the default
|
|
538
|
-
// segment
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
var allKeys = [];
|
|
545
|
-
for (var i = 0, len = applicableChanges.length; i < len; i++) {
|
|
546
|
-
var change = applicableChanges[i];
|
|
547
|
-
allKeys.push.apply(allKeys, change.ids);
|
|
548
|
-
}
|
|
549
|
-
var keysLength = allKeys.length;
|
|
550
|
-
if (keysLength === 0) {
|
|
551
|
-
// if no keys changed then no need to broadcast
|
|
552
|
-
return;
|
|
553
|
-
}
|
|
554
|
-
for (var i = 0; i < keysLength; i++) {
|
|
555
|
-
var key = allKeys[i];
|
|
556
|
-
var canonical = environment.storeGetCanonicalKey(key);
|
|
557
|
-
if (canonical !== key) {
|
|
558
|
-
continue;
|
|
560
|
+
// segment or the adapter context
|
|
561
|
+
if (change.segment === DefaultDurableSegment) {
|
|
562
|
+
defaultSegmentKeys.push.apply(defaultSegmentKeys, change.ids);
|
|
563
|
+
}
|
|
564
|
+
else if (change.segment === AdapterContextSegment) {
|
|
565
|
+
adapterContextSegmentKeys.push.apply(adapterContextSegmentKeys, change.ids);
|
|
559
566
|
}
|
|
560
|
-
// TODO: W-8909393 If expiration is the only thing that changed we should not evict the data... so
|
|
561
|
-
// if we stored expiration and data at different keys (or same keys in different segments)
|
|
562
|
-
// then we could know if only the expiration has changed and we wouldn't need to evict
|
|
563
|
-
// and go through an entire broadcast/revive cycle for unchanged data
|
|
564
|
-
// call base environment storeEvict so this evict is not tracked for durable deletion
|
|
565
|
-
environment.storeEvict(key);
|
|
566
567
|
}
|
|
567
|
-
|
|
568
|
+
// process adapter context changes
|
|
569
|
+
var adapterContextKeysFromDifferentInstance = [];
|
|
570
|
+
for (var _i = 0, adapterContextSegmentKeys_1 = adapterContextSegmentKeys; _i < adapterContextSegmentKeys_1.length; _i++) {
|
|
571
|
+
var key = adapterContextSegmentKeys_1[_i];
|
|
572
|
+
if (pendingContextStoreKeys.has(key)) {
|
|
573
|
+
// if this instance caused the L2 write then remove from the
|
|
574
|
+
// "pending" Set and move on
|
|
575
|
+
pendingContextStoreKeys.delete(key);
|
|
576
|
+
}
|
|
577
|
+
else {
|
|
578
|
+
// else it came from another luvio instance and we need to
|
|
579
|
+
// read from L2
|
|
580
|
+
adapterContextKeysFromDifferentInstance.push(key);
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
if (adapterContextKeysFromDifferentInstance.length > 0) {
|
|
584
|
+
// change handlers are sync, so kick off L2 read of the changed
|
|
585
|
+
// segment keys but we can't await it
|
|
586
|
+
durableStore
|
|
587
|
+
.getEntries(adapterContextKeysFromDifferentInstance, AdapterContextSegment)
|
|
588
|
+
.then(function (entries) {
|
|
589
|
+
if (entries !== undefined) {
|
|
590
|
+
var entryKeys = keys(entries);
|
|
591
|
+
for (var i = 0, len = entryKeys.length; i < len; i++) {
|
|
592
|
+
var entryKey = entryKeys[i];
|
|
593
|
+
var entry = entries[entryKey];
|
|
594
|
+
contextStores[entryKey] = entry.data;
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
})
|
|
598
|
+
.catch(durableStoreErrorHandler);
|
|
599
|
+
}
|
|
600
|
+
// process default segment changes
|
|
601
|
+
var defaultSegmentKeysLength = defaultSegmentKeys.length;
|
|
602
|
+
if (defaultSegmentKeysLength > 0) {
|
|
603
|
+
for (var i = 0; i < defaultSegmentKeysLength; i++) {
|
|
604
|
+
var key = defaultSegmentKeys[i];
|
|
605
|
+
var canonical = environment.storeGetCanonicalKey(key);
|
|
606
|
+
if (canonical !== key) {
|
|
607
|
+
continue;
|
|
608
|
+
}
|
|
609
|
+
// TODO: W-8909393 If expiration is the only thing that changed we should not evict the data... so
|
|
610
|
+
// if we stored expiration and data at different keys (or same keys in different segments)
|
|
611
|
+
// then we could know if only the expiration has changed and we wouldn't need to evict
|
|
612
|
+
// and go through an entire broadcast/revive cycle for unchanged data
|
|
613
|
+
// call base environment storeEvict so this evict is not tracked for durable deletion
|
|
614
|
+
environment.storeEvict(key);
|
|
615
|
+
}
|
|
616
|
+
environment.storeBroadcast(rebuildSnapshot, environment.snapshotAvailable);
|
|
617
|
+
}
|
|
568
618
|
});
|
|
569
619
|
var dispose = function () {
|
|
570
620
|
validateNotDisposed();
|
|
@@ -678,7 +728,7 @@
|
|
|
678
728
|
validateNotDisposed();
|
|
679
729
|
var contextId = options.contextId, onContextLoaded = options.onContextLoaded;
|
|
680
730
|
var context = undefined;
|
|
681
|
-
var contextAsPromise = reviveOrCreateContext("".concat(contextId).concat(ADAPTER_CONTEXT_ID_SUFFIX), durableStore, durableStoreErrorHandler, onContextLoaded);
|
|
731
|
+
var contextAsPromise = reviveOrCreateContext("".concat(contextId).concat(ADAPTER_CONTEXT_ID_SUFFIX), durableStore, durableStoreErrorHandler, contextStores, pendingContextStoreKeys, onContextLoaded);
|
|
682
732
|
return function (config, requestContext) {
|
|
683
733
|
if (context === undefined) {
|
|
684
734
|
return contextAsPromise.then(function (revivedContext) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@luvio/environments",
|
|
3
|
-
"version": "0.109.
|
|
3
|
+
"version": "0.109.1",
|
|
4
4
|
"description": "Luvio Environments",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"watch": "yarn build --watch"
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@luvio/engine": "0.109.
|
|
26
|
+
"@luvio/engine": "0.109.1"
|
|
27
27
|
},
|
|
28
28
|
"bundlesize": [
|
|
29
29
|
{
|