@luvio/environments 0.142.4 → 0.143.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.
@@ -18,6 +18,7 @@ function isDeprecatedDurableStoreEntry(durableRecord) {
18
18
  return false;
19
19
  }
20
20
  const DefaultDurableSegment = 'DEFAULT';
21
+ const RedirectDurableSegment = 'REDIRECT_KEYS';
21
22
 
22
23
  const { keys, create, assign, freeze } = Object;
23
24
 
@@ -261,7 +262,7 @@ class DurableTTLStore {
261
262
  }
262
263
  }
263
264
 
264
- function flushInMemoryStoreValuesToDurableStore(store, durableStore, durableStoreErrorHandler, additionalDurableStoreOperations = []) {
265
+ function flushInMemoryStoreValuesToDurableStore(store, durableStore, durableStoreErrorHandler, redirects, additionalDurableStoreOperations = []) {
265
266
  const durableRecords = create(null);
266
267
  const evictedRecords = create(null);
267
268
  const { records, metadata: storeMetadata, visitedIds, refreshedIds, } = store.fallbackStringKeyInMemoryStore;
@@ -298,6 +299,18 @@ function flushInMemoryStoreValuesToDurableStore(store, durableStore, durableStor
298
299
  segment: DefaultDurableSegment,
299
300
  });
300
301
  }
302
+ // redirects
303
+ redirects.forEach((value, key) => {
304
+ durableStoreOperations.push({
305
+ type: 'setEntries',
306
+ entries: {
307
+ [key]: {
308
+ data: { key, redirect: value },
309
+ },
310
+ },
311
+ segment: RedirectDurableSegment,
312
+ });
313
+ });
301
314
  // evicts
302
315
  const evictedKeys = keys(evictedRecords);
303
316
  if (evictedKeys.length > 0) {
@@ -346,6 +359,19 @@ function buildIngestStagingStore(environment) {
346
359
  return environment.storeBuildIngestionStagingStore();
347
360
  }
348
361
 
362
+ async function reviveRedirects(durableStore, env) {
363
+ const entries = await durableStore.getAllEntries(RedirectDurableSegment);
364
+ if (entries) {
365
+ for (const durableEntry of Object.keys(entries)) {
366
+ const entry = entries[durableEntry];
367
+ const { data: { key, redirect }, } = entry;
368
+ if (entry) {
369
+ env.storeRedirect(key, redirect);
370
+ }
371
+ }
372
+ }
373
+ }
374
+
349
375
  const AdapterContextSegment = 'ADAPTER-CONTEXT';
350
376
  const ADAPTER_CONTEXT_ID_SUFFIX = '__NAMED_CONTEXT';
351
377
  async function reviveOrCreateContext(adapterId, durableStore, durableStoreErrorHandler, contextStores, pendingContextStoreKeys, onContextLoaded) {
@@ -409,13 +435,18 @@ function makeDurable(environment, { durableStore, instrumentation }) {
409
435
  // event. If this instance of makeDurable caused that L2 write we can ignore that
410
436
  // on change event. This Set helps us do that.
411
437
  const pendingContextStoreKeys = new Set();
438
+ // redirects that need to be flushed to the durable store
439
+ const pendingStoreRedirects = new Map();
412
440
  const contextStores = create(null);
413
441
  let initializationPromise = new Promise((resolve) => {
414
442
  const finish = () => {
415
443
  resolve();
416
444
  initializationPromise = undefined;
417
445
  };
418
- reviveTTLOverrides(durableTTLStore, environment).then(finish);
446
+ Promise.all([
447
+ reviveTTLOverrides(durableTTLStore, environment),
448
+ reviveRedirects(durableStore, environment),
449
+ ]).then(finish);
419
450
  });
420
451
  //instrumentation for durable store errors
421
452
  const durableStoreErrorHandler = handleDurableStoreRejection(instrumentation);
@@ -428,6 +459,8 @@ function makeDurable(environment, { durableStore, instrumentation }) {
428
459
  const unsubscribe = durableStore.registerOnChangedListener(async (changes) => {
429
460
  const defaultSegmentKeys = [];
430
461
  const adapterContextSegmentKeys = [];
462
+ const redirectSegmentKeys = [];
463
+ let shouldBroadcast = false;
431
464
  for (let i = 0, len = changes.length; i < len; i++) {
432
465
  const change = changes[i];
433
466
  // we only care about changes to the data which is stored in the default
@@ -438,6 +471,20 @@ function makeDurable(environment, { durableStore, instrumentation }) {
438
471
  else if (change.segment === AdapterContextSegment) {
439
472
  adapterContextSegmentKeys.push(...change.ids);
440
473
  }
474
+ else if (change.segment === RedirectDurableSegment) {
475
+ redirectSegmentKeys.push(...change.ids);
476
+ }
477
+ }
478
+ if (redirectSegmentKeys.length > 0) {
479
+ const redirectEntries = await durableStore.getEntries(redirectSegmentKeys, RedirectDurableSegment);
480
+ if (redirectEntries !== undefined) {
481
+ const redirectKeys = Object.keys(redirectEntries);
482
+ for (const key of redirectKeys) {
483
+ const redirectData = redirectEntries[key];
484
+ environment.storeRedirect(redirectData.data.key, redirectData.data.redirect);
485
+ shouldBroadcast = true;
486
+ }
487
+ }
441
488
  }
442
489
  // process adapter context changes
443
490
  const adapterContextKeysFromDifferentInstance = [];
@@ -474,10 +521,6 @@ function makeDurable(environment, { durableStore, instrumentation }) {
474
521
  if (defaultSegmentKeysLength > 0) {
475
522
  for (let i = 0; i < defaultSegmentKeysLength; i++) {
476
523
  const key = defaultSegmentKeys[i];
477
- const canonical = environment.storeGetCanonicalKey(key);
478
- if (canonical !== key) {
479
- continue;
480
- }
481
524
  // TODO: W-8909393 If expiration is the only thing that changed we should not evict the data... so
482
525
  // if we stored expiration and data at different keys (or same keys in different segments)
483
526
  // then we could know if only the expiration has changed and we wouldn't need to evict
@@ -485,6 +528,9 @@ function makeDurable(environment, { durableStore, instrumentation }) {
485
528
  // call base environment storeEvict so this evict is not tracked for durable deletion
486
529
  environment.storeEvict(key);
487
530
  }
531
+ shouldBroadcast = true;
532
+ }
533
+ if (shouldBroadcast) {
488
534
  await environment.storeBroadcast(rebuildSnapshot, environment.snapshotAvailable);
489
535
  }
490
536
  });
@@ -540,7 +586,8 @@ function makeDurable(environment, { durableStore, instrumentation }) {
540
586
  if (ingestStagingStore === null) {
541
587
  return Promise.resolve();
542
588
  }
543
- const promise = flushInMemoryStoreValuesToDurableStore(ingestStagingStore, durableStore, durableStoreErrorHandler, additionalDurableStoreOperations);
589
+ const promise = flushInMemoryStoreValuesToDurableStore(ingestStagingStore, durableStore, durableStoreErrorHandler, new Map(pendingStoreRedirects), additionalDurableStoreOperations);
590
+ pendingStoreRedirects.clear();
544
591
  ingestStagingStore = null;
545
592
  return promise;
546
593
  };
@@ -622,6 +669,7 @@ function makeDurable(environment, { durableStore, instrumentation }) {
622
669
  };
623
670
  const storeRedirect = function (existingKey, canonicalKey) {
624
671
  validateNotDisposed();
672
+ pendingStoreRedirects.set(existingKey, canonicalKey);
625
673
  // call redirect on staging store so "old" keys are removed from L2 on
626
674
  // the next publishChangesToDurableStore. NOTE: we don't need to call
627
675
  // redirect on the base environment store because staging store and base
@@ -42,7 +42,9 @@ export interface DurableStoreEvictOperation extends BaseOperation {
42
42
  }
43
43
  export type DurableStoreOperation<T> = DurableStoreSetOperation<T> | DurableStoreEvictOperation;
44
44
  export type DefaultDurableSegmentName = 'DEFAULT';
45
+ export type RedirectDurableSegmentName = 'REDIRECT_KEYS';
45
46
  export declare const DefaultDurableSegment: DefaultDurableSegmentName;
47
+ export declare const RedirectDurableSegment: RedirectDurableSegmentName;
46
48
  export interface DurableStoreChange {
47
49
  /** The entry IDs of the entries that have changed */
48
50
  ids: string[];
@@ -1,4 +1,4 @@
1
1
  import type { InMemoryStore } from '@luvio/engine';
2
2
  import type { DurableStore, DurableStoreOperation } from '../DurableStore';
3
3
  import type { DurableStoreRejectionHandler } from './error';
4
- export declare function flushInMemoryStoreValuesToDurableStore(store: InMemoryStore, durableStore: DurableStore, durableStoreErrorHandler: DurableStoreRejectionHandler, additionalDurableStoreOperations?: DurableStoreOperation<unknown>[]): Promise<void>;
4
+ export declare function flushInMemoryStoreValuesToDurableStore(store: InMemoryStore, durableStore: DurableStore, durableStoreErrorHandler: DurableStoreRejectionHandler, redirects: Map<string, string>, additionalDurableStoreOperations?: DurableStoreOperation<unknown>[]): Promise<void>;
@@ -0,0 +1,7 @@
1
+ import type { Environment } from '@luvio/engine';
2
+ import type { DurableStore } from '../DurableStore';
3
+ export interface RedirectData {
4
+ key: string;
5
+ redirect: string;
6
+ }
7
+ export declare function reviveRedirects(durableStore: DurableStore, env: Environment): Promise<void>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@luvio/environments",
3
- "version": "0.142.4",
3
+ "version": "0.143.1",
4
4
  "description": "Luvio Environments",
5
5
  "repository": {
6
6
  "type": "git",
@@ -27,7 +27,7 @@
27
27
  "watch": "yarn build --watch"
28
28
  },
29
29
  "dependencies": {
30
- "@luvio/engine": "^0.142.4"
30
+ "@luvio/engine": "^0.143.1"
31
31
  },
32
32
  "volta": {
33
33
  "extends": "../../../package.json"