@zenfs/core 0.9.3 → 0.9.5

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.
@@ -3,6 +3,18 @@ import { PreloadFile } from '../file.js';
3
3
  import { FileSystem, type FileSystemMetadata } from '../filesystem.js';
4
4
  import { type Ino } from '../inode.js';
5
5
  import { type Stats } from '../stats.js';
6
+ /**
7
+ * Last Recently Used cache
8
+ */
9
+ declare class LRUCache<K, V> {
10
+ readonly limit: number;
11
+ private cache;
12
+ constructor(limit: number);
13
+ set(key: K, value: V): void;
14
+ get(key: K): V | null;
15
+ remove(key: K): void;
16
+ reset(): void;
17
+ }
6
18
  /**
7
19
  * Represents an asynchronous key-value store.
8
20
  */
@@ -68,6 +80,7 @@ export interface AsyncStoreOptions {
68
80
  }
69
81
  declare const AsyncStoreFS_base: (abstract new (...args: any[]) => {
70
82
  _sync: FileSystem;
83
+ queueDone(): Promise<void>;
71
84
  metadata(): FileSystemMetadata;
72
85
  ready(): Promise<any>;
73
86
  renameSync(oldPath: string, newPath: string, cred: Cred): void;
@@ -101,7 +114,8 @@ declare const AsyncStoreFS_base: (abstract new (...args: any[]) => {
101
114
  export declare class AsyncStoreFS extends AsyncStoreFS_base {
102
115
  protected _options: AsyncStoreOptions;
103
116
  protected store: AsyncStore;
104
- private _cache?;
117
+ protected _cache?: LRUCache<string, Ino>;
118
+ private _initialized;
105
119
  _sync: FileSystem;
106
120
  ready(): Promise<this>;
107
121
  metadata(): FileSystemMetadata;
@@ -52,6 +52,10 @@ class LRUCache {
52
52
  */
53
53
  export class AsyncStoreFS extends Async(FileSystem) {
54
54
  async ready() {
55
+ if (this._initialized) {
56
+ return this;
57
+ }
58
+ this._initialized = true;
55
59
  if (this._options.lruCacheSize > 0) {
56
60
  this._cache = new LRUCache(this._options.lruCacheSize);
57
61
  }
@@ -70,6 +74,7 @@ export class AsyncStoreFS extends Async(FileSystem) {
70
74
  constructor(_options) {
71
75
  super();
72
76
  this._options = _options;
77
+ this._initialized = false;
73
78
  }
74
79
  /**
75
80
  * Delete all contents stored in the file system.
@@ -79,13 +84,14 @@ export class AsyncStoreFS extends Async(FileSystem) {
79
84
  this._cache.reset();
80
85
  }
81
86
  await this.store.clear();
82
- // INVARIANT: Root always exists.
87
+ // Root always exists.
83
88
  await this.makeRootDirectory();
84
89
  }
85
90
  /**
86
91
  * @todo Make rename compatible with the cache.
87
92
  */
88
93
  async rename(oldPath, newPath, cred) {
94
+ await this.queueDone();
89
95
  const c = this._cache;
90
96
  if (this._cache) {
91
97
  // Clear and disable cache during renaming process.
@@ -160,6 +166,7 @@ export class AsyncStoreFS extends Async(FileSystem) {
160
166
  }
161
167
  }
162
168
  async stat(p, cred) {
169
+ await this.queueDone();
163
170
  const tx = this.store.beginTransaction();
164
171
  const inode = await this.findINode(tx, p);
165
172
  if (!inode) {
@@ -172,11 +179,13 @@ export class AsyncStoreFS extends Async(FileSystem) {
172
179
  return stats;
173
180
  }
174
181
  async createFile(p, flag, mode, cred) {
182
+ await this.queueDone();
175
183
  const tx = this.store.beginTransaction(), data = new Uint8Array(0), newFile = await this.commitNewFile(tx, p, FileType.FILE, mode, cred, data);
176
184
  // Open the file.
177
185
  return new PreloadFile(this, p, flag, newFile.toStats(), data);
178
186
  }
179
187
  async openFile(p, flag, cred) {
188
+ await this.queueDone();
180
189
  const tx = this.store.beginTransaction(), node = await this.findINode(tx, p), data = await tx.get(node.ino);
181
190
  if (!node.toStats().hasAccess(flagToMode(flag), cred)) {
182
191
  throw ApiError.With('EACCES', p, 'openFile');
@@ -187,9 +196,11 @@ export class AsyncStoreFS extends Async(FileSystem) {
187
196
  return new PreloadFile(this, p, flag, node.toStats(), data);
188
197
  }
189
198
  async unlink(p, cred) {
199
+ await this.queueDone();
190
200
  return this.removeEntry(p, false, cred);
191
201
  }
192
202
  async rmdir(p, cred) {
203
+ await this.queueDone();
193
204
  // Check first if directory is empty.
194
205
  const list = await this.readdir(p, cred);
195
206
  if (list.length > 0) {
@@ -198,10 +209,12 @@ export class AsyncStoreFS extends Async(FileSystem) {
198
209
  await this.removeEntry(p, true, cred);
199
210
  }
200
211
  async mkdir(p, mode, cred) {
212
+ await this.queueDone();
201
213
  const tx = this.store.beginTransaction(), data = encode('{}');
202
214
  await this.commitNewFile(tx, p, FileType.DIRECTORY, mode, cred, data);
203
215
  }
204
216
  async readdir(p, cred) {
217
+ await this.queueDone();
205
218
  const tx = this.store.beginTransaction();
206
219
  const node = await this.findINode(tx, p);
207
220
  if (!node.toStats().hasAccess(R_OK, cred)) {
@@ -214,6 +227,7 @@ export class AsyncStoreFS extends Async(FileSystem) {
214
227
  * @todo Ensure mtime updates properly, and use that to determine if a data update is required.
215
228
  */
216
229
  async sync(p, data, stats) {
230
+ await this.queueDone();
217
231
  const tx = this.store.beginTransaction(),
218
232
  // We use the _findInode helper because we actually need the INode id.
219
233
  fileInodeId = await this._findINode(tx, dirname(p), basename(p)), fileInode = await this.getINode(tx, fileInodeId, p), inodeChanged = fileInode.update(stats);
@@ -232,6 +246,7 @@ export class AsyncStoreFS extends Async(FileSystem) {
232
246
  await tx.commit();
233
247
  }
234
248
  async link(existing, newpath, cred) {
249
+ await this.queueDone();
235
250
  const tx = this.store.beginTransaction(), existingDir = dirname(existing), existingDirNode = await this.findINode(tx, existingDir);
236
251
  if (!existingDirNode.toStats().hasAccess(R_OK, cred)) {
237
252
  throw ApiError.With('EACCES', existingDir, 'link');
@@ -262,14 +277,13 @@ export class AsyncStoreFS extends Async(FileSystem) {
262
277
  */
263
278
  async makeRootDirectory() {
264
279
  const tx = this.store.beginTransaction();
265
- if ((await tx.get(rootIno)) === undefined) {
280
+ if (!(await tx.get(rootIno))) {
266
281
  // Create new inode. o777, owned by root:root
267
- const dirInode = new Inode();
268
- dirInode.mode = 0o777 | FileType.DIRECTORY;
269
- // If the root doesn't exist, the first random ID shouldn't exist,
270
- // either.
271
- await tx.put(dirInode.ino, encode('{}'), false);
272
- await tx.put(rootIno, dirInode.data, false);
282
+ const inode = new Inode();
283
+ inode.mode = 0o777 | FileType.DIRECTORY;
284
+ // If the root doesn't exist, the first random ID shouldn't exist either.
285
+ await tx.put(inode.ino, encode('{}'), false);
286
+ await tx.put(rootIno, inode.data, false);
273
287
  await tx.commit();
274
288
  }
275
289
  }
@@ -173,6 +173,9 @@ declare const IndexFS_base: (abstract new (...args: any[]) => {
173
173
  stat(path: string, cred: Cred): Promise<Stats>;
174
174
  statSync(path: string, cred: Cred): Stats;
175
175
  openFile(path: string, flag: string, cred: Cred): Promise<import("../file.js").File>;
176
+ /**
177
+ * Constructs a new FileIndex.
178
+ */
176
179
  openFileSync(path: string, flag: string, cred: Cred): import("../file.js").File;
177
180
  readdir(path: string, cred: Cred): Promise<string[]>;
178
181
  readdirSync(path: string, cred: Cred): string[];