@pgxsinkit/pgwasm
Version:
296 lines • 10.2 kB
TypeScript
export type InodeId = bigint;
export type ExtentId = bigint;
export type MetadataFile = "a" | "b";
export declare function otherMetadataFile(file: MetadataFile): MetadataFile;
interface BaseInode {
id: InodeId;
mode: number;
atimeMs: bigint;
mtimeMs: bigint;
ctimeMs: bigint;
}
export interface DirectoryInode extends BaseInode {
kind: "directory";
children: Map<string, InodeId>;
}
export interface FileInode extends BaseInode {
kind: "file";
size: bigint;
extents: ExtentId[];
}
/**
* A symbolic link. It owns no extents and no children — the whole entry IS its absolute `target`,
* which path resolution restarts the walk at. See {@link validateSymlinkTarget} for why relative
* targets are refused.
*/
export interface SymlinkInode extends BaseInode {
kind: "symlink";
target: string;
}
export type Inode = DirectoryInode | FileInode | SymlinkInode;
export interface OrphanRecord {
inodeId: InodeId;
mode: number;
atimeMs: bigint;
mtimeMs: bigint;
ctimeMs: bigint;
size: bigint;
extents: ExtentId[];
}
export declare function makeOrphanRecord(inode: FileInode): OrphanRecord;
export declare class IndexedExtentSet {
#private;
get size(): number;
has(extentId: ExtentId): boolean;
add(extentId: ExtentId): void;
delete(extentId: ExtentId): boolean;
values(): readonly ExtentId[];
peekLast(count: number): ExtentId[];
clone(): IndexedExtentSet;
}
export interface AllocatorState {
totalExtents: bigint;
ownedBy: Map<ExtentId, InodeId>;
available: IndexedExtentSet;
quarantine: Map<ExtentId, bigint | null>;
}
export interface VfsState {
generation: bigint;
nextInodeId: bigint;
rootInodeId: bigint;
extentSize: number;
activeMetadataFile: MetadataFile;
retainedGenerations: Record<MetadataFile, bigint | null>;
basePayloadBytes: number;
inodes: Map<InodeId, Inode>;
parentByInode: Map<InodeId, {
parentId: InodeId;
name: string;
}>;
allocator: AllocatorState;
}
export interface CreateDirectoryChoice {
parentId: InodeId;
name: string;
inodeId: InodeId;
mode: number;
atimeMs: bigint;
mtimeMs: bigint;
ctimeMs: bigint;
}
export interface ExtentRun {
start: ExtentId;
count: number;
}
export type TxnRecord = {
kind: "createDirectories";
entries: readonly CreateDirectoryChoice[];
} | {
kind: "createFile";
parentId: InodeId;
name: string;
inodeId: InodeId;
mode: number;
atimeMs: bigint;
mtimeMs: bigint;
ctimeMs: bigint;
size: bigint;
extents: readonly ExtentRun[];
} | {
kind: "removeFile";
parentId: InodeId;
name: string;
parentMtimeMs: bigint;
parentCtimeMs: bigint;
} | {
kind: "changeMode";
inodeId: InodeId;
mode: number;
ctimeMs: bigint;
} | {
kind: "changeTimes";
inodeId: InodeId;
atimeMs: bigint;
mtimeMs: bigint;
ctimeMs: bigint;
} | {
kind: "resizeFile";
operation: "truncate" | "write";
inodeId: InodeId;
size: bigint;
allocated: readonly ExtentRun[];
mtimeMs: bigint;
ctimeMs: bigint;
} | {
kind: "removeDirectory";
parentId: InodeId;
name: string;
parentMtimeMs: bigint;
parentCtimeMs: bigint;
} | {
kind: "rename";
sourceParentId: InodeId;
sourceName: string;
destinationParentId: InodeId;
destinationName: string;
timestampMs: bigint;
} | {
kind: "createSymlink";
parentId: InodeId;
name: string;
inodeId: InodeId;
mode: number;
atimeMs: bigint;
mtimeMs: bigint;
ctimeMs: bigint;
target: string;
} | {
kind: "reserveQuarantine";
extents: readonly ExtentRun[];
};
export interface TxnPlan<RecordType extends TxnRecord = TxnRecord> {
record: RecordType;
}
export interface PreflightLimits {
maxFramePayloadBytes: number;
maxBasePayloadBytes: number;
}
/** The mode a symbolic link carries: `S_IFLNK | 0777`, the only mode POSIX gives a link. */
export declare const SYMLINK_MODE = 41471;
export declare function estimateMetadataBasePayloadBytes(state: VfsState): number;
export declare function estimateTxnPayloadBytes(record: TxnRecord): number;
export declare function preflightTxn(state: VfsState, record: TxnRecord, limits?: PreflightLimits): number;
declare const PREPARED_TXN_PROJECTION: unique symbol;
export interface PreparedTxnProjection {
readonly projectedBasePayloadBytes: number;
readonly state: VfsState;
readonly record: TxnRecord;
readonly [PREPARED_TXN_PROJECTION]: true;
}
/** @internal Bind one projected size to the exact live state and record it preflighted. */
export declare function prepareTxnProjection(state: VfsState, record: TxnRecord): PreparedTxnProjection;
export declare function createInitialState(extentSize: number): VfsState;
export declare function toExtentRuns(extents: readonly ExtentId[]): ExtentRun[];
export declare function expandExtentRuns(runs: readonly ExtentRun[], maximum: number): ExtentId[];
export declare function getInodeAtPath(state: VfsState, path: string): Inode;
/**
* Resolve every symbolic link on `path` and report the link-free absolute path it names.
*
* `follow` governs the FINAL component only — the POSIX `stat`/`lstat` split. Every INTERMEDIATE
* link is always followed, because a path can only continue through the thing a link points at.
*
* A component that does not exist, or one whose parent turned out not to be a directory, stops the
* walk and the remainder is carried through verbatim: resolution answers "which path does this
* name", not "does it exist". The operation that follows reports `ENOENT`/`ENOTDIR` itself, or
* creates the tail — which is exactly what an `open(O_CREAT)` through a symlinked directory needs.
*
* Targets are absolute, so a hop restarts the walk at the root. `MAX_SYMLINK_HOPS` hops is `ELOOP`,
* and each expansion is re-validated by `parsePath`, so a chain that outgrows the store's depth or
* byte limits is rejected here rather than in a planner.
*/
export declare function resolveLinks(state: VfsState, path: string, follow: boolean): string;
export declare function planMkdir(state: VfsState, path: string, options: {
recursive?: boolean;
mode?: number;
nowMs: bigint;
}): TxnPlan<Extract<TxnRecord, {
kind: "createDirectories";
}>>;
export declare function planCreateFile(state: VfsState, path: string, options: {
mode?: number;
nowMs: bigint;
size?: bigint;
}): TxnPlan<Extract<TxnRecord, {
kind: "createFile";
}>>;
/** A symbolic link. Nothing about the TARGET is consulted — the link entry is the whole record. */
export declare function planSymlink(state: VfsState, path: string, target: string, options: {
mode?: number;
nowMs: bigint;
}): TxnPlan<Extract<TxnRecord, {
kind: "createSymlink";
}>>;
/** Removes a FILE or a SYMBOLIC LINK. A link is unlinked as itself; its target is never touched. */
export declare function planUnlink(state: VfsState, path: string, nowMs: bigint): TxnPlan<Extract<TxnRecord, {
kind: "removeFile";
}>>;
export declare function planChmod(state: VfsState, path: string, mode: number, nowMs: bigint): TxnPlan<Extract<TxnRecord, {
kind: "changeMode";
}>>;
export declare function planUtimes(state: VfsState, path: string, atimeMs: bigint, mtimeMs: bigint, ctimeMs: bigint): TxnPlan<Extract<TxnRecord, {
kind: "changeTimes";
}>>;
export declare function planResizeFile(state: VfsState, path: string, size: bigint, nowMs: bigint, operation: "truncate" | "write"): TxnPlan<Extract<TxnRecord, {
kind: "resizeFile";
}>>;
/** @internal Inode-first planner for descriptor operations that already resolved the file. */
export declare function planResizeFileForInode(state: VfsState, inode: FileInode, size: bigint, nowMs: bigint, operation: "truncate" | "write"): TxnPlan<Extract<TxnRecord, {
kind: "resizeFile";
}>>;
export declare function planRmdir(state: VfsState, path: string, nowMs: bigint): TxnPlan<Extract<TxnRecord, {
kind: "removeDirectory";
}>>;
export declare function planRename(state: VfsState, oldPath: string, newPath: string, nowMs: bigint): TxnPlan<Extract<TxnRecord, {
kind: "rename";
}>>;
export declare function planReserveQuarantine(state: VfsState, count: number): TxnPlan<Extract<TxnRecord, {
kind: "reserveQuarantine";
}>>;
export declare function applyTxn(state: VfsState, record: TxnRecord, prepared?: PreparedTxnProjection): void;
export declare function projectRepack(state: VfsState, pinnedQuarantine?: ReadonlySet<ExtentId>): VfsState;
/**
* @internal Activation-only projection. Structures repack never mutates are shared read-only until
* durable activation; allocator and generation structures remain isolated from the live state.
*/
export declare function projectRepackForActivation(state: VfsState, pinnedQuarantine?: ReadonlySet<ExtentId>): VfsState;
export declare function validateState(state: VfsState): void;
export declare function canonicalStateView(state: VfsState): {
generation: bigint;
nextInodeId: bigint;
rootInodeId: bigint;
extentSize: number;
activeMetadataFile: MetadataFile;
retainedGenerations: {
a: bigint | null;
b: bigint | null;
};
basePayloadBytes: number;
inodes: ({
id: InodeId;
mode: number;
atimeMs: bigint;
mtimeMs: bigint;
ctimeMs: bigint;
kind: "directory";
children: [string, bigint][];
} | {
id: InodeId;
mode: number;
atimeMs: bigint;
mtimeMs: bigint;
ctimeMs: bigint;
kind: "file";
size: bigint;
extents: bigint[];
} | {
id: InodeId;
mode: number;
atimeMs: bigint;
mtimeMs: bigint;
ctimeMs: bigint;
kind: "symlink";
target: string;
})[];
parentByInode: [bigint, {
parentId: InodeId;
name: string;
}][];
allocator: {
totalExtents: bigint;
ownedBy: [bigint, bigint][];
available: bigint[];
quarantine: [bigint, bigint | null][];
};
};
export {};
//# sourceMappingURL=state-machine.d.ts.map