import type { CacheSpec, SpecForId } from "../../types/00_CacheSpec.js"; import type { StoreGetManyResult } from "../../types/06_Store.js"; import { type AnyParams, type AnyValidators, type Entry, type NormalizedParams, type Store, type StoreEntryInput, type StoreGetManyRequest } from "../../types/index.js"; /** * This class implements an in-memory store for cache entries. For details on * each method, see the interface. * * Note that this class is implemented to make get() fast, at the expense of * making store() slower, under the assumption that reads from the cache happen * much more often than new data is stored (which should be the case). */ export default class MemoryStore implements Store { #private; /** * This map stores metadata about each distinct `ResourceId` (i.e., primary * cache key) that's stored. Specifically... * * - When an incoming request comes in, we have to find entries that match on * both the primary cache key (the `ResourceId`) and the secondary cache key * (the `VariantKey`). However, to match on the latter, we can't compute all * possible variant keys for the request, so, instead, we need to store * which sets of `varyKeys` we've seen for producer results for this * `ResourceId`. That's what `varyKeysSets` holds. This is consulted on each * request. See note on {@link requestVariantKeyForVaryKeys} for details. * * - When all stored entries for a given ResourceId have been evicted/expired, * we want to reclaim a bit of memory (by deleting the whole map entry for * that `ResourceId`, so we use `entryVariantKeys` to track how many entries * we're still storing for this `ResourceId`. * * - Similarly, during cache invalidation, we want to be able to delete all * the stored entries for a given `ResourceId`, so we use `entryVariantKeys` * to be able to find all of those. */ private readonly resourceMetadataMap; /** * Meanwhile, this map wholes the actual cached entries, keyed by their full * cache key. We use an ExpiringEntryMap to efficiently support time- and * size-based expiration of entries. It stores the `ResourceId` in addition to * the entry solely so that, on expiration, we can decrement the entry count * for that resource id without having to parse the cache key. */ private readonly entriesMap; private readonly fallbackDeleteAfter; /** * @param opts.numItemsLimit If set, the store will limit the number of items * it maintains by evicting least recently used items. Note that, while this * caps the amount of memory the store will use, it also adds marginal * overhead to every lookup, as the store must record that the looked up * item is now the most recently accessed. * * @param opts.fallbackDeleteAfter When an item is stored, the caller (usually * the Cache class) tells the store how long to retain the item for, based * on how long it's likely to be useful for satisfying future requests. * However, sometimes, the cache will tell the store that an entry can be * stored forever. This usually happens if the producer doesn't limit the * item's `maxStale`, in which case the data is potentially usable forever, * as consumers can request arbitarily data using the maxStale directive. * However, storing this sort of data forever is impractical in terms of * memory usage. So, the fallbackDeleteAfter setting controls the TTL that * should apply in these cases. Like all times in this caching setup, this * is in seconds. * * @param opts.onItemEviction A callback that's called whenever an item is * removed from the store -- whether because it expired or because it was * evicted to make room for a new item under the `numItemsLimit` setting. */ constructor(opts?: { numItemsLimit?: number; fallbackDeleteAfter?: number; onItemEviction?: (entry: Entry) => void; }); private onItemEviction; get(id: Id, normalizedParams: NormalizedParams): Promise, Validators, Params>[]>; getMany[]>(requests: Reqs): Promise>; store(entriesWithTimes: readonly StoreEntryInput[]): Promise; private storeOne; delete(id: Spec["id"]): Promise; close(): Promise; [Symbol.asyncDispose](): Promise; } //# sourceMappingURL=MemoryStore.d.ts.map