export type Stamp = readonly [epoch: number, key: number];
/**
 * The invalidations a cache writer checks before it installs.
 *
 * A writer holds bytes it read earlier; an invalidation that lands between
 * the read and the install makes them stale even though the writer was
 * granted its turn after it. The writer takes a stamp before it waits and
 * compares it before it installs.
 *
 * The RAM store holds a per-key lock only for its in-memory install,
 * never across hashing or backend I/O. A free lock admits its writer
 * without suspending on both hosts; a queued writer checks its stamp
 * after acquiring the lock. Redis holds no client-side key lock: it
 * sends atomic writes to the server and checks after acquiring its
 * client (an await on TypeScript, synchronous on Python). The guard
 * tracks local invalidations, not writes by other Redis clients.
 *
 * Two counters, because invalidations have different reaches. The
 * store-wide epoch answers `clear`. The per-key counter answers a removal
 * of one key and a prefix eviction, so a large fill is not thrown away
 * because an unrelated key or folder was dropped. A prefix eviction can
 * name its victims although a fill in flight has no entry yet: every
 * writer registers here in `enter` before it waits. Per-key counters
 * exist only while a writer for that key is in flight, which bounds the
 * map by concurrent writers, not by every key ever removed.
 */
export declare class Invalidation {
    private epoch;
    private readonly keys;
    private readonly writers;
    /** Register a writer for `key` and take its stamp. */
    enter(key: string): Stamp;
    /** Unregister a writer for `key`; the last one out drops the key's counter. */
    leave(key: string): void;
    /** Whether an invalidation reached `key` since `stamp`. */
    stale(key: string, stamp: Stamp): boolean;
    /** Record a removal of `key` for the writers in flight on it. */
    invalidate(key: string): void;
    /**
     * Record a prefix eviction for the writers in flight under it, matched
     * as the stores match it (`startsWith`), sparing the excluded roots.
     */
    invalidatePrefix(prefix: string, excluded?: readonly string[]): void;
    /** Record an invalidation whose victims cannot be enumerated. */
    invalidateAll(): void;
}
/**
 * Track a fill's keys until it completes, fails or is cancelled.
 *
 * The callback starts without a yield, before any lock/client wait. Call
 * its predicate immediately before each install or retry. Unknown keys
 * are not live, and duplicate keys count as one writer.
 */
export declare function withFillGuard(invalidation: Invalidation, keys: Iterable<string>, fill: (isLive: (key: string) => boolean) => Promise<void>): Promise<void>;
//# sourceMappingURL=invalidation.d.ts.map