Skip to content

Commit

Permalink
Removed internalIno type,
Browse files Browse the repository at this point in the history
Corrected name of data pointers called `ino` to `data`
Fixed key fields being incorrectly named `ino`
Added a proper `ino` field
  • Loading branch information
james-pre committed Nov 12, 2024
1 parent 983d864 commit 3b2fe9e
Show file tree
Hide file tree
Showing 7 changed files with 191 additions and 229 deletions.
3 changes: 1 addition & 2 deletions src/backends/memory.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import type { Ino } from '../inode.js';
import type { Backend } from './backend.js';
import { StoreFS } from './store/fs.js';
import { SimpleTransaction, type SimpleSyncStore } from './store/simple.js';

/**
* A simple in-memory store
*/
export class InMemoryStore extends Map<Ino, Uint8Array> implements SimpleSyncStore {
export class InMemoryStore extends Map<bigint, Uint8Array> implements SimpleSyncStore {
public constructor(public name: string = 'tmp') {
super();
}
Expand Down
245 changes: 112 additions & 133 deletions src/backends/store/fs.ts

Large diffs are not rendered by default.

73 changes: 36 additions & 37 deletions src/backends/store/simple.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import type { Ino } from '../../inode.js';
import { SyncTransaction, type Store } from './store.js';

/**
* An interface for simple synchronous stores that don't have special support for transactions and such.
*/
export interface SimpleSyncStore extends Store {
keys(): Iterable<Ino>;
get(ino: Ino): Uint8Array | undefined;
set(ino: Ino, data: Uint8Array): void;
delete(ino: Ino): void;
keys(): Iterable<bigint>;
get(id: bigint): Uint8Array | undefined;
set(id: bigint, data: Uint8Array): void;
delete(id: bigint): void;
}

/**
Expand All @@ -18,33 +17,33 @@ export interface SimpleSyncStore extends Store {
export abstract class SimpleAsyncStore implements SimpleSyncStore {
public abstract name: string;

protected cache: Map<Ino, Uint8Array> = new Map();
protected cache: Map<bigint, Uint8Array> = new Map();

protected queue: Set<Promise<unknown>> = new Set();

protected abstract entries(): Promise<Iterable<[Ino, Uint8Array]>>;
protected abstract entries(): Promise<Iterable<[bigint, Uint8Array]>>;

public keys(): Iterable<Ino> {
public keys(): Iterable<bigint> {
return this.cache.keys();
}

public get(ino: Ino): Uint8Array | undefined {
return this.cache.get(ino);
public get(id: bigint): Uint8Array | undefined {
return this.cache.get(id);
}

public set(ino: Ino, data: Uint8Array): void {
this.cache.set(ino, data);
this.queue.add(this._set(ino, data));
public set(id: bigint, data: Uint8Array): void {
this.cache.set(id, data);
this.queue.add(this._set(id, data));
}

protected abstract _set(ino: Ino, data: Uint8Array): Promise<void>;
protected abstract _set(ino: bigint, data: Uint8Array): Promise<void>;

public delete(ino: Ino): void {
this.cache.delete(ino);
this.queue.add(this._delete(ino));
public delete(id: bigint): void {
this.cache.delete(id);
this.queue.add(this._delete(id));
}

protected abstract _delete(ino: Ino): Promise<void>;
protected abstract _delete(ino: bigint): Promise<void>;

public clearSync(): void {
this.cache.clear();
Expand Down Expand Up @@ -79,32 +78,32 @@ export class SimpleTransaction extends SyncTransaction<SimpleSyncStore> {
* Stores data in the keys we modify prior to modifying them.
* Allows us to roll back commits.
*/
protected originalData: Map<Ino, Uint8Array | void> = new Map();
protected originalData: Map<bigint, Uint8Array | void> = new Map();
/**
* List of keys modified in this transaction, if any.
*/
protected modifiedKeys: Set<Ino> = new Set();
protected modifiedKeys: Set<bigint> = new Set();

protected declare store: SimpleSyncStore;

public keysSync(): Iterable<Ino> {
public keysSync(): Iterable<bigint> {
return this.store.keys();
}

public getSync(ino: Ino): Uint8Array {
const val = this.store.get(ino);
this.stashOldValue(ino, val);
public getSync(id: bigint): Uint8Array {
const val = this.store.get(id);
this.stashOldValue(id, val);
return val!;
}

public setSync(ino: Ino, data: Uint8Array): void {
this.markModified(ino);
return this.store.set(ino, data);
public setSync(id: bigint, data: Uint8Array): void {
this.markModified(id);
return this.store.set(id, data);
}

public removeSync(ino: Ino): void {
this.markModified(ino);
this.store.delete(ino);
public removeSync(id: bigint): void {
this.markModified(id);
this.store.delete(id);
}

public commitSync(): void {
Expand Down Expand Up @@ -135,21 +134,21 @@ export class SimpleTransaction extends SyncTransaction<SimpleSyncStore> {
* prevent needless `get` requests if the program modifies the data later
* on during the transaction.
*/
protected stashOldValue(ino: Ino, value?: Uint8Array): void {
protected stashOldValue(id: bigint, value?: Uint8Array): void {
// Keep only the earliest value in the transaction.
if (!this.originalData.has(ino)) {
this.originalData.set(ino, value);
if (!this.originalData.has(id)) {
this.originalData.set(id, value);
}
}

/**
* Marks `ino` as modified, and stashes its value if it has not been
* stashed already.
*/
protected markModified(ino: Ino): void {
this.modifiedKeys.add(ino);
if (!this.originalData.has(ino)) {
this.originalData.set(ino, this.store.get(ino));
protected markModified(id: bigint): void {
this.modifiedKeys.add(id);
if (!this.originalData.has(id)) {
this.originalData.set(id, this.store.get(id));
}
}
}
51 changes: 25 additions & 26 deletions src/backends/store/store.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { ErrnoError } from '../../error.js';
import type { Ino } from '../../inode.js';
import '../../polyfills.js';

/**
Expand Down Expand Up @@ -46,52 +45,52 @@ export abstract class Transaction<T extends Store = Store> {
/**
* Gets all of the keys
*/
public abstract keys(): Promise<Iterable<Ino>>;
public abstract keys(): Promise<Iterable<bigint>>;

/**
* Gets all of the keys
*/
public abstract keysSync(): Iterable<Ino>;
public abstract keysSync(): Iterable<bigint>;

/**
* Retrieves the data at `ino`.
* @param ino The key to look under for data.
* Retrieves data.
* @param id The key to look under for data.
*/
public abstract get(ino: Ino): Promise<Uint8Array>;
public abstract get(id: bigint): Promise<Uint8Array>;

/**
* Retrieves the data at `ino`.
* Retrieves data.
* Throws an error if an error occurs or if the key does not exist.
* @param ino The key to look under for data.
* @param id The key to look under for data.
* @return The data stored under the key, or undefined if not present.
*/
public abstract getSync(ino: Ino): Uint8Array;
public abstract getSync(id: bigint): Uint8Array;

/**
* Adds the data to the store under `ino`. Overwrites any existing data.
* @param ino The key to add the data under.
* Adds the data to the store under an id. Overwrites any existing data.
* @param id The key to add the data under.
* @param data The data to add to the store.
*/
public abstract set(ino: Ino, data: Uint8Array): Promise<void>;
public abstract set(id: bigint, data: Uint8Array): Promise<void>;

/**
* Adds the data to the store under `ino`.
* @param ino The key to add the data under.
* Adds the data to the store under and id.
* @param id The key to add the data under.
* @param data The data to add to the store.
*/
public abstract setSync(ino: Ino, data: Uint8Array): void;
public abstract setSync(id: bigint, data: Uint8Array): void;

/**
* Deletes the data at `ino`.
* @param ino The key to delete from the store.
* @param id The key to delete from the store.
*/
public abstract remove(ino: Ino): Promise<void>;
public abstract remove(id: bigint): Promise<void>;

/**
* Deletes the data at `ino`.
* @param ino The key to delete from the store.
* @param id The key to delete from the store.
*/
public abstract removeSync(ino: Ino): void;
public abstract removeSync(id: bigint): void;

/**
* Commits the transaction.
Expand Down Expand Up @@ -135,19 +134,19 @@ export abstract class Transaction<T extends Store = Store> {
*/
export abstract class SyncTransaction<T extends Store = Store> extends Transaction<T> {
/* eslint-disable @typescript-eslint/require-await */
public async keys(): Promise<Iterable<Ino>> {
public async keys(): Promise<Iterable<bigint>> {
return this.keysSync();
}
public async get(ino: Ino): Promise<Uint8Array> {
return this.getSync(ino);
public async get(id: bigint): Promise<Uint8Array> {
return this.getSync(id);
}

public async set(ino: bigint, data: Uint8Array): Promise<void> {
return this.setSync(ino, data);
public async set(id: bigint, data: Uint8Array): Promise<void> {
return this.setSync(id, data);
}

public async remove(ino: Ino): Promise<void> {
return this.removeSync(ino);
public async remove(id: bigint): Promise<void> {
return this.removeSync(id);
}

public async commit(): Promise<void> {
Expand Down
5 changes: 2 additions & 3 deletions src/devices.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import { File } from './file.js';
import type { StatsLike } from './stats.js';
import { Stats } from './stats.js';
import { basename, dirname } from './emulation/path.js';
import type { Ino } from './inode.js';

/**
* A device
Expand All @@ -28,7 +27,7 @@ export interface Device<TData = any> {
/**
* Which inode the device is assigned
*/
ino: Ino;
ino: bigint;

/**
* Data associated with a device.
Expand Down Expand Up @@ -70,7 +69,7 @@ export interface DeviceDriver<TData = any> {
* @returns `Device.data`
* @experimental
*/
init?(ino: Ino): {
init?(ino: bigint): {
data?: TData;
minor?: number;
major?: number;
Expand Down
35 changes: 7 additions & 28 deletions src/inode.ts
Original file line number Diff line number Diff line change
@@ -1,42 +1,19 @@
import { deserialize, serialize, sizeof, struct, types as t } from 'utilium';
import { deserialize, sizeof, struct, types as t } from 'utilium';
import { Stats, type StatsLike } from './stats.js';

/**
* Alias for an ino.
* This will be helpful if in the future inode numbers/IDs are changed to strings or numbers.
*/
export type Ino = bigint;
import { randomBigInt } from './utils.js';

/**
* Room inode
* @hidden
*/
export const rootIno = 0n;

/**
* Generates a random 32 bit integer, then converts to a hex string
*/
function _random() {
return Math.round(Math.random() * 2 ** 32).toString(16);
}

/**
* Generate a random ino
* @internal
*/
export function randomIno(): Ino {
return BigInt('0x' + _random() + _random());
}

/**
* Generic inode definition that can easily be serialized.
* @internal
*/
@struct()
export class Inode implements StatsLike {
public get data(): Uint8Array {
return serialize(this);
}

public constructor(buffer?: ArrayBufferLike | ArrayBufferView) {
if (buffer) {
if (buffer.byteLength < sizeof(Inode)) {
Expand All @@ -48,7 +25,8 @@ export class Inode implements StatsLike {
}

// set defaults on a fresh inode
this.ino = randomIno();
this.ino = randomBigInt();
this.data = randomBigInt();
this.nlink = 1;
this.size = 4096;
const now = Date.now();
Expand All @@ -58,7 +36,7 @@ export class Inode implements StatsLike {
this.birthtimeMs = now;
}

@t.uint64 public ino!: Ino;
@t.uint64 public data!: bigint;
@t.uint32 public size!: number;
@t.uint16 public mode!: number;
@t.uint32 public nlink!: number;
Expand All @@ -68,6 +46,7 @@ export class Inode implements StatsLike {
@t.float64 public birthtimeMs!: number;
@t.float64 public mtimeMs!: number;
@t.float64 public ctimeMs!: number;
@t.uint64 public ino!: bigint;

/**
* Handy function that converts the Inode to a Node Stats object.
Expand Down
8 changes: 8 additions & 0 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -266,3 +266,11 @@ export function normalizeOptions(
}

export type Concrete<T extends ClassLike> = Pick<T, keyof T> & (new (...args: any[]) => InstanceType<T>);

/**
* Generate a random ino
* @internal
*/
export function randomBigInt(): bigint {
return crypto.getRandomValues(new BigUint64Array(1))[0];
}

0 comments on commit 3b2fe9e

Please sign in to comment.