@zenfs/core 1.2.2 → 1.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/backends/store/simple.d.ts +3 -0
- package/dist/backends/store/simple.js +6 -0
- package/dist/backends/store/store.d.ts +16 -6
- package/dist/backends/store/store.js +7 -1
- package/dist/config.d.ts +2 -2
- package/dist/config.js +1 -1
- package/dist/emulation/config.d.ts +1 -1
- package/dist/emulation/config.js +1 -1
- package/dist/file.js +6 -6
- package/dist/mixins/async.js +17 -3
- package/package.json +1 -1
- package/src/backends/store/simple.ts +9 -0
- package/src/backends/store/store.ts +23 -6
- package/src/config.ts +3 -3
- package/src/emulation/config.ts +1 -1
- package/src/file.ts +6 -4
- package/src/mixins/async.ts +22 -3
|
@@ -4,6 +4,7 @@ import { SyncTransaction, type Store } from './store.js';
|
|
|
4
4
|
* An interface for simple synchronous stores that don't have special support for transactions and such.
|
|
5
5
|
*/
|
|
6
6
|
export interface SimpleSyncStore extends Store {
|
|
7
|
+
keys(): Iterable<Ino>;
|
|
7
8
|
get(ino: Ino): Uint8Array | undefined;
|
|
8
9
|
set(ino: Ino, data: Uint8Array): void;
|
|
9
10
|
delete(ino: Ino): void;
|
|
@@ -17,6 +18,7 @@ export declare abstract class SimpleAsyncStore implements SimpleSyncStore {
|
|
|
17
18
|
protected cache: Map<Ino, Uint8Array>;
|
|
18
19
|
protected queue: Set<Promise<unknown>>;
|
|
19
20
|
protected abstract entries(): Promise<Iterable<[Ino, Uint8Array]>>;
|
|
21
|
+
keys(): Iterable<Ino>;
|
|
20
22
|
get(ino: Ino): Uint8Array | undefined;
|
|
21
23
|
set(ino: Ino, data: Uint8Array): void;
|
|
22
24
|
protected abstract _set(ino: Ino, data: Uint8Array): Promise<void>;
|
|
@@ -43,6 +45,7 @@ export declare class SimpleTransaction extends SyncTransaction<SimpleSyncStore>
|
|
|
43
45
|
*/
|
|
44
46
|
protected modifiedKeys: Set<Ino>;
|
|
45
47
|
protected store: SimpleSyncStore;
|
|
48
|
+
keysSync(): Iterable<Ino>;
|
|
46
49
|
getSync(ino: Ino): Uint8Array;
|
|
47
50
|
setSync(ino: Ino, data: Uint8Array): void;
|
|
48
51
|
removeSync(ino: Ino): void;
|
|
@@ -8,6 +8,9 @@ export class SimpleAsyncStore {
|
|
|
8
8
|
this.cache = new Map();
|
|
9
9
|
this.queue = new Set();
|
|
10
10
|
}
|
|
11
|
+
keys() {
|
|
12
|
+
return this.cache.keys();
|
|
13
|
+
}
|
|
11
14
|
get(ino) {
|
|
12
15
|
return this.cache.get(ino);
|
|
13
16
|
}
|
|
@@ -55,6 +58,9 @@ export class SimpleTransaction extends SyncTransaction {
|
|
|
55
58
|
*/
|
|
56
59
|
this.modifiedKeys = new Set();
|
|
57
60
|
}
|
|
61
|
+
keysSync() {
|
|
62
|
+
return this.store.keys();
|
|
63
|
+
}
|
|
58
64
|
getSync(ino) {
|
|
59
65
|
const val = this.store.get(ino);
|
|
60
66
|
this.stashOldValue(ino, val);
|
|
@@ -32,9 +32,17 @@ export declare abstract class Transaction<T extends Store = Store> {
|
|
|
32
32
|
protected store: T;
|
|
33
33
|
constructor(store: T);
|
|
34
34
|
/**
|
|
35
|
-
* Whether the transaction was
|
|
35
|
+
* Whether the transaction was committed or aborted
|
|
36
36
|
*/
|
|
37
37
|
protected done: boolean;
|
|
38
|
+
/**
|
|
39
|
+
* Gets all of the keys
|
|
40
|
+
*/
|
|
41
|
+
abstract keys(): Promise<Iterable<Ino>>;
|
|
42
|
+
/**
|
|
43
|
+
* Gets all of the keys
|
|
44
|
+
*/
|
|
45
|
+
abstract keysSync(): Iterable<Ino>;
|
|
38
46
|
/**
|
|
39
47
|
* Retrieves the data at `ino`.
|
|
40
48
|
* @param ino The key to look under for data.
|
|
@@ -92,6 +100,7 @@ export declare abstract class Transaction<T extends Store = Store> {
|
|
|
92
100
|
* Transaction that implements asynchronous operations with synchronous ones
|
|
93
101
|
*/
|
|
94
102
|
export declare abstract class SyncTransaction<T extends Store = Store> extends Transaction<T> {
|
|
103
|
+
keys(): Promise<Iterable<Ino>>;
|
|
95
104
|
get(ino: Ino): Promise<Uint8Array>;
|
|
96
105
|
set(ino: bigint, data: Uint8Array): Promise<void>;
|
|
97
106
|
remove(ino: Ino): Promise<void>;
|
|
@@ -102,9 +111,10 @@ export declare abstract class SyncTransaction<T extends Store = Store> extends T
|
|
|
102
111
|
* Transaction that only supports asynchronous operations
|
|
103
112
|
*/
|
|
104
113
|
export declare abstract class AsyncTransaction<T extends Store = Store> extends Transaction<T> {
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
114
|
+
keysSync(): never;
|
|
115
|
+
getSync(): never;
|
|
116
|
+
setSync(): never;
|
|
117
|
+
removeSync(): never;
|
|
118
|
+
commitSync(): never;
|
|
119
|
+
abortSync(): never;
|
|
110
120
|
}
|
|
@@ -7,7 +7,7 @@ export class Transaction {
|
|
|
7
7
|
constructor(store) {
|
|
8
8
|
this.store = store;
|
|
9
9
|
/**
|
|
10
|
-
* Whether the transaction was
|
|
10
|
+
* Whether the transaction was committed or aborted
|
|
11
11
|
*/
|
|
12
12
|
this.done = false;
|
|
13
13
|
}
|
|
@@ -29,6 +29,9 @@ export class Transaction {
|
|
|
29
29
|
*/
|
|
30
30
|
export class SyncTransaction extends Transaction {
|
|
31
31
|
/* eslint-disable @typescript-eslint/require-await */
|
|
32
|
+
async keys() {
|
|
33
|
+
return this.keysSync();
|
|
34
|
+
}
|
|
32
35
|
async get(ino) {
|
|
33
36
|
return this.getSync(ino);
|
|
34
37
|
}
|
|
@@ -49,6 +52,9 @@ export class SyncTransaction extends Transaction {
|
|
|
49
52
|
* Transaction that only supports asynchronous operations
|
|
50
53
|
*/
|
|
51
54
|
export class AsyncTransaction extends Transaction {
|
|
55
|
+
keysSync() {
|
|
56
|
+
throw ErrnoError.With('ENOSYS', undefined, 'AsyncTransaction.keysSync');
|
|
57
|
+
}
|
|
52
58
|
getSync() {
|
|
53
59
|
throw ErrnoError.With('ENOSYS', undefined, 'AsyncTransaction.getSync');
|
|
54
60
|
}
|
package/dist/config.d.ts
CHANGED
|
@@ -54,13 +54,13 @@ export interface Configuration<T extends ConfigMounts> extends SharedConfig {
|
|
|
54
54
|
*/
|
|
55
55
|
disableAccessChecks: boolean;
|
|
56
56
|
/**
|
|
57
|
-
* If true, disables `read` and `readSync` from
|
|
57
|
+
* If true, disables `read` and `readSync` from updating the atime.
|
|
58
58
|
*
|
|
59
59
|
* This can increase performance.
|
|
60
60
|
* @experimental
|
|
61
61
|
* @default false
|
|
62
62
|
*/
|
|
63
|
-
|
|
63
|
+
disableUpdateOnRead: boolean;
|
|
64
64
|
}
|
|
65
65
|
/**
|
|
66
66
|
* Configures ZenFS with single mount point /
|
package/dist/config.js
CHANGED
|
@@ -70,7 +70,7 @@ export async function configure(configuration) {
|
|
|
70
70
|
Object.assign(credentials, { uid, gid, suid: uid, sgid: gid, euid: uid, egid: gid });
|
|
71
71
|
cache.setEnabled(configuration.cacheStats ?? false);
|
|
72
72
|
config.checkAccess = !configuration.disableAccessChecks;
|
|
73
|
-
config.
|
|
73
|
+
config.updateOnRead = !configuration.disableUpdateOnRead;
|
|
74
74
|
if (configuration.addDevices) {
|
|
75
75
|
const devfs = new DeviceFS();
|
|
76
76
|
devfs.createDevice('/null', nullDevice);
|
package/dist/emulation/config.js
CHANGED
package/dist/file.js
CHANGED
|
@@ -358,13 +358,15 @@ export class PreloadFile extends File {
|
|
|
358
358
|
if (!isReadable(this.flag)) {
|
|
359
359
|
throw new ErrnoError(Errno.EPERM, 'File not opened with a readable mode.');
|
|
360
360
|
}
|
|
361
|
-
|
|
361
|
+
if (config.updateOnRead) {
|
|
362
|
+
this.dirty = true;
|
|
363
|
+
this.stats.atimeMs = Date.now();
|
|
364
|
+
}
|
|
362
365
|
position ?? (position = this.position);
|
|
363
366
|
let end = position + length;
|
|
364
367
|
if (end > this.stats.size) {
|
|
365
368
|
end = position + Math.max(this.stats.size - position, 0);
|
|
366
369
|
}
|
|
367
|
-
this.stats.atimeMs = Date.now();
|
|
368
370
|
this._position = end;
|
|
369
371
|
const bytesRead = end - position;
|
|
370
372
|
if (bytesRead == 0) {
|
|
@@ -384,8 +386,7 @@ export class PreloadFile extends File {
|
|
|
384
386
|
*/
|
|
385
387
|
async read(buffer, offset, length, position) {
|
|
386
388
|
const bytesRead = this._read(buffer, offset, length, position);
|
|
387
|
-
|
|
388
|
-
await this.sync();
|
|
389
|
+
await this.sync();
|
|
389
390
|
return { bytesRead, buffer };
|
|
390
391
|
}
|
|
391
392
|
/**
|
|
@@ -399,8 +400,7 @@ export class PreloadFile extends File {
|
|
|
399
400
|
*/
|
|
400
401
|
readSync(buffer, offset, length, position) {
|
|
401
402
|
const bytesRead = this._read(buffer, offset, length, position);
|
|
402
|
-
|
|
403
|
-
this.syncSync();
|
|
403
|
+
this.syncSync();
|
|
404
404
|
return bytesRead;
|
|
405
405
|
}
|
|
406
406
|
async chmod(mode) {
|
package/dist/mixins/async.js
CHANGED
|
@@ -45,6 +45,7 @@ var __disposeResources = (this && this.__disposeResources) || (function (Suppres
|
|
|
45
45
|
var e = new Error(message);
|
|
46
46
|
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
47
47
|
});
|
|
48
|
+
import { StoreFS } from '../backends/store/fs.js';
|
|
48
49
|
import { join } from '../emulation/path.js';
|
|
49
50
|
import { Errno, ErrnoError } from '../error.js';
|
|
50
51
|
import { parseFlag, PreloadFile } from '../file.js';
|
|
@@ -84,6 +85,18 @@ export function Async(FS) {
|
|
|
84
85
|
}
|
|
85
86
|
this.checkSync();
|
|
86
87
|
await this._sync.ready();
|
|
88
|
+
// optimization: for 2 storeFS', we copy at a lower abstraction level.
|
|
89
|
+
if (this._sync instanceof StoreFS && this instanceof StoreFS) {
|
|
90
|
+
const sync = this._sync['store'].transaction();
|
|
91
|
+
const async = this['store'].transaction();
|
|
92
|
+
const promises = [];
|
|
93
|
+
for (const key of sync.keysSync()) {
|
|
94
|
+
promises.push(async.set(key, sync.getSync(key)));
|
|
95
|
+
}
|
|
96
|
+
await Promise.all(promises);
|
|
97
|
+
this._isInitialized = true;
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
87
100
|
try {
|
|
88
101
|
await this.crossCopy('/');
|
|
89
102
|
this._isInitialized = true;
|
|
@@ -187,10 +200,11 @@ export function Async(FS) {
|
|
|
187
200
|
const stats = await this.stat(path);
|
|
188
201
|
this._sync.mkdirSync(path, stats.mode);
|
|
189
202
|
}
|
|
190
|
-
const
|
|
191
|
-
for (const file of
|
|
192
|
-
|
|
203
|
+
const promises = [];
|
|
204
|
+
for (const file of await this.readdir(path)) {
|
|
205
|
+
promises.push(this.crossCopy(join(path, file)));
|
|
193
206
|
}
|
|
207
|
+
await Promise.all(promises);
|
|
194
208
|
}
|
|
195
209
|
/**
|
|
196
210
|
* @internal
|
package/package.json
CHANGED
|
@@ -5,6 +5,7 @@ import { SyncTransaction, type Store } from './store.js';
|
|
|
5
5
|
* An interface for simple synchronous stores that don't have special support for transactions and such.
|
|
6
6
|
*/
|
|
7
7
|
export interface SimpleSyncStore extends Store {
|
|
8
|
+
keys(): Iterable<Ino>;
|
|
8
9
|
get(ino: Ino): Uint8Array | undefined;
|
|
9
10
|
set(ino: Ino, data: Uint8Array): void;
|
|
10
11
|
delete(ino: Ino): void;
|
|
@@ -23,6 +24,10 @@ export abstract class SimpleAsyncStore implements SimpleSyncStore {
|
|
|
23
24
|
|
|
24
25
|
protected abstract entries(): Promise<Iterable<[Ino, Uint8Array]>>;
|
|
25
26
|
|
|
27
|
+
public keys(): Iterable<Ino> {
|
|
28
|
+
return this.cache.keys();
|
|
29
|
+
}
|
|
30
|
+
|
|
26
31
|
public get(ino: Ino): Uint8Array | undefined {
|
|
27
32
|
return this.cache.get(ino);
|
|
28
33
|
}
|
|
@@ -82,6 +87,10 @@ export class SimpleTransaction extends SyncTransaction<SimpleSyncStore> {
|
|
|
82
87
|
|
|
83
88
|
protected declare store: SimpleSyncStore;
|
|
84
89
|
|
|
90
|
+
public keysSync(): Iterable<Ino> {
|
|
91
|
+
return this.store.keys();
|
|
92
|
+
}
|
|
93
|
+
|
|
85
94
|
public getSync(ino: Ino): Uint8Array {
|
|
86
95
|
const val = this.store.get(ino);
|
|
87
96
|
this.stashOldValue(ino, val);
|
|
@@ -39,10 +39,20 @@ export abstract class Transaction<T extends Store = Store> {
|
|
|
39
39
|
public constructor(protected store: T) {}
|
|
40
40
|
|
|
41
41
|
/**
|
|
42
|
-
* Whether the transaction was
|
|
42
|
+
* Whether the transaction was committed or aborted
|
|
43
43
|
*/
|
|
44
44
|
protected done: boolean = false;
|
|
45
45
|
|
|
46
|
+
/**
|
|
47
|
+
* Gets all of the keys
|
|
48
|
+
*/
|
|
49
|
+
public abstract keys(): Promise<Iterable<Ino>>;
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Gets all of the keys
|
|
53
|
+
*/
|
|
54
|
+
public abstract keysSync(): Iterable<Ino>;
|
|
55
|
+
|
|
46
56
|
/**
|
|
47
57
|
* Retrieves the data at `ino`.
|
|
48
58
|
* @param ino The key to look under for data.
|
|
@@ -125,6 +135,9 @@ export abstract class Transaction<T extends Store = Store> {
|
|
|
125
135
|
*/
|
|
126
136
|
export abstract class SyncTransaction<T extends Store = Store> extends Transaction<T> {
|
|
127
137
|
/* eslint-disable @typescript-eslint/require-await */
|
|
138
|
+
public async keys(): Promise<Iterable<Ino>> {
|
|
139
|
+
return this.keysSync();
|
|
140
|
+
}
|
|
128
141
|
public async get(ino: Ino): Promise<Uint8Array> {
|
|
129
142
|
return this.getSync(ino);
|
|
130
143
|
}
|
|
@@ -151,23 +164,27 @@ export abstract class SyncTransaction<T extends Store = Store> extends Transacti
|
|
|
151
164
|
* Transaction that only supports asynchronous operations
|
|
152
165
|
*/
|
|
153
166
|
export abstract class AsyncTransaction<T extends Store = Store> extends Transaction<T> {
|
|
154
|
-
public
|
|
167
|
+
public keysSync(): never {
|
|
168
|
+
throw ErrnoError.With('ENOSYS', undefined, 'AsyncTransaction.keysSync');
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
public getSync(): never {
|
|
155
172
|
throw ErrnoError.With('ENOSYS', undefined, 'AsyncTransaction.getSync');
|
|
156
173
|
}
|
|
157
174
|
|
|
158
|
-
public setSync():
|
|
175
|
+
public setSync(): never {
|
|
159
176
|
throw ErrnoError.With('ENOSYS', undefined, 'AsyncTransaction.setSync');
|
|
160
177
|
}
|
|
161
178
|
|
|
162
|
-
public removeSync():
|
|
179
|
+
public removeSync(): never {
|
|
163
180
|
throw ErrnoError.With('ENOSYS', undefined, 'AsyncTransaction.removeSync');
|
|
164
181
|
}
|
|
165
182
|
|
|
166
|
-
public commitSync():
|
|
183
|
+
public commitSync(): never {
|
|
167
184
|
throw ErrnoError.With('ENOSYS', undefined, 'AsyncTransaction.commitSync');
|
|
168
185
|
}
|
|
169
186
|
|
|
170
|
-
public abortSync():
|
|
187
|
+
public abortSync(): never {
|
|
171
188
|
throw ErrnoError.With('ENOSYS', undefined, 'AsyncTransaction.abortSync');
|
|
172
189
|
}
|
|
173
190
|
}
|
package/src/config.ts
CHANGED
|
@@ -119,13 +119,13 @@ export interface Configuration<T extends ConfigMounts> extends SharedConfig {
|
|
|
119
119
|
disableAccessChecks: boolean;
|
|
120
120
|
|
|
121
121
|
/**
|
|
122
|
-
* If true, disables `read` and `readSync` from
|
|
122
|
+
* If true, disables `read` and `readSync` from updating the atime.
|
|
123
123
|
*
|
|
124
124
|
* This can increase performance.
|
|
125
125
|
* @experimental
|
|
126
126
|
* @default false
|
|
127
127
|
*/
|
|
128
|
-
|
|
128
|
+
disableUpdateOnRead: boolean;
|
|
129
129
|
}
|
|
130
130
|
|
|
131
131
|
/**
|
|
@@ -153,7 +153,7 @@ export async function configure<T extends ConfigMounts>(configuration: Partial<C
|
|
|
153
153
|
|
|
154
154
|
cache.setEnabled(configuration.cacheStats ?? false);
|
|
155
155
|
config.checkAccess = !configuration.disableAccessChecks;
|
|
156
|
-
config.
|
|
156
|
+
config.updateOnRead = !configuration.disableUpdateOnRead;
|
|
157
157
|
|
|
158
158
|
if (configuration.addDevices) {
|
|
159
159
|
const devfs = new DeviceFS();
|
package/src/emulation/config.ts
CHANGED
package/src/file.ts
CHANGED
|
@@ -515,13 +515,15 @@ export class PreloadFile<FS extends FileSystem> extends File {
|
|
|
515
515
|
if (!isReadable(this.flag)) {
|
|
516
516
|
throw new ErrnoError(Errno.EPERM, 'File not opened with a readable mode.');
|
|
517
517
|
}
|
|
518
|
-
|
|
518
|
+
if (config.updateOnRead) {
|
|
519
|
+
this.dirty = true;
|
|
520
|
+
this.stats.atimeMs = Date.now();
|
|
521
|
+
}
|
|
519
522
|
position ??= this.position;
|
|
520
523
|
let end = position + length;
|
|
521
524
|
if (end > this.stats.size) {
|
|
522
525
|
end = position + Math.max(this.stats.size - position, 0);
|
|
523
526
|
}
|
|
524
|
-
this.stats.atimeMs = Date.now();
|
|
525
527
|
this._position = end;
|
|
526
528
|
const bytesRead = end - position;
|
|
527
529
|
if (bytesRead == 0) {
|
|
@@ -542,7 +544,7 @@ export class PreloadFile<FS extends FileSystem> extends File {
|
|
|
542
544
|
*/
|
|
543
545
|
public async read<TBuffer extends ArrayBufferView>(buffer: TBuffer, offset?: number, length?: number, position?: number): Promise<{ bytesRead: number; buffer: TBuffer }> {
|
|
544
546
|
const bytesRead = this._read(buffer, offset, length, position);
|
|
545
|
-
|
|
547
|
+
await this.sync();
|
|
546
548
|
return { bytesRead, buffer };
|
|
547
549
|
}
|
|
548
550
|
|
|
@@ -557,7 +559,7 @@ export class PreloadFile<FS extends FileSystem> extends File {
|
|
|
557
559
|
*/
|
|
558
560
|
public readSync(buffer: ArrayBufferView, offset?: number, length?: number, position?: number): number {
|
|
559
561
|
const bytesRead = this._read(buffer, offset, length, position);
|
|
560
|
-
|
|
562
|
+
this.syncSync();
|
|
561
563
|
return bytesRead;
|
|
562
564
|
}
|
|
563
565
|
|
package/src/mixins/async.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { StoreFS } from '../backends/store/fs.js';
|
|
2
|
+
import type { Store } from '../backends/store/store.js';
|
|
1
3
|
import { join } from '../emulation/path.js';
|
|
2
4
|
import { Errno, ErrnoError } from '../error.js';
|
|
3
5
|
import { parseFlag, PreloadFile, type File } from '../file.js';
|
|
@@ -72,6 +74,22 @@ export function Async<T extends typeof FileSystem>(
|
|
|
72
74
|
|
|
73
75
|
await this._sync.ready();
|
|
74
76
|
|
|
77
|
+
// optimization: for 2 storeFS', we copy at a lower abstraction level.
|
|
78
|
+
if (this._sync instanceof StoreFS && this instanceof StoreFS) {
|
|
79
|
+
const sync = (this._sync as StoreFS<Store>)['store'].transaction();
|
|
80
|
+
const async = (this as StoreFS<Store>)['store'].transaction();
|
|
81
|
+
|
|
82
|
+
const promises = [];
|
|
83
|
+
for (const key of sync.keysSync()) {
|
|
84
|
+
promises.push(async.set(key, sync.getSync(key)));
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
await Promise.all(promises);
|
|
88
|
+
|
|
89
|
+
this._isInitialized = true;
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
|
|
75
93
|
try {
|
|
76
94
|
await this.crossCopy('/');
|
|
77
95
|
this._isInitialized = true;
|
|
@@ -175,10 +193,11 @@ export function Async<T extends typeof FileSystem>(
|
|
|
175
193
|
const stats = await this.stat(path);
|
|
176
194
|
this._sync.mkdirSync(path, stats.mode);
|
|
177
195
|
}
|
|
178
|
-
const
|
|
179
|
-
for (const file of
|
|
180
|
-
|
|
196
|
+
const promises = [];
|
|
197
|
+
for (const file of await this.readdir(path)) {
|
|
198
|
+
promises.push(this.crossCopy(join(path, file)));
|
|
181
199
|
}
|
|
200
|
+
await Promise.all(promises);
|
|
182
201
|
}
|
|
183
202
|
|
|
184
203
|
/**
|