UNPKG

@struktoai/mirage-core

Version:

A Unified Virtual Filesystem For AI Agents

98 lines • 4.78 kB
import type { ByteSource } from '../io/types.ts'; import { type CapacityResult, type PathSpec } from '../types.ts'; /** The bytes at a path, a directory's included; 0 for none. */ export type SizeOf = (path: PathSpec) => Promise<number>; /** The bytes the whole store holds. */ export type CountAll = () => Promise<number>; /** * One store's capacity and the bytes counted against it. * * `used` is null until the store is counted. `pending` holds bytes a stream * or an awaiting write admitted and has not landed yet. `active` holds the * writes in flight. Every method but `counted` is * synchronous, so a check and the change it guards run as one step on the * one thread, which is what makes parallel writers safe without a lock. Two * writes in flight on overlapping paths (a file and its folder) can both * measure the same bytes, so they lose the credit for the bytes they replace * and mark the count for a recount, which waits until no write is in flight. The count lives in this object: another * process, or another VFS on the same disk folder, Redis prefix or OPFS * directory, counts on its own, so together they can pass the limit. * Mirrors Python's `StorageUsage`. */ export declare class StorageUsage { readonly limit: number; used: number | null; pending: number; readonly active: Charge[]; dirty: boolean; private counting; constructor(limit: number, used?: number | null); /** Count the store when it is uncounted, or marked for a recount and no * write is in flight; parallel callers wait on one count. */ counted(count: CountAll): Promise<void>; private count; /** Count the store again once no write is in flight, as bytes written * past mirage (a native program on a disk folder) went uncounted. */ stale(): void; /** Mark a write in flight; one overlapping another in flight takes both * off their credit and marks the count for a recount. */ enter(held: Charge): void; /** Mark a write done. */ leave(held: Charge): void; /** Throw `edquot(path)` when positive growth would pass the limit; * reaching it exactly passes. */ admit(path: PathSpec, growth: number): void; /** Admit `size` and keep it in `pending` until it lands. */ hold(path: PathSpec, size: number): void; /** Take `held` out of `pending` and add the measured `delta`. */ land(held: number, delta: number): void; /** df's QUOTA row: total is the limit, available never below 0. */ report(): CapacityResult; } /** * A backend's usage for its `capacity` setting; null for no cap. `used` is * the bytes it starts with when the backend knows them, as an empty RAM * store does. Mirrors Python's `storage_usage`. * * @throws VFSConfigError when the setting is not a size. */ export declare function storageUsage(name: string, capacity: number | string | null | undefined, used?: number | null): StorageUsage | null; /** * What one write reserves against a counted store, and the bytes it held so * far; inert for an uncapped store. A replacement is credited with the bytes * it replaces until another write overlaps it (`contended`), as that write * may move those bytes elsewhere. Mirrors Python's `Charge`. */ export declare class Charge { readonly usage: StorageUsage | null; readonly path: PathSpec; before: number; held: number; written: number; contended: boolean; constructor(usage: StorageUsage | null, path: PathSpec, before?: number); /** Reserve `size` more bytes, or throw EDQUOT. */ hold(size: number): void; /** The length the operand may reach within what this charge holds and is * credited with. */ get reserved(): number; /** Reserve what growing the operand to `size` bytes adds past what this * charge already holds. */ growTo(size: number): void; /** `data`, each chunk reserved as the writer takes it. With `append` * false, a replacement reserves only what passes the bytes it replaces. */ stream(data: ByteSource, append?: boolean): ByteSource; private take; private held_; } /** * Reserve before a write's bytes go and land what it really changed. The * reservation is checked and taken in one synchronous step, so parallel * writers can never pass the store's capacity together. After the write, * however it ended, the operand is measured again and the change lands; one * that overlapped another in flight marks the count for a recount. An * uncapped store gets an inert charge and measures nothing. Mirrors Python's * `charge`. */ export declare function charge<T>(usage: StorageUsage | null, path: PathSpec, sizeOf: SizeOf, count: CountAll, write: (held: Charge) => Promise<T>): Promise<T>; //# sourceMappingURL=capacity.d.ts.map