@dxos/random-access-storage 0.1.55-main.ff36828 → 0.1.55
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/lib/browser/index.mjs +194 -56
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node/index.cjs +2 -2
- package/dist/lib/node/meta.json +1 -1
- package/dist/types/src/browser/web-fs.d.ts +4 -2
- package/dist/types/src/browser/web-fs.d.ts.map +1 -1
- package/dist/types/src/monitor.d.ts +41 -0
- package/dist/types/src/monitor.d.ts.map +1 -0
- package/package.json +6 -6
- package/src/browser/web-fs.ts +78 -40
- package/src/monitor.ts +140 -0
|
@@ -55,7 +55,7 @@ var Directory = class {
|
|
|
55
55
|
// packages/common/random-access-storage/src/common/file.ts
|
|
56
56
|
import pify from "pify";
|
|
57
57
|
import { log } from "@dxos/log";
|
|
58
|
-
var __dxlog_file = "/
|
|
58
|
+
var __dxlog_file = "/mnt/ramdisk/work/packages/common/random-access-storage/src/common/file.ts";
|
|
59
59
|
var pifyFields = (object, type, fields) => {
|
|
60
60
|
for (const field of fields) {
|
|
61
61
|
if (!object[field]) {
|
|
@@ -100,7 +100,7 @@ var wrapFile = (native, type) => {
|
|
|
100
100
|
};
|
|
101
101
|
|
|
102
102
|
// packages/common/random-access-storage/src/common/abstract-storage.ts
|
|
103
|
-
var __dxlog_file2 = "/
|
|
103
|
+
var __dxlog_file2 = "/mnt/ramdisk/work/packages/common/random-access-storage/src/common/abstract-storage.ts";
|
|
104
104
|
var AbstractStorage = class {
|
|
105
105
|
// TODO(burdon): Make required.
|
|
106
106
|
constructor(path) {
|
|
@@ -328,6 +328,98 @@ import { callbackify } from "@dxos/node-std/util";
|
|
|
328
328
|
import invariant from "tiny-invariant";
|
|
329
329
|
import { synchronized } from "@dxos/async";
|
|
330
330
|
import { log as log3 } from "@dxos/log";
|
|
331
|
+
|
|
332
|
+
// packages/common/random-access-storage/src/monitor.ts
|
|
333
|
+
import { unrefTimeout } from "@dxos/async";
|
|
334
|
+
var BUCKET_COLLECTION_INTERVAL = 1e3;
|
|
335
|
+
var StorageMonitor = class {
|
|
336
|
+
constructor() {
|
|
337
|
+
this._enabled = false;
|
|
338
|
+
/**
|
|
339
|
+
* By resource.
|
|
340
|
+
*/
|
|
341
|
+
this._buckets = /* @__PURE__ */ new Map();
|
|
342
|
+
}
|
|
343
|
+
enable() {
|
|
344
|
+
this._enabled = true;
|
|
345
|
+
const timer = setInterval(() => {
|
|
346
|
+
this._finalizeBuckets();
|
|
347
|
+
}, BUCKET_COLLECTION_INTERVAL);
|
|
348
|
+
unrefTimeout(timer);
|
|
349
|
+
}
|
|
350
|
+
beginOp(op) {
|
|
351
|
+
if (!this._enabled) {
|
|
352
|
+
return {
|
|
353
|
+
end: () => {
|
|
354
|
+
}
|
|
355
|
+
};
|
|
356
|
+
}
|
|
357
|
+
const beginTime = performance.now();
|
|
358
|
+
return {
|
|
359
|
+
end: () => {
|
|
360
|
+
var _a2, _b;
|
|
361
|
+
const endTime = performance.now();
|
|
362
|
+
const duration = endTime - beginTime;
|
|
363
|
+
const bucket = this._getOrInitBucket(op.resource);
|
|
364
|
+
switch (op.type) {
|
|
365
|
+
case "read":
|
|
366
|
+
bucket.readOps++;
|
|
367
|
+
bucket.readBytes += (_a2 = op.size) != null ? _a2 : 0;
|
|
368
|
+
bucket.readTime += duration;
|
|
369
|
+
break;
|
|
370
|
+
case "write":
|
|
371
|
+
bucket.writeOps++;
|
|
372
|
+
bucket.writeBytes += (_b = op.size) != null ? _b : 0;
|
|
373
|
+
bucket.writeTime += duration;
|
|
374
|
+
break;
|
|
375
|
+
default:
|
|
376
|
+
bucket.otherOps++;
|
|
377
|
+
bucket.otherTime += duration;
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
};
|
|
381
|
+
}
|
|
382
|
+
_getOrInitBucket(resource) {
|
|
383
|
+
const bucket = this._buckets.get(resource);
|
|
384
|
+
if (bucket) {
|
|
385
|
+
return bucket;
|
|
386
|
+
}
|
|
387
|
+
const newBucket = {
|
|
388
|
+
resource,
|
|
389
|
+
beginTime: performance.now(),
|
|
390
|
+
endTime: 0,
|
|
391
|
+
usage: 0,
|
|
392
|
+
readOps: 0,
|
|
393
|
+
readBytes: 0,
|
|
394
|
+
readTime: 0,
|
|
395
|
+
writeOps: 0,
|
|
396
|
+
writeBytes: 0,
|
|
397
|
+
writeTime: 0,
|
|
398
|
+
otherOps: 0,
|
|
399
|
+
otherTime: 0
|
|
400
|
+
};
|
|
401
|
+
this._buckets.set(resource, newBucket);
|
|
402
|
+
return newBucket;
|
|
403
|
+
}
|
|
404
|
+
_finalizeBuckets() {
|
|
405
|
+
var _a2;
|
|
406
|
+
const now = performance.now();
|
|
407
|
+
const toEmit = [];
|
|
408
|
+
for (const bucket of this._buckets.values()) {
|
|
409
|
+
bucket.endTime = now;
|
|
410
|
+
bucket.usage = (bucket.readTime + bucket.writeTime + bucket.otherTime) / (bucket.endTime - bucket.beginTime);
|
|
411
|
+
toEmit.push(bucket);
|
|
412
|
+
}
|
|
413
|
+
this._buckets.clear();
|
|
414
|
+
for (const bucket of toEmit) {
|
|
415
|
+
this._getOrInitBucket(bucket.resource);
|
|
416
|
+
}
|
|
417
|
+
((_a2 = globalThis.__STORAGE_METRICS) != null ? _a2 : globalThis.__STORAGE_METRICS = []).push(...toEmit);
|
|
418
|
+
}
|
|
419
|
+
};
|
|
420
|
+
var STORAGE_MONITOR = new StorageMonitor();
|
|
421
|
+
|
|
422
|
+
// packages/common/random-access-storage/src/browser/web-fs.ts
|
|
331
423
|
function _ts_decorate(decorators, target, key, desc) {
|
|
332
424
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
333
425
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function")
|
|
@@ -338,7 +430,7 @@ function _ts_decorate(decorators, target, key, desc) {
|
|
|
338
430
|
r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
339
431
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
340
432
|
}
|
|
341
|
-
var __dxlog_file3 = "/
|
|
433
|
+
var __dxlog_file3 = "/mnt/ramdisk/work/packages/common/random-access-storage/src/browser/web-fs.ts";
|
|
342
434
|
var WebFS = class {
|
|
343
435
|
constructor(path) {
|
|
344
436
|
this.path = path;
|
|
@@ -388,6 +480,7 @@ var WebFS = class {
|
|
|
388
480
|
}
|
|
389
481
|
_createFile(fullName) {
|
|
390
482
|
return new WebFile({
|
|
483
|
+
fileName: fullName,
|
|
391
484
|
file: this._initialize().then((root) => root.getFileHandle(fullName, {
|
|
392
485
|
create: true
|
|
393
486
|
})),
|
|
@@ -402,7 +495,7 @@ var WebFS = class {
|
|
|
402
495
|
await Promise.all(Array.from(this._getFiles(path)).map(async ([path2, file]) => {
|
|
403
496
|
await file.destroy().catch((err) => log3.warn(err, void 0, {
|
|
404
497
|
F: __dxlog_file3,
|
|
405
|
-
L:
|
|
498
|
+
L: 107,
|
|
406
499
|
S: this,
|
|
407
500
|
C: (f, a) => f(...a)
|
|
408
501
|
}));
|
|
@@ -417,7 +510,7 @@ var WebFS = class {
|
|
|
417
510
|
recursive: true
|
|
418
511
|
}).catch((err) => log3.warn(err, void 0, {
|
|
419
512
|
F: __dxlog_file3,
|
|
420
|
-
L:
|
|
513
|
+
L: 117,
|
|
421
514
|
S: this,
|
|
422
515
|
C: (f, a) => f(...a)
|
|
423
516
|
}));
|
|
@@ -460,7 +553,7 @@ _ts_decorate([
|
|
|
460
553
|
], WebFS.prototype, "_initialize", null);
|
|
461
554
|
var _a;
|
|
462
555
|
var WebFile = class extends EventEmitter {
|
|
463
|
-
constructor({ file, destroy }) {
|
|
556
|
+
constructor({ fileName, file, destroy }) {
|
|
464
557
|
super();
|
|
465
558
|
this.opened = true;
|
|
466
559
|
this.suspended = false;
|
|
@@ -474,6 +567,7 @@ var WebFile = class extends EventEmitter {
|
|
|
474
567
|
this.statable = true;
|
|
475
568
|
this.destroyed = false;
|
|
476
569
|
this.directory = "";
|
|
570
|
+
// TODO(dmaretskyi): is this used?
|
|
477
571
|
this.filename = "";
|
|
478
572
|
this.type = StorageType.WEBFS;
|
|
479
573
|
this.native = {
|
|
@@ -484,60 +578,115 @@ var WebFile = class extends EventEmitter {
|
|
|
484
578
|
destroy: callbackify(this.destroy.bind(this)),
|
|
485
579
|
truncate: callbackify((_a = this.truncate) == null ? void 0 : _a.bind(this))
|
|
486
580
|
};
|
|
581
|
+
this._fileName = fileName;
|
|
487
582
|
this._fileHandle = file;
|
|
488
583
|
this._destroy = destroy;
|
|
489
584
|
}
|
|
490
585
|
async write(offset, data) {
|
|
491
|
-
const
|
|
492
|
-
|
|
493
|
-
keepExistingData: true
|
|
494
|
-
});
|
|
495
|
-
await writable.write({
|
|
586
|
+
const metric = STORAGE_MONITOR.beginOp({
|
|
587
|
+
resource: this._fileName,
|
|
496
588
|
type: "write",
|
|
497
|
-
data
|
|
498
|
-
position: offset
|
|
589
|
+
size: data.length
|
|
499
590
|
});
|
|
500
|
-
|
|
591
|
+
try {
|
|
592
|
+
const fileHandle = await this._fileHandle;
|
|
593
|
+
const writable = await fileHandle.createWritable({
|
|
594
|
+
keepExistingData: true
|
|
595
|
+
});
|
|
596
|
+
await writable.write({
|
|
597
|
+
type: "write",
|
|
598
|
+
data,
|
|
599
|
+
position: offset
|
|
600
|
+
});
|
|
601
|
+
await writable.close();
|
|
602
|
+
} finally {
|
|
603
|
+
metric.end();
|
|
604
|
+
}
|
|
501
605
|
}
|
|
502
606
|
async read(offset, size) {
|
|
503
|
-
const
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
607
|
+
const metric = STORAGE_MONITOR.beginOp({
|
|
608
|
+
resource: this._fileName,
|
|
609
|
+
type: "read",
|
|
610
|
+
size
|
|
611
|
+
});
|
|
612
|
+
try {
|
|
613
|
+
const fileHandle = await this._fileHandle;
|
|
614
|
+
const file = await fileHandle.getFile();
|
|
615
|
+
if (offset + size > file.size) {
|
|
616
|
+
throw new Error("Read out of bounds");
|
|
617
|
+
}
|
|
618
|
+
return Buffer.from(await file.slice(offset, offset + size).arrayBuffer());
|
|
619
|
+
} finally {
|
|
620
|
+
metric.end();
|
|
507
621
|
}
|
|
508
|
-
return Buffer.from(await file.slice(offset, offset + size).arrayBuffer());
|
|
509
622
|
}
|
|
510
623
|
async del(offset, size) {
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
const writable = await fileHandle.createWritable({
|
|
516
|
-
keepExistingData: true
|
|
624
|
+
const metric = STORAGE_MONITOR.beginOp({
|
|
625
|
+
resource: this._fileName,
|
|
626
|
+
type: "delete",
|
|
627
|
+
size
|
|
517
628
|
});
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
629
|
+
try {
|
|
630
|
+
if (offset < 0 || size < 0) {
|
|
631
|
+
return;
|
|
632
|
+
}
|
|
633
|
+
const fileHandle = await this._fileHandle;
|
|
634
|
+
const writable = await fileHandle.createWritable({
|
|
635
|
+
keepExistingData: true
|
|
636
|
+
});
|
|
637
|
+
const file = await fileHandle.getFile();
|
|
638
|
+
let leftoverSize = 0;
|
|
639
|
+
if (offset + size < file.size) {
|
|
640
|
+
const leftover = Buffer.from(await file.slice(offset + size, file.size).arrayBuffer());
|
|
641
|
+
leftoverSize = leftover.length;
|
|
642
|
+
await writable.write({
|
|
643
|
+
type: "write",
|
|
644
|
+
data: leftover,
|
|
645
|
+
position: offset
|
|
646
|
+
});
|
|
647
|
+
}
|
|
523
648
|
await writable.write({
|
|
524
|
-
type: "
|
|
525
|
-
|
|
526
|
-
position: offset
|
|
649
|
+
type: "truncate",
|
|
650
|
+
size: offset + leftoverSize
|
|
527
651
|
});
|
|
652
|
+
await writable.close();
|
|
653
|
+
} finally {
|
|
654
|
+
metric.end();
|
|
528
655
|
}
|
|
529
|
-
await writable.write({
|
|
530
|
-
type: "truncate",
|
|
531
|
-
size: offset + leftoverSize
|
|
532
|
-
});
|
|
533
|
-
await writable.close();
|
|
534
656
|
}
|
|
535
657
|
async stat() {
|
|
536
|
-
const
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
658
|
+
const metric = STORAGE_MONITOR.beginOp({
|
|
659
|
+
resource: this._fileName,
|
|
660
|
+
type: "stat"
|
|
661
|
+
});
|
|
662
|
+
try {
|
|
663
|
+
const fileHandle = await this._fileHandle;
|
|
664
|
+
const file = await fileHandle.getFile();
|
|
665
|
+
return {
|
|
666
|
+
size: file.size
|
|
667
|
+
};
|
|
668
|
+
} finally {
|
|
669
|
+
metric.end();
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
async truncate(offset) {
|
|
673
|
+
const metric = STORAGE_MONITOR.beginOp({
|
|
674
|
+
resource: this._fileName,
|
|
675
|
+
type: "truncate"
|
|
676
|
+
});
|
|
677
|
+
try {
|
|
678
|
+
const fileHandle = await this._fileHandle;
|
|
679
|
+
const writable = await fileHandle.createWritable({
|
|
680
|
+
keepExistingData: true
|
|
681
|
+
});
|
|
682
|
+
await writable.write({
|
|
683
|
+
type: "truncate",
|
|
684
|
+
size: offset
|
|
685
|
+
});
|
|
686
|
+
await writable.close();
|
|
687
|
+
} finally {
|
|
688
|
+
metric.end();
|
|
689
|
+
}
|
|
541
690
|
}
|
|
542
691
|
async close() {
|
|
543
692
|
}
|
|
@@ -545,17 +694,6 @@ var WebFile = class extends EventEmitter {
|
|
|
545
694
|
this.destroyed = true;
|
|
546
695
|
return await this._destroy();
|
|
547
696
|
}
|
|
548
|
-
async truncate(offset) {
|
|
549
|
-
const fileHandle = await this._fileHandle;
|
|
550
|
-
const writable = await fileHandle.createWritable({
|
|
551
|
-
keepExistingData: true
|
|
552
|
-
});
|
|
553
|
-
await writable.write({
|
|
554
|
-
type: "truncate",
|
|
555
|
-
size: offset
|
|
556
|
-
});
|
|
557
|
-
await writable.close();
|
|
558
|
-
}
|
|
559
697
|
};
|
|
560
698
|
_ts_decorate([
|
|
561
699
|
synchronized
|
|
@@ -571,10 +709,10 @@ _ts_decorate([
|
|
|
571
709
|
], WebFile.prototype, "stat", null);
|
|
572
710
|
_ts_decorate([
|
|
573
711
|
synchronized
|
|
574
|
-
], WebFile.prototype, "
|
|
712
|
+
], WebFile.prototype, "truncate", null);
|
|
575
713
|
_ts_decorate([
|
|
576
714
|
synchronized
|
|
577
|
-
], WebFile.prototype, "
|
|
715
|
+
], WebFile.prototype, "destroy", null);
|
|
578
716
|
|
|
579
717
|
// packages/common/random-access-storage/src/browser/storage.ts
|
|
580
718
|
var createStorage = ({ type, root = "" } = {}) => {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../../../src/common/abstract-storage.ts", "../../../src/common/utils.ts", "../../../src/common/directory.ts", "../../../src/common/file.ts", "../../../src/common/memory-storage.ts", "../../../src/common/storage.ts", "../../../src/browser/firefox-storage.ts", "../../../src/browser/browser-storage.ts", "../../../src/browser/idb-storage.ts", "../../../src/browser/web-fs.ts", "../../../src/browser/storage.ts"],
|
|
4
|
-
"sourcesContent": ["//\n// Copyright 2021 DXOS.org\n//\n\nimport { join } from 'node:path';\nimport { inspect } from 'node:util';\nimport type { RandomAccessStorage } from 'random-access-storage';\n\nimport { inspectObject } from '@dxos/debug';\nimport { log } from '@dxos/log';\n\nimport { Directory } from './directory';\nimport { File, wrapFile } from './file';\nimport { Storage, StorageType } from './storage';\nimport { getFullPath } from './utils';\n\n/**\n * Base class for all storage implementations.\n * https://github.com/random-access-storage\n * https://github.com/random-access-storage/random-access-storage\n */\nexport abstract class AbstractStorage implements Storage {\n protected readonly _files = new Map<string, File>();\n\n public abstract readonly type: StorageType;\n\n // TODO(burdon): Make required.\n constructor(public readonly path: string) {}\n\n [inspect.custom]() {\n return inspectObject(this);\n }\n\n toJSON() {\n return { type: this.type, path: this.path };\n }\n\n public get size() {\n return this._files.size;\n }\n\n // TODO(burdon): Make required.\n public createDirectory(sub = ''): Directory {\n // invariant(sub.length);\n return new Directory(\n this.type,\n getFullPath(this.path, sub),\n this._list.bind(this),\n (...args) => this.getOrCreateFile(...args),\n () => this._delete(sub),\n );\n }\n\n /**\n * Delete all files.\n */\n async reset() {\n try {\n log.info('Erasing all data...');\n await this._closeFilesInPath('');\n await this._delete('');\n await this._destroy();\n log('Erased...');\n } catch (err: any) {\n log.catch(err);\n }\n }\n\n protected async _list(path: string): Promise<string[]> {\n // TODO(dmaretskyi): Fix me.\n return Array.from(this._getFiles(path).keys()).map((filename) => {\n let name = filename.replace(path, '');\n if (name.startsWith('/')) {\n name = name.substring(1);\n }\n return name;\n });\n }\n\n protected getOrCreateFile(path: string, filename: string, opts?: any): File {\n const fullPath = join(path, filename);\n\n let native;\n let file = this._getFileIfExists(fullPath);\n if (file) {\n if (!file.closed) {\n return file;\n }\n\n native = this._openFile(file.native);\n }\n\n if (!native) {\n native = this._createFile(path, filename, opts);\n }\n\n file = wrapFile(native, this.type);\n this._files.set(fullPath, file);\n return file;\n }\n\n protected _destroy(): Promise<void> | undefined {\n return undefined;\n }\n\n /**\n * Attempt to reopen file.\n */\n protected _openFile(file: RandomAccessStorage): RandomAccessStorage | undefined {\n return undefined;\n }\n\n protected abstract _createFile(path: string, filename: string, opts?: any): RandomAccessStorage;\n\n private _getFileIfExists(filename: string): File | undefined {\n if (this._files.has(filename)) {\n const file = this._files.get(filename);\n if (file && !file.destroyed) {\n return file;\n }\n }\n }\n\n private _getFiles(path: string): Map<string, File> {\n const fullPath = getFullPath(this.path, path);\n return new Map(\n [...this._files.entries()].filter(([path, file]) => path.includes(fullPath) && file.destroyed !== true),\n );\n }\n\n private async _closeFilesInPath(path: string): Promise<void> {\n await Promise.all(\n Array.from(this._getFiles(path).values()).map((file) => file.close().catch((err: any) => log.catch(err))),\n );\n }\n\n // TODO(burdon): Delete directory (not just listed files).\n protected async _delete(path: string): Promise<void> {\n await Promise.all(\n Array.from(this._getFiles(path)).map(([path, file]) => {\n return file\n .destroy()\n .then(() => this._files.delete(path))\n .catch((err: any) => log.error(err.message));\n }),\n );\n }\n}\n", "//\n// Copyright 2022 DXOS.org\n//\n\nimport { join } from 'node:path';\n\n// TODO(burdon): Document.\nexport const stringDiff = (first: string, second: string) => first.split(second).join('');\n\nexport const getFullPath = (root: string, path: string) => join(root, stringDiff(path, root));\n", "//\n// Copyright 2022 DXOS.org\n//\n\nimport { File } from './file';\nimport { StorageType } from './storage';\nimport { getFullPath } from './utils';\n\n/**\n * Wraps a directory in the storage file system.\n */\nexport class Directory {\n constructor(\n public readonly type: StorageType,\n public readonly path: string,\n // TODO(burdon): Create interface for these methods (shared with AbstractStorage).\n private readonly _list: (path: string) => Promise<string[]>,\n private readonly _getOrCreateFile: (path: string, filename: string, opts?: any) => File,\n private readonly _delete: () => Promise<void>,\n ) {}\n\n toString() {\n return `Directory(${JSON.stringify({ type: this.type, path: this.path })})`;\n }\n\n /**\n * Create a new sub-directory.\n */\n createDirectory(path: string): Directory {\n return new Directory(this.type, getFullPath(this.path, path), this._list, this._getOrCreateFile, this._delete);\n }\n\n /**\n * Get all files in the current directory.\n */\n list(): Promise<string[]> {\n return this._list(this.path);\n }\n\n /**\n * Get or create a new file.\n */\n getOrCreateFile(filename: string, opts?: any): File {\n return this._getOrCreateFile(this.path, filename, opts);\n }\n\n /**\n * Close and delete all files in the directory and all its sub-directories.\n */\n async delete() {\n await this._delete();\n }\n}\n", "//\n// Copyright 2022 DXOS.org\n//\n\nimport pify from 'pify';\nimport type { FileStat, RandomAccessStorage, RandomAccessStorageProperties } from 'random-access-storage';\n\nimport { log } from '@dxos/log';\n\nimport { StorageType } from './storage';\n\n/**\n * Random access file wrapper.\n * https://github.com/random-access-storage/random-access-storage\n */\nexport interface File extends RandomAccessStorageProperties {\n readonly destroyed: boolean;\n\n // TODO(burdon): Can we remove these since they are not standard across implementations?\n readonly directory: string;\n readonly filename: string;\n\n // Added by factory.\n readonly type: StorageType;\n readonly native: RandomAccessStorage;\n\n write(offset: number, data: Buffer): Promise<void>;\n read(offset: number, size: number): Promise<Buffer>;\n del(offset: number, size: number): Promise<void>;\n stat(): Promise<FileStat>;\n close(): Promise<Error | void>;\n destroy(): Promise<Error | void>;\n\n // Not supported in node, memory.\n truncate?(offset: number): Promise<void>;\n\n // random-access-memory only.\n clone?(): RandomAccessStorage;\n}\n\nconst pifyFields = (object: any, type: StorageType, fields: string[]) => {\n for (const field of fields) {\n if (!object[field]) {\n // TODO(burdon): Suppress warning and throw error if used.\n // console.warn(`Field not supported for type: ${JSON.stringify({ type, field })}`);\n } else {\n const fn = pify(object[field].bind(object));\n object[field] = async (...args: any) => {\n const before = performance.now();\n\n const res = await fn(...args);\n\n const elapsed = performance.now() - before;\n if (elapsed > 10) {\n log.warn('Slow storage operation', { type, operation: field, elapsed });\n }\n\n return res;\n };\n }\n }\n\n return object;\n};\n\n/**\n * Construct async File wrapper.\n * NOTE: This is safe since these are interface methods only (not used internally).\n */\nexport const wrapFile = (native: RandomAccessStorage, type: StorageType): File => {\n const file = pifyFields(native, type, ['write', 'read', 'del', 'stat', 'close', 'destroy', 'truncate']);\n return Object.assign(file, { type, native });\n};\n", "//\n// Copyright 2021 DXOS.org\n//\n\nimport ram from 'random-access-memory';\nimport { Callback, RandomAccessStorage } from 'random-access-storage';\n\nimport { arrayToBuffer } from '@dxos/util';\n\nimport { AbstractStorage } from './abstract-storage';\nimport { StorageType } from './storage';\n\n/**\n * Storage interface implementation for RAM.\n * https://github.com/random-access-storage/random-access-memory\n */\nexport class MemoryStorage extends AbstractStorage {\n public override type: StorageType = StorageType.RAM;\n\n protected override _createFile(path: string, filename: string): RandomAccessStorage {\n return this._patchFile(ram());\n }\n\n protected override _openFile(file: RandomAccessStorage): RandomAccessStorage {\n const newFile = file.clone!();\n (newFile as any).closed = false;\n return this._patchFile(newFile);\n }\n\n private _patchFile(file: RandomAccessStorage): RandomAccessStorage {\n // Patch required to make consistent across platforms.\n const trueRead = file.read.bind(file);\n\n file.read = (offset: number, size: number, cb: Callback<Buffer>) =>\n trueRead(offset, size, (err: Error | null, data?: Buffer) => {\n if (err) {\n return cb(err);\n } else {\n return cb(err, arrayToBuffer(data!));\n }\n });\n\n return file;\n }\n}\n", "//\n// Copyright 2021 DXOS.org\n//\n\nimport { Directory } from './directory';\n\n// TODO(burdon): Reconcile with ConfigProto.\nexport enum StorageType {\n RAM = 'ram',\n IDB = 'idb',\n CHROME = 'chrome',\n FIREFOX = 'firefox',\n NODE = 'node',\n WEBFS = 'webfs',\n}\n\nexport type DiskInfo = {\n /**\n * Bytes.\n */\n used: number;\n};\n\nexport interface Storage {\n readonly path: string;\n readonly type: StorageType;\n readonly size: number;\n\n getDiskInfo?(): Promise<DiskInfo>;\n\n // TODO(burdon): Make required.\n createDirectory: (path?: string) => Directory;\n reset: () => Promise<void>;\n}\n\nexport type StorageConstructor = (params?: { type?: StorageType; root?: string }) => Storage;\n", "//\n// Copyright 2021 DXOS.org\n//\n\n// NOTE: Removing the .js extension here breaks usage in create-react-app.\n// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-ignore\nimport raw from 'random-access-web/mutable-file-wrapper.js';\n\nimport { StorageType } from '../common';\nimport { BrowserStorage } from './browser-storage';\n\n/**\n * Storage interface implementation for Firefox browser.\n * https://github.com/random-access-storage/random-access-web\n */\nexport class FirefoxStorage extends BrowserStorage {\n public override type: StorageType = StorageType.FIREFOX;\n\n protected override _createFileStorage(path: string) {\n return raw({ name: path });\n }\n}\n", "//\n// Copyright 2021 DXOS.org\n//\n\nimport { join } from 'node:path';\nimport type { RandomAccessStorage } from 'random-access-storage';\n\nimport { AbstractStorage } from '../common';\n\n/**\n * Base class for random access files based on IDB.\n */\nexport abstract class BrowserStorage extends AbstractStorage {\n private readonly _fileStorage: (filename: string, opts?: {}) => RandomAccessStorage;\n\n constructor(path: string) {\n super(path);\n this._fileStorage = this._createFileStorage(path);\n }\n\n protected _createFile(path: string, filename: string): RandomAccessStorage {\n const fullPath = join(path, filename);\n return this._fileStorage(fullPath);\n }\n\n protected abstract _createFileStorage(path: string): (filename: string, opts?: {}) => RandomAccessStorage;\n\n protected override async _destroy() {\n // eslint-disable-next-line no-undef\n return new Promise<void>((resolve, reject) => {\n const request = indexedDB.deleteDatabase(this.path);\n request.onsuccess = () => {\n resolve();\n };\n request.onupgradeneeded = () => {\n reject(new Error('Upgrade needed.'));\n };\n request.onblocked = () => {\n reject(new Error('Blocked.'));\n };\n request.onerror = (err: any) => {\n reject(err);\n };\n });\n }\n}\n", "//\n// Copyright 2021 DXOS.org\n//\n\nimport idb from 'random-access-idb';\n\nimport { StorageType } from '../common';\nimport { BrowserStorage } from './browser-storage';\n\n/**\n * Storage interface implementation for index DB.\n * https://github.com/random-access-storage/random-access-idb\n */\nexport class IDbStorage extends BrowserStorage {\n public override type: StorageType = StorageType.IDB;\n\n protected override _createFileStorage(path: string) {\n return idb(path);\n }\n}\n", "//\n// Copyright 2023 DXOS.org\n//\n\nimport { EventEmitter } from 'node:events';\nimport { callbackify } from 'node:util';\nimport { RandomAccessStorage } from 'random-access-storage';\nimport invariant from 'tiny-invariant';\n\nimport { synchronized } from '@dxos/async';\nimport { log } from '@dxos/log';\n\nimport { Directory, File, Storage, StorageType, getFullPath, DiskInfo } from '../common';\n\n/**\n * Web file systems.\n */\nexport class WebFS implements Storage {\n readonly type = StorageType.WEBFS;\n\n protected readonly _files = new Map<string, File>();\n protected _root?: FileSystemDirectoryHandle;\n\n constructor(public readonly path: string) {}\n\n public get size() {\n return this._files.size;\n }\n\n private _getFiles(path: string): Map<string, File> {\n const fullName = this._getFullFilename(this.path, path);\n return new Map(\n [...this._files.entries()].filter(([path, file]) => path.includes(fullName) && file.destroyed !== true),\n );\n }\n\n private async _list(path: string): Promise<string[]> {\n const fullName = this._getFullFilename(path);\n\n const root = await this._initialize();\n\n // TODO(dmaretskyi): While we're storing all files in flat namespace we just iterate the root.\n // console.log({ path, fullName })\n // let dir: FileSystemDirectoryHandle;\n // if (path === '') {\n // dir = root;\n // } else {\n // dir = await root.getDirectoryHandle(fullName, { create: true });\n // }\n const entries: string[] = [];\n\n for await (const entry of (root as any).keys()) {\n if (entry.startsWith(fullName + '_')) {\n entries.push(entry.slice(fullName.length + 1));\n }\n }\n return entries;\n }\n\n @synchronized\n private async _initialize() {\n if (this._root) {\n return this._root;\n }\n this._root = await navigator.storage.getDirectory();\n invariant(this._root, 'Root is undefined');\n return this._root;\n }\n\n createDirectory(sub = '') {\n return new Directory(\n this.type,\n getFullPath(this.path, sub),\n (path) => this._list(path),\n (...args) => this.getOrCreateFile(...args),\n () => this._delete(sub),\n );\n }\n\n getOrCreateFile(path: string, filename: string, opts?: any): File {\n const fullName = this._getFullFilename(path, filename);\n const existingFile = this._files.get(fullName);\n if (existingFile) {\n return existingFile;\n }\n const file = this._createFile(fullName);\n this._files.set(fullName, file);\n return file;\n }\n\n private _createFile(fullName: string) {\n return new WebFile({\n file: this._initialize().then((root) => root.getFileHandle(fullName, { create: true })),\n destroy: async () => {\n this._files.delete(fullName);\n const root = await this._initialize();\n return root.removeEntry(fullName);\n },\n });\n }\n\n private async _delete(path: string): Promise<void> {\n await Promise.all(\n Array.from(this._getFiles(path)).map(async ([path, file]) => {\n await file.destroy().catch((err: any) => log.warn(err));\n this._files.delete(path);\n }),\n );\n }\n\n async reset() {\n await this._initialize();\n for await (const filename of await (this._root as any).keys()) {\n this._files.delete(filename);\n await this._root!.removeEntry(filename, { recursive: true }).catch((err: any) => log.warn(err));\n }\n this._root = undefined;\n }\n\n private _getFullFilename(path: string, filename?: string) {\n // Replace slashes with underscores. Because we can't have slashes in filenames in Browser File Handle API.\n if (filename) {\n return getFullPath(path, filename).split('/').join('_');\n } else {\n return path.split('/').join('_');\n }\n }\n\n async getDiskInfo(): Promise<DiskInfo> {\n let used = 0;\n\n const recurse = async (handle: FileSystemDirectoryHandle) => {\n const promises = [];\n\n for await (const entry of (handle as any).values()) {\n promises.push(\n (async () => {\n switch (entry.kind) {\n case 'file':\n used += await (entry as FileSystemFileHandle).getFile().then((f) => (used += f.size));\n break;\n case 'directory':\n await recurse(entry as FileSystemDirectoryHandle);\n break;\n }\n })(),\n );\n }\n await Promise.all(promises);\n };\n\n await recurse(this._root!);\n\n return {\n used,\n };\n }\n}\n\n// TODO(mykola): Remove EventEmitter.\nexport class WebFile extends EventEmitter implements File {\n readonly opened: boolean = true;\n readonly suspended: boolean = false;\n readonly closed: boolean = false;\n readonly unlinked: boolean = false;\n readonly writing: boolean = false;\n readonly readable: boolean = true;\n readonly writable: boolean = true;\n readonly deletable: boolean = true;\n readonly truncatable: boolean = true;\n readonly statable: boolean = true;\n\n private readonly _fileHandle: Promise<FileSystemFileHandle>;\n private readonly _destroy: () => Promise<void>;\n\n constructor({ file, destroy }: { file: Promise<FileSystemFileHandle>; destroy: () => Promise<void> }) {\n super();\n this._fileHandle = file;\n this._destroy = destroy;\n }\n\n destroyed = false;\n directory = '';\n filename = '';\n type: StorageType = StorageType.WEBFS;\n native: RandomAccessStorage = {\n write: callbackify(this.write.bind(this)),\n read: callbackify(this.read.bind(this)),\n del: callbackify(this.del.bind(this)),\n stat: callbackify(this.stat.bind(this)),\n destroy: callbackify(this.destroy.bind(this)),\n truncate: callbackify(this.truncate?.bind(this)),\n } as RandomAccessStorage;\n\n @synchronized\n async write(offset: number, data: Buffer) {\n // TODO(mykola): Fix types.\n const fileHandle: any = await this._fileHandle;\n const writable = await fileHandle.createWritable({ keepExistingData: true });\n await writable.write({ type: 'write', data, position: offset });\n await writable.close();\n }\n\n @synchronized\n async read(offset: number, size: number) {\n const fileHandle: any = await this._fileHandle;\n const file = await fileHandle.getFile();\n if (offset + size > file.size) {\n throw new Error('Read out of bounds');\n }\n // does not copy the buffer\n return Buffer.from(await file.slice(offset, offset + size).arrayBuffer());\n }\n\n @synchronized\n async del(offset: number, size: number) {\n if (offset < 0 || size < 0) {\n return;\n }\n const fileHandle: any = await this._fileHandle;\n const writable = await fileHandle.createWritable({ keepExistingData: true });\n const file = await fileHandle.getFile();\n let leftoverSize = 0;\n if (offset + size < file.size) {\n // does not copy the buffer\n const leftover = Buffer.from(await file.slice(offset + size, file.size).arrayBuffer());\n leftoverSize = leftover.length;\n await writable.write({ type: 'write', data: leftover, position: offset });\n }\n\n await writable.write({ type: 'truncate', size: offset + leftoverSize });\n await writable.close();\n }\n\n @synchronized\n async stat() {\n const fileHandle: any = await this._fileHandle;\n const file = await fileHandle.getFile();\n return {\n size: file.size,\n };\n }\n\n async close(): Promise<void> {}\n\n @synchronized\n async destroy() {\n this.destroyed = true;\n return await this._destroy();\n }\n\n @synchronized\n async truncate(offset: number) {\n const fileHandle: any = await this._fileHandle;\n const writable = await fileHandle.createWritable({ keepExistingData: true });\n await writable.write({ type: 'truncate', size: offset });\n await writable.close();\n }\n}\n", "//\n// Copyright 2021 DXOS.org\n//\n\nimport { MemoryStorage, Storage, StorageConstructor, StorageType } from '../common';\nimport { FirefoxStorage } from './firefox-storage';\nimport { IDbStorage } from './idb-storage';\nimport { WebFS } from './web-fs';\n\nexport const createStorage: StorageConstructor = ({ type, root = '' } = {}): Storage => {\n if (type === undefined) {\n if (\n navigator &&\n navigator.storage &&\n typeof navigator.storage.getDirectory === 'function' &&\n FileSystemFileHandle &&\n typeof (FileSystemFileHandle.prototype as any).createWritable === 'function'\n ) {\n return new WebFS(root);\n } else {\n return new IDbStorage(root);\n }\n }\n\n switch (type) {\n case StorageType.RAM: {\n return new MemoryStorage(root);\n }\n\n case StorageType.IDB:\n case StorageType.CHROME: {\n return new IDbStorage(root);\n }\n\n case StorageType.FIREFOX: {\n return new FirefoxStorage(root);\n }\n\n case StorageType.WEBFS: {\n return new WebFS(root);\n }\n\n default: {\n throw new Error(`Invalid type: ${type}`);\n }\n }\n};\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": ["join", "inspect", "inspectObject", "log", "join", "stringDiff", "first", "second", "split", "join", "getFullPath", "root", "path", "Directory", "constructor", "type", "path", "_list", "_getOrCreateFile", "_delete", "toString", "JSON", "stringify", "createDirectory", "getFullPath", "list", "getOrCreateFile", "filename", "opts", "delete", "pify", "log", "pifyFields", "object", "type", "fields", "field", "fn", "bind", "args", "before", "performance", "now", "res", "elapsed", "warn", "operation", "wrapFile", "native", "file", "Object", "assign", "AbstractStorage", "constructor", "path", "_files", "Map", "inspect", "custom", "inspectObject", "toJSON", "type", "size", "createDirectory", "sub", "Directory", "getFullPath", "_list", "bind", "args", "getOrCreateFile", "_delete", "reset", "log", "info", "_closeFilesInPath", "_destroy", "err", "catch", "Array", "from", "_getFiles", "keys", "map", "filename", "name", "replace", "startsWith", "substring", "opts", "fullPath", "join", "native", "file", "_getFileIfExists", "closed", "_openFile", "_createFile", "wrapFile", "set", "undefined", "has", "get", "destroyed", "entries", "filter", "includes", "Promise", "all", "values", "close", "destroy", "then", "delete", "error", "message", "ram", "arrayToBuffer", "StorageType", "RAM", "IDB", "CHROME", "FIREFOX", "NODE", "WEBFS", "MemoryStorage", "AbstractStorage", "type", "StorageType", "RAM", "_createFile", "path", "filename", "_patchFile", "ram", "_openFile", "file", "newFile", "clone", "closed", "trueRead", "read", "bind", "offset", "size", "cb", "err", "data", "arrayToBuffer", "raw", "join", "BrowserStorage", "AbstractStorage", "constructor", "path", "_fileStorage", "_createFileStorage", "_createFile", "filename", "fullPath", "join", "_destroy", "Promise", "resolve", "reject", "request", "indexedDB", "deleteDatabase", "onsuccess", "onupgradeneeded", "Error", "onblocked", "onerror", "err", "FirefoxStorage", "BrowserStorage", "type", "StorageType", "FIREFOX", "_createFileStorage", "path", "raw", "name", "idb", "IDbStorage", "BrowserStorage", "type", "StorageType", "IDB", "_createFileStorage", "path", "idb", "EventEmitter", "callbackify", "invariant", "synchronized", "log", "WebFS", "constructor", "path", "type", "StorageType", "WEBFS", "_files", "Map", "size", "_getFiles", "fullName", "_getFullFilename", "entries", "filter", "file", "includes", "destroyed", "_list", "root", "_initialize", "entry", "keys", "startsWith", "push", "slice", "length", "_root", "navigator", "storage", "getDirectory", "invariant", "createDirectory", "sub", "Directory", "getFullPath", "args", "getOrCreateFile", "_delete", "filename", "opts", "existingFile", "get", "_createFile", "set", "WebFile", "then", "getFileHandle", "create", "destroy", "delete", "removeEntry", "Promise", "all", "Array", "from", "map", "catch", "err", "log", "warn", "reset", "recursive", "undefined", "split", "join", "getDiskInfo", "used", "recurse", "handle", "promises", "values", "kind", "getFile", "f", "synchronized", "EventEmitter", "opened", "suspended", "closed", "unlinked", "writing", "readable", "writable", "deletable", "truncatable", "statable", "directory", "native", "write", "callbackify", "bind", "read", "del", "stat", "truncate", "_fileHandle", "_destroy", "offset", "data", "fileHandle", "createWritable", "keepExistingData", "position", "close", "Error", "Buffer", "arrayBuffer", "leftoverSize", "leftover", "createStorage", "type", "root", "undefined", "navigator", "storage", "getDirectory", "FileSystemFileHandle", "prototype", "createWritable", "WebFS", "IDbStorage", "StorageType", "RAM", "MemoryStorage", "IDB", "CHROME", "FIREFOX", "FirefoxStorage", "WEBFS", "Error"]
|
|
3
|
+
"sources": ["../../../src/common/abstract-storage.ts", "../../../src/common/utils.ts", "../../../src/common/directory.ts", "../../../src/common/file.ts", "../../../src/common/memory-storage.ts", "../../../src/common/storage.ts", "../../../src/browser/firefox-storage.ts", "../../../src/browser/browser-storage.ts", "../../../src/browser/idb-storage.ts", "../../../src/browser/web-fs.ts", "../../../src/monitor.ts", "../../../src/browser/storage.ts"],
|
|
4
|
+
"sourcesContent": ["//\n// Copyright 2021 DXOS.org\n//\n\nimport { join } from 'node:path';\nimport { inspect } from 'node:util';\nimport type { RandomAccessStorage } from 'random-access-storage';\n\nimport { inspectObject } from '@dxos/debug';\nimport { log } from '@dxos/log';\n\nimport { Directory } from './directory';\nimport { File, wrapFile } from './file';\nimport { Storage, StorageType } from './storage';\nimport { getFullPath } from './utils';\n\n/**\n * Base class for all storage implementations.\n * https://github.com/random-access-storage\n * https://github.com/random-access-storage/random-access-storage\n */\nexport abstract class AbstractStorage implements Storage {\n protected readonly _files = new Map<string, File>();\n\n public abstract readonly type: StorageType;\n\n // TODO(burdon): Make required.\n constructor(public readonly path: string) {}\n\n [inspect.custom]() {\n return inspectObject(this);\n }\n\n toJSON() {\n return { type: this.type, path: this.path };\n }\n\n public get size() {\n return this._files.size;\n }\n\n // TODO(burdon): Make required.\n public createDirectory(sub = ''): Directory {\n // invariant(sub.length);\n return new Directory(\n this.type,\n getFullPath(this.path, sub),\n this._list.bind(this),\n (...args) => this.getOrCreateFile(...args),\n () => this._delete(sub),\n );\n }\n\n /**\n * Delete all files.\n */\n async reset() {\n try {\n log.info('Erasing all data...');\n await this._closeFilesInPath('');\n await this._delete('');\n await this._destroy();\n log('Erased...');\n } catch (err: any) {\n log.catch(err);\n }\n }\n\n protected async _list(path: string): Promise<string[]> {\n // TODO(dmaretskyi): Fix me.\n return Array.from(this._getFiles(path).keys()).map((filename) => {\n let name = filename.replace(path, '');\n if (name.startsWith('/')) {\n name = name.substring(1);\n }\n return name;\n });\n }\n\n protected getOrCreateFile(path: string, filename: string, opts?: any): File {\n const fullPath = join(path, filename);\n\n let native;\n let file = this._getFileIfExists(fullPath);\n if (file) {\n if (!file.closed) {\n return file;\n }\n\n native = this._openFile(file.native);\n }\n\n if (!native) {\n native = this._createFile(path, filename, opts);\n }\n\n file = wrapFile(native, this.type);\n this._files.set(fullPath, file);\n return file;\n }\n\n protected _destroy(): Promise<void> | undefined {\n return undefined;\n }\n\n /**\n * Attempt to reopen file.\n */\n protected _openFile(file: RandomAccessStorage): RandomAccessStorage | undefined {\n return undefined;\n }\n\n protected abstract _createFile(path: string, filename: string, opts?: any): RandomAccessStorage;\n\n private _getFileIfExists(filename: string): File | undefined {\n if (this._files.has(filename)) {\n const file = this._files.get(filename);\n if (file && !file.destroyed) {\n return file;\n }\n }\n }\n\n private _getFiles(path: string): Map<string, File> {\n const fullPath = getFullPath(this.path, path);\n return new Map(\n [...this._files.entries()].filter(([path, file]) => path.includes(fullPath) && file.destroyed !== true),\n );\n }\n\n private async _closeFilesInPath(path: string): Promise<void> {\n await Promise.all(\n Array.from(this._getFiles(path).values()).map((file) => file.close().catch((err: any) => log.catch(err))),\n );\n }\n\n // TODO(burdon): Delete directory (not just listed files).\n protected async _delete(path: string): Promise<void> {\n await Promise.all(\n Array.from(this._getFiles(path)).map(([path, file]) => {\n return file\n .destroy()\n .then(() => this._files.delete(path))\n .catch((err: any) => log.error(err.message));\n }),\n );\n }\n}\n", "//\n// Copyright 2022 DXOS.org\n//\n\nimport { join } from 'node:path';\n\n// TODO(burdon): Document.\nexport const stringDiff = (first: string, second: string) => first.split(second).join('');\n\nexport const getFullPath = (root: string, path: string) => join(root, stringDiff(path, root));\n", "//\n// Copyright 2022 DXOS.org\n//\n\nimport { File } from './file';\nimport { StorageType } from './storage';\nimport { getFullPath } from './utils';\n\n/**\n * Wraps a directory in the storage file system.\n */\nexport class Directory {\n constructor(\n public readonly type: StorageType,\n public readonly path: string,\n // TODO(burdon): Create interface for these methods (shared with AbstractStorage).\n private readonly _list: (path: string) => Promise<string[]>,\n private readonly _getOrCreateFile: (path: string, filename: string, opts?: any) => File,\n private readonly _delete: () => Promise<void>,\n ) {}\n\n toString() {\n return `Directory(${JSON.stringify({ type: this.type, path: this.path })})`;\n }\n\n /**\n * Create a new sub-directory.\n */\n createDirectory(path: string): Directory {\n return new Directory(this.type, getFullPath(this.path, path), this._list, this._getOrCreateFile, this._delete);\n }\n\n /**\n * Get all files in the current directory.\n */\n list(): Promise<string[]> {\n return this._list(this.path);\n }\n\n /**\n * Get or create a new file.\n */\n getOrCreateFile(filename: string, opts?: any): File {\n return this._getOrCreateFile(this.path, filename, opts);\n }\n\n /**\n * Close and delete all files in the directory and all its sub-directories.\n */\n async delete() {\n await this._delete();\n }\n}\n", "//\n// Copyright 2022 DXOS.org\n//\n\nimport pify from 'pify';\nimport type { FileStat, RandomAccessStorage, RandomAccessStorageProperties } from 'random-access-storage';\n\nimport { log } from '@dxos/log';\n\nimport { StorageType } from './storage';\n\n/**\n * Random access file wrapper.\n * https://github.com/random-access-storage/random-access-storage\n */\nexport interface File extends RandomAccessStorageProperties {\n readonly destroyed: boolean;\n\n // TODO(burdon): Can we remove these since they are not standard across implementations?\n readonly directory: string;\n readonly filename: string;\n\n // Added by factory.\n readonly type: StorageType;\n readonly native: RandomAccessStorage;\n\n write(offset: number, data: Buffer): Promise<void>;\n read(offset: number, size: number): Promise<Buffer>;\n del(offset: number, size: number): Promise<void>;\n stat(): Promise<FileStat>;\n close(): Promise<Error | void>;\n destroy(): Promise<Error | void>;\n\n // Not supported in node, memory.\n truncate?(offset: number): Promise<void>;\n\n // random-access-memory only.\n clone?(): RandomAccessStorage;\n}\n\nconst pifyFields = (object: any, type: StorageType, fields: string[]) => {\n for (const field of fields) {\n if (!object[field]) {\n // TODO(burdon): Suppress warning and throw error if used.\n // console.warn(`Field not supported for type: ${JSON.stringify({ type, field })}`);\n } else {\n const fn = pify(object[field].bind(object));\n object[field] = async (...args: any) => {\n const before = performance.now();\n\n const res = await fn(...args);\n\n const elapsed = performance.now() - before;\n if (elapsed > 10) {\n log.warn('Slow storage operation', { type, operation: field, elapsed });\n }\n\n return res;\n };\n }\n }\n\n return object;\n};\n\n/**\n * Construct async File wrapper.\n * NOTE: This is safe since these are interface methods only (not used internally).\n */\nexport const wrapFile = (native: RandomAccessStorage, type: StorageType): File => {\n const file = pifyFields(native, type, ['write', 'read', 'del', 'stat', 'close', 'destroy', 'truncate']);\n return Object.assign(file, { type, native });\n};\n", "//\n// Copyright 2021 DXOS.org\n//\n\nimport ram from 'random-access-memory';\nimport { Callback, RandomAccessStorage } from 'random-access-storage';\n\nimport { arrayToBuffer } from '@dxos/util';\n\nimport { AbstractStorage } from './abstract-storage';\nimport { StorageType } from './storage';\n\n/**\n * Storage interface implementation for RAM.\n * https://github.com/random-access-storage/random-access-memory\n */\nexport class MemoryStorage extends AbstractStorage {\n public override type: StorageType = StorageType.RAM;\n\n protected override _createFile(path: string, filename: string): RandomAccessStorage {\n return this._patchFile(ram());\n }\n\n protected override _openFile(file: RandomAccessStorage): RandomAccessStorage {\n const newFile = file.clone!();\n (newFile as any).closed = false;\n return this._patchFile(newFile);\n }\n\n private _patchFile(file: RandomAccessStorage): RandomAccessStorage {\n // Patch required to make consistent across platforms.\n const trueRead = file.read.bind(file);\n\n file.read = (offset: number, size: number, cb: Callback<Buffer>) =>\n trueRead(offset, size, (err: Error | null, data?: Buffer) => {\n if (err) {\n return cb(err);\n } else {\n return cb(err, arrayToBuffer(data!));\n }\n });\n\n return file;\n }\n}\n", "//\n// Copyright 2021 DXOS.org\n//\n\nimport { Directory } from './directory';\n\n// TODO(burdon): Reconcile with ConfigProto.\nexport enum StorageType {\n RAM = 'ram',\n IDB = 'idb',\n CHROME = 'chrome',\n FIREFOX = 'firefox',\n NODE = 'node',\n WEBFS = 'webfs',\n}\n\nexport type DiskInfo = {\n /**\n * Bytes.\n */\n used: number;\n};\n\nexport interface Storage {\n readonly path: string;\n readonly type: StorageType;\n readonly size: number;\n\n getDiskInfo?(): Promise<DiskInfo>;\n\n // TODO(burdon): Make required.\n createDirectory: (path?: string) => Directory;\n reset: () => Promise<void>;\n}\n\nexport type StorageConstructor = (params?: { type?: StorageType; root?: string }) => Storage;\n", "//\n// Copyright 2021 DXOS.org\n//\n\n// NOTE: Removing the .js extension here breaks usage in create-react-app.\n// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-ignore\nimport raw from 'random-access-web/mutable-file-wrapper.js';\n\nimport { StorageType } from '../common';\nimport { BrowserStorage } from './browser-storage';\n\n/**\n * Storage interface implementation for Firefox browser.\n * https://github.com/random-access-storage/random-access-web\n */\nexport class FirefoxStorage extends BrowserStorage {\n public override type: StorageType = StorageType.FIREFOX;\n\n protected override _createFileStorage(path: string) {\n return raw({ name: path });\n }\n}\n", "//\n// Copyright 2021 DXOS.org\n//\n\nimport { join } from 'node:path';\nimport type { RandomAccessStorage } from 'random-access-storage';\n\nimport { AbstractStorage } from '../common';\n\n/**\n * Base class for random access files based on IDB.\n */\nexport abstract class BrowserStorage extends AbstractStorage {\n private readonly _fileStorage: (filename: string, opts?: {}) => RandomAccessStorage;\n\n constructor(path: string) {\n super(path);\n this._fileStorage = this._createFileStorage(path);\n }\n\n protected _createFile(path: string, filename: string): RandomAccessStorage {\n const fullPath = join(path, filename);\n return this._fileStorage(fullPath);\n }\n\n protected abstract _createFileStorage(path: string): (filename: string, opts?: {}) => RandomAccessStorage;\n\n protected override async _destroy() {\n // eslint-disable-next-line no-undef\n return new Promise<void>((resolve, reject) => {\n const request = indexedDB.deleteDatabase(this.path);\n request.onsuccess = () => {\n resolve();\n };\n request.onupgradeneeded = () => {\n reject(new Error('Upgrade needed.'));\n };\n request.onblocked = () => {\n reject(new Error('Blocked.'));\n };\n request.onerror = (err: any) => {\n reject(err);\n };\n });\n }\n}\n", "//\n// Copyright 2021 DXOS.org\n//\n\nimport idb from 'random-access-idb';\n\nimport { StorageType } from '../common';\nimport { BrowserStorage } from './browser-storage';\n\n/**\n * Storage interface implementation for index DB.\n * https://github.com/random-access-storage/random-access-idb\n */\nexport class IDbStorage extends BrowserStorage {\n public override type: StorageType = StorageType.IDB;\n\n protected override _createFileStorage(path: string) {\n return idb(path);\n }\n}\n", "//\n// Copyright 2023 DXOS.org\n//\n\nimport { EventEmitter } from 'node:events';\nimport { callbackify } from 'node:util';\nimport { RandomAccessStorage } from 'random-access-storage';\nimport invariant from 'tiny-invariant';\n\nimport { synchronized } from '@dxos/async';\nimport { log } from '@dxos/log';\n\nimport { Directory, File, Storage, StorageType, getFullPath, DiskInfo } from '../common';\nimport { STORAGE_MONITOR } from '../monitor';\n\n/**\n * Web file systems.\n */\nexport class WebFS implements Storage {\n readonly type = StorageType.WEBFS;\n\n protected readonly _files = new Map<string, File>();\n protected _root?: FileSystemDirectoryHandle;\n\n constructor(public readonly path: string) {}\n\n public get size() {\n return this._files.size;\n }\n\n private _getFiles(path: string): Map<string, File> {\n const fullName = this._getFullFilename(this.path, path);\n return new Map(\n [...this._files.entries()].filter(([path, file]) => path.includes(fullName) && file.destroyed !== true),\n );\n }\n\n private async _list(path: string): Promise<string[]> {\n const fullName = this._getFullFilename(path);\n\n const root = await this._initialize();\n\n // TODO(dmaretskyi): While we're storing all files in flat namespace we just iterate the root.\n // console.log({ path, fullName })\n // let dir: FileSystemDirectoryHandle;\n // if (path === '') {\n // dir = root;\n // } else {\n // dir = await root.getDirectoryHandle(fullName, { create: true });\n // }\n const entries: string[] = [];\n\n for await (const entry of (root as any).keys()) {\n if (entry.startsWith(fullName + '_')) {\n entries.push(entry.slice(fullName.length + 1));\n }\n }\n return entries;\n }\n\n @synchronized\n private async _initialize() {\n if (this._root) {\n return this._root;\n }\n this._root = await navigator.storage.getDirectory();\n invariant(this._root, 'Root is undefined');\n return this._root;\n }\n\n createDirectory(sub = '') {\n return new Directory(\n this.type,\n getFullPath(this.path, sub),\n (path) => this._list(path),\n (...args) => this.getOrCreateFile(...args),\n () => this._delete(sub),\n );\n }\n\n getOrCreateFile(path: string, filename: string, opts?: any): File {\n const fullName = this._getFullFilename(path, filename);\n const existingFile = this._files.get(fullName);\n if (existingFile) {\n return existingFile;\n }\n const file = this._createFile(fullName);\n this._files.set(fullName, file);\n return file;\n }\n\n private _createFile(fullName: string) {\n return new WebFile({\n fileName: fullName,\n file: this._initialize().then((root) => root.getFileHandle(fullName, { create: true })),\n destroy: async () => {\n this._files.delete(fullName);\n const root = await this._initialize();\n return root.removeEntry(fullName);\n },\n });\n }\n\n private async _delete(path: string): Promise<void> {\n await Promise.all(\n Array.from(this._getFiles(path)).map(async ([path, file]) => {\n await file.destroy().catch((err: any) => log.warn(err));\n this._files.delete(path);\n }),\n );\n }\n\n async reset() {\n await this._initialize();\n for await (const filename of await (this._root as any).keys()) {\n this._files.delete(filename);\n await this._root!.removeEntry(filename, { recursive: true }).catch((err: any) => log.warn(err));\n }\n this._root = undefined;\n }\n\n private _getFullFilename(path: string, filename?: string) {\n // Replace slashes with underscores. Because we can't have slashes in filenames in Browser File Handle API.\n if (filename) {\n return getFullPath(path, filename).split('/').join('_');\n } else {\n return path.split('/').join('_');\n }\n }\n\n async getDiskInfo(): Promise<DiskInfo> {\n let used = 0;\n\n const recurse = async (handle: FileSystemDirectoryHandle) => {\n const promises = [];\n\n for await (const entry of (handle as any).values()) {\n promises.push(\n (async () => {\n switch (entry.kind) {\n case 'file':\n used += await (entry as FileSystemFileHandle).getFile().then((f) => (used += f.size));\n break;\n case 'directory':\n await recurse(entry as FileSystemDirectoryHandle);\n break;\n }\n })(),\n );\n }\n await Promise.all(promises);\n };\n\n await recurse(this._root!);\n\n return {\n used,\n };\n }\n}\n\n// TODO(mykola): Remove EventEmitter.\nexport class WebFile extends EventEmitter implements File {\n readonly opened: boolean = true;\n readonly suspended: boolean = false;\n readonly closed: boolean = false;\n readonly unlinked: boolean = false;\n readonly writing: boolean = false;\n readonly readable: boolean = true;\n readonly writable: boolean = true;\n readonly deletable: boolean = true;\n readonly truncatable: boolean = true;\n readonly statable: boolean = true;\n private readonly _fileName: string;\n\n private readonly _fileHandle: Promise<FileSystemFileHandle>;\n private readonly _destroy: () => Promise<void>;\n\n constructor({\n fileName,\n file,\n destroy,\n }: {\n file: Promise<FileSystemFileHandle>;\n fileName: string;\n destroy: () => Promise<void>;\n }) {\n super();\n this._fileName = fileName;\n this._fileHandle = file;\n this._destroy = destroy;\n }\n\n destroyed = false;\n directory = '';\n // TODO(dmaretskyi): is this used?\n filename = '';\n type: StorageType = StorageType.WEBFS;\n native: RandomAccessStorage = {\n write: callbackify(this.write.bind(this)),\n read: callbackify(this.read.bind(this)),\n del: callbackify(this.del.bind(this)),\n stat: callbackify(this.stat.bind(this)),\n destroy: callbackify(this.destroy.bind(this)),\n truncate: callbackify(this.truncate?.bind(this)),\n } as RandomAccessStorage;\n\n @synchronized\n async write(offset: number, data: Buffer) {\n const metric = STORAGE_MONITOR.beginOp({ resource: this._fileName, type: 'write', size: data.length });\n try {\n // TODO(mykola): Fix types.\n const fileHandle: any = await this._fileHandle;\n const writable = await fileHandle.createWritable({ keepExistingData: true });\n await writable.write({ type: 'write', data, position: offset });\n await writable.close();\n } finally {\n metric.end();\n }\n }\n\n @synchronized\n async read(offset: number, size: number) {\n const metric = STORAGE_MONITOR.beginOp({ resource: this._fileName, type: 'read', size });\n try {\n const fileHandle: any = await this._fileHandle;\n const file = await fileHandle.getFile();\n if (offset + size > file.size) {\n throw new Error('Read out of bounds');\n }\n // does not copy the buffer\n return Buffer.from(await file.slice(offset, offset + size).arrayBuffer());\n } finally {\n metric.end();\n }\n }\n\n @synchronized\n async del(offset: number, size: number) {\n const metric = STORAGE_MONITOR.beginOp({ resource: this._fileName, type: 'delete', size });\n try {\n if (offset < 0 || size < 0) {\n return;\n }\n const fileHandle: any = await this._fileHandle;\n const writable = await fileHandle.createWritable({ keepExistingData: true });\n const file = await fileHandle.getFile();\n let leftoverSize = 0;\n if (offset + size < file.size) {\n // does not copy the buffer\n const leftover = Buffer.from(await file.slice(offset + size, file.size).arrayBuffer());\n leftoverSize = leftover.length;\n await writable.write({ type: 'write', data: leftover, position: offset });\n }\n\n await writable.write({ type: 'truncate', size: offset + leftoverSize });\n await writable.close();\n } finally {\n metric.end();\n }\n }\n\n @synchronized\n async stat() {\n const metric = STORAGE_MONITOR.beginOp({ resource: this._fileName, type: 'stat' });\n try {\n const fileHandle: any = await this._fileHandle;\n const file = await fileHandle.getFile();\n return {\n size: file.size,\n };\n } finally {\n metric.end();\n }\n }\n\n @synchronized\n async truncate(offset: number) {\n const metric = STORAGE_MONITOR.beginOp({ resource: this._fileName, type: 'truncate' });\n try {\n const fileHandle: any = await this._fileHandle;\n const writable = await fileHandle.createWritable({ keepExistingData: true });\n await writable.write({ type: 'truncate', size: offset });\n await writable.close();\n } finally {\n metric.end();\n }\n }\n\n async close(): Promise<void> {}\n\n @synchronized\n async destroy() {\n this.destroyed = true;\n return await this._destroy();\n }\n}\n", "//\n// Copyright 2023 DXOS.org\n//\n\nimport { unrefTimeout } from '@dxos/async';\n\nexport type StorageOperation = {\n resource: string;\n type: 'read' | 'write' | 'stat' | 'delete' | 'truncate';\n size?: number;\n};\n\nexport type OpHandle = {\n end: () => void;\n};\n\nexport type StatsBucket = {\n resource: string;\n beginTime: number;\n endTime: number;\n\n /**\n * Fraction of time spent in storage operations.\n */\n usage: number;\n\n readOps: number;\n readBytes: number;\n readTime: number;\n\n writeOps: number;\n writeBytes: number;\n writeTime: number;\n\n otherOps: number;\n otherTime: number;\n};\n\nconst BUCKET_COLLECTION_INTERVAL = 1_000;\n\n/**\n * Storage performance metrics.\n */\nexport class StorageMonitor {\n private _enabled = false;\n\n /**\n * By resource.\n */\n private readonly _buckets = new Map<string, StatsBucket>();\n\n enable() {\n this._enabled = true;\n\n const timer = setInterval(() => {\n this._finalizeBuckets();\n }, BUCKET_COLLECTION_INTERVAL);\n unrefTimeout(timer);\n }\n\n beginOp(op: StorageOperation): OpHandle {\n if (!this._enabled) {\n return {\n end: () => {},\n };\n }\n\n const beginTime = performance.now();\n return {\n end: () => {\n const endTime = performance.now();\n const duration = endTime - beginTime;\n\n const bucket = this._getOrInitBucket(op.resource);\n switch (op.type) {\n case 'read':\n bucket.readOps++;\n bucket.readBytes += op.size ?? 0;\n bucket.readTime += duration;\n break;\n case 'write':\n bucket.writeOps++;\n bucket.writeBytes += op.size ?? 0;\n bucket.writeTime += duration;\n break;\n default:\n bucket.otherOps++;\n bucket.otherTime += duration;\n }\n },\n };\n }\n\n private _getOrInitBucket(resource: string): StatsBucket {\n const bucket = this._buckets.get(resource);\n if (bucket) {\n return bucket;\n }\n\n const newBucket = {\n resource,\n beginTime: performance.now(),\n endTime: 0,\n usage: 0,\n readOps: 0,\n readBytes: 0,\n readTime: 0,\n writeOps: 0,\n writeBytes: 0,\n writeTime: 0,\n otherOps: 0,\n otherTime: 0,\n };\n this._buckets.set(resource, newBucket);\n return newBucket;\n }\n\n private _finalizeBuckets() {\n const now = performance.now();\n const toEmit = [];\n for (const bucket of this._buckets.values()) {\n bucket.endTime = now;\n bucket.usage = (bucket.readTime + bucket.writeTime + bucket.otherTime) / (bucket.endTime - bucket.beginTime);\n toEmit.push(bucket);\n }\n\n // Clear the buckets.\n this._buckets.clear();\n for (const bucket of toEmit) {\n this._getOrInitBucket(bucket.resource);\n }\n\n ((globalThis as any).__STORAGE_METRICS ??= []).push(...toEmit);\n }\n}\n\nexport const STORAGE_MONITOR = new StorageMonitor();\n\n// TODO(dmaretskyi): Disabled due to performance concerns.\n// STORAGE_MONITOR.enable();\n", "//\n// Copyright 2021 DXOS.org\n//\n\nimport { MemoryStorage, Storage, StorageConstructor, StorageType } from '../common';\nimport { FirefoxStorage } from './firefox-storage';\nimport { IDbStorage } from './idb-storage';\nimport { WebFS } from './web-fs';\n\nexport const createStorage: StorageConstructor = ({ type, root = '' } = {}): Storage => {\n if (type === undefined) {\n if (\n navigator &&\n navigator.storage &&\n typeof navigator.storage.getDirectory === 'function' &&\n FileSystemFileHandle &&\n typeof (FileSystemFileHandle.prototype as any).createWritable === 'function'\n ) {\n return new WebFS(root);\n } else {\n return new IDbStorage(root);\n }\n }\n\n switch (type) {\n case StorageType.RAM: {\n return new MemoryStorage(root);\n }\n\n case StorageType.IDB:\n case StorageType.CHROME: {\n return new IDbStorage(root);\n }\n\n case StorageType.FIREFOX: {\n return new FirefoxStorage(root);\n }\n\n case StorageType.WEBFS: {\n return new WebFS(root);\n }\n\n default: {\n throw new Error(`Invalid type: ${type}`);\n }\n }\n};\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["join", "inspect", "inspectObject", "log", "join", "stringDiff", "first", "second", "split", "join", "getFullPath", "root", "path", "Directory", "constructor", "type", "path", "_list", "_getOrCreateFile", "_delete", "toString", "JSON", "stringify", "createDirectory", "getFullPath", "list", "getOrCreateFile", "filename", "opts", "delete", "pify", "log", "pifyFields", "object", "type", "fields", "field", "fn", "bind", "args", "before", "performance", "now", "res", "elapsed", "warn", "operation", "wrapFile", "native", "file", "Object", "assign", "AbstractStorage", "constructor", "path", "_files", "Map", "inspect", "custom", "inspectObject", "toJSON", "type", "size", "createDirectory", "sub", "Directory", "getFullPath", "_list", "bind", "args", "getOrCreateFile", "_delete", "reset", "log", "info", "_closeFilesInPath", "_destroy", "err", "catch", "Array", "from", "_getFiles", "keys", "map", "filename", "name", "replace", "startsWith", "substring", "opts", "fullPath", "join", "native", "file", "_getFileIfExists", "closed", "_openFile", "_createFile", "wrapFile", "set", "undefined", "has", "get", "destroyed", "entries", "filter", "includes", "Promise", "all", "values", "close", "destroy", "then", "delete", "error", "message", "ram", "arrayToBuffer", "StorageType", "RAM", "IDB", "CHROME", "FIREFOX", "NODE", "WEBFS", "MemoryStorage", "AbstractStorage", "type", "StorageType", "RAM", "_createFile", "path", "filename", "_patchFile", "ram", "_openFile", "file", "newFile", "clone", "closed", "trueRead", "read", "bind", "offset", "size", "cb", "err", "data", "arrayToBuffer", "raw", "join", "BrowserStorage", "AbstractStorage", "constructor", "path", "_fileStorage", "_createFileStorage", "_createFile", "filename", "fullPath", "join", "_destroy", "Promise", "resolve", "reject", "request", "indexedDB", "deleteDatabase", "onsuccess", "onupgradeneeded", "Error", "onblocked", "onerror", "err", "FirefoxStorage", "BrowserStorage", "type", "StorageType", "FIREFOX", "_createFileStorage", "path", "raw", "name", "idb", "IDbStorage", "BrowserStorage", "type", "StorageType", "IDB", "_createFileStorage", "path", "idb", "EventEmitter", "callbackify", "invariant", "synchronized", "log", "unrefTimeout", "BUCKET_COLLECTION_INTERVAL", "StorageMonitor", "_enabled", "_buckets", "Map", "enable", "timer", "setInterval", "_finalizeBuckets", "unrefTimeout", "beginOp", "op", "end", "beginTime", "performance", "now", "_a", "endTime", "duration", "bucket", "_getOrInitBucket", "resource", "type", "readOps", "readBytes", "size", "readTime", "writeOps", "writeBytes", "writeTime", "otherOps", "otherTime", "get", "newBucket", "usage", "set", "toEmit", "values", "push", "clear", "globalThis", "__STORAGE_METRICS", "STORAGE_MONITOR", "WebFS", "constructor", "path", "type", "StorageType", "WEBFS", "_files", "Map", "size", "_getFiles", "fullName", "_getFullFilename", "entries", "filter", "file", "includes", "destroyed", "_list", "root", "_initialize", "entry", "keys", "startsWith", "push", "slice", "length", "_root", "navigator", "storage", "getDirectory", "invariant", "createDirectory", "sub", "Directory", "getFullPath", "args", "getOrCreateFile", "_delete", "filename", "opts", "existingFile", "get", "_createFile", "set", "WebFile", "fileName", "then", "getFileHandle", "create", "destroy", "delete", "removeEntry", "Promise", "all", "Array", "from", "map", "catch", "err", "log", "warn", "reset", "recursive", "undefined", "split", "join", "getDiskInfo", "used", "recurse", "handle", "promises", "values", "kind", "getFile", "f", "synchronized", "EventEmitter", "opened", "suspended", "closed", "unlinked", "writing", "readable", "writable", "deletable", "truncatable", "statable", "directory", "native", "write", "callbackify", "bind", "read", "del", "stat", "truncate", "_fileName", "_fileHandle", "_destroy", "offset", "data", "metric", "STORAGE_MONITOR", "beginOp", "resource", "fileHandle", "createWritable", "keepExistingData", "position", "close", "end", "Error", "Buffer", "arrayBuffer", "leftoverSize", "leftover", "createStorage", "type", "root", "undefined", "navigator", "storage", "getDirectory", "FileSystemFileHandle", "prototype", "createWritable", "WebFS", "IDbStorage", "StorageType", "RAM", "MemoryStorage", "IDB", "CHROME", "FIREFOX", "FirefoxStorage", "WEBFS", "Error"]
|
|
7
7
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"inputs":{"packages/common/random-access-storage/src/common/utils.ts":{"bytes":
|
|
1
|
+
{"inputs":{"packages/common/random-access-storage/src/common/utils.ts":{"bytes":1285,"imports":[{"path":"@dxos/node-std/path","kind":"import-statement","external":true}]},"packages/common/random-access-storage/src/common/directory.ts":{"bytes":4638,"imports":[{"path":"packages/common/random-access-storage/src/common/utils.ts","kind":"import-statement","original":"./utils"}]},"packages/common/random-access-storage/src/common/file.ts":{"bytes":6041,"imports":[{"path":"pify","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true}]},"packages/common/random-access-storage/src/common/abstract-storage.ts":{"bytes":14191,"imports":[{"path":"@dxos/node-std/path","kind":"import-statement","external":true},{"path":"@dxos/node-std/util","kind":"import-statement","external":true},{"path":"@dxos/debug","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true},{"path":"packages/common/random-access-storage/src/common/directory.ts","kind":"import-statement","original":"./directory"},{"path":"packages/common/random-access-storage/src/common/file.ts","kind":"import-statement","original":"./file"},{"path":"packages/common/random-access-storage/src/common/utils.ts","kind":"import-statement","original":"./utils"}]},"packages/common/random-access-storage/src/common/storage.ts":{"bytes":1856,"imports":[]},"packages/common/random-access-storage/src/common/memory-storage.ts":{"bytes":4338,"imports":[{"path":"random-access-memory","kind":"import-statement","external":true},{"path":"@dxos/util","kind":"import-statement","external":true},{"path":"packages/common/random-access-storage/src/common/abstract-storage.ts","kind":"import-statement","original":"./abstract-storage"},{"path":"packages/common/random-access-storage/src/common/storage.ts","kind":"import-statement","original":"./storage"}]},"packages/common/random-access-storage/src/common/index.ts":{"bytes":937,"imports":[{"path":"packages/common/random-access-storage/src/common/abstract-storage.ts","kind":"import-statement","original":"./abstract-storage"},{"path":"packages/common/random-access-storage/src/common/directory.ts","kind":"import-statement","original":"./directory"},{"path":"packages/common/random-access-storage/src/common/file.ts","kind":"import-statement","original":"./file"},{"path":"packages/common/random-access-storage/src/common/memory-storage.ts","kind":"import-statement","original":"./memory-storage"},{"path":"packages/common/random-access-storage/src/common/storage.ts","kind":"import-statement","original":"./storage"},{"path":"packages/common/random-access-storage/src/common/utils.ts","kind":"import-statement","original":"./utils"}]},"packages/common/random-access-storage/src/browser/browser-storage.ts":{"bytes":4369,"imports":[{"path":"@dxos/node-std/path","kind":"import-statement","external":true},{"path":"packages/common/random-access-storage/src/common/index.ts","kind":"import-statement","original":"../common"}]},"packages/common/random-access-storage/src/browser/firefox-storage.ts":{"bytes":2381,"imports":[{"path":"random-access-web/mutable-file-wrapper.js","kind":"import-statement","external":true},{"path":"packages/common/random-access-storage/src/common/index.ts","kind":"import-statement","original":"../common"},{"path":"packages/common/random-access-storage/src/browser/browser-storage.ts","kind":"import-statement","original":"./browser-storage"}]},"packages/common/random-access-storage/src/browser/idb-storage.ts":{"bytes":1789,"imports":[{"path":"random-access-idb","kind":"import-statement","external":true},{"path":"packages/common/random-access-storage/src/common/index.ts","kind":"import-statement","original":"../common"},{"path":"packages/common/random-access-storage/src/browser/browser-storage.ts","kind":"import-statement","original":"./browser-storage"}]},"packages/common/random-access-storage/src/monitor.ts":{"bytes":10173,"imports":[{"path":"@dxos/async","kind":"import-statement","external":true}]},"packages/common/random-access-storage/src/browser/web-fs.ts":{"bytes":32944,"imports":[{"path":"@dxos/node-std/events","kind":"import-statement","external":true},{"path":"@dxos/node-std/util","kind":"import-statement","external":true},{"path":"tiny-invariant","kind":"import-statement","external":true},{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true},{"path":"packages/common/random-access-storage/src/common/index.ts","kind":"import-statement","original":"../common"},{"path":"packages/common/random-access-storage/src/monitor.ts","kind":"import-statement","original":"../monitor"}]},"packages/common/random-access-storage/src/browser/storage.ts":{"bytes":4386,"imports":[{"path":"packages/common/random-access-storage/src/common/index.ts","kind":"import-statement","original":"../common"},{"path":"packages/common/random-access-storage/src/browser/firefox-storage.ts","kind":"import-statement","original":"./firefox-storage"},{"path":"packages/common/random-access-storage/src/browser/idb-storage.ts","kind":"import-statement","original":"./idb-storage"},{"path":"packages/common/random-access-storage/src/browser/web-fs.ts","kind":"import-statement","original":"./web-fs"}]},"packages/common/random-access-storage/src/browser/index.ts":{"bytes":561,"imports":[{"path":"packages/common/random-access-storage/src/common/index.ts","kind":"import-statement","original":"../common"},{"path":"packages/common/random-access-storage/src/browser/storage.ts","kind":"import-statement","original":"./storage"}]}},"outputs":{"packages/common/random-access-storage/dist/lib/browser/index.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":43766},"packages/common/random-access-storage/dist/lib/browser/index.mjs":{"imports":[{"path":"@dxos/node-std/path","kind":"import-statement","external":true},{"path":"@dxos/node-std/util","kind":"import-statement","external":true},{"path":"@dxos/debug","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true},{"path":"@dxos/node-std/path","kind":"import-statement","external":true},{"path":"pify","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true},{"path":"random-access-memory","kind":"import-statement","external":true},{"path":"@dxos/util","kind":"import-statement","external":true},{"path":"random-access-web/mutable-file-wrapper.js","kind":"import-statement","external":true},{"path":"@dxos/node-std/path","kind":"import-statement","external":true},{"path":"random-access-idb","kind":"import-statement","external":true},{"path":"@dxos/node-std/events","kind":"import-statement","external":true},{"path":"@dxos/node-std/util","kind":"import-statement","external":true},{"path":"tiny-invariant","kind":"import-statement","external":true},{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true},{"path":"@dxos/async","kind":"import-statement","external":true}],"exports":["AbstractStorage","Directory","MemoryStorage","StorageType","createStorage","getFullPath","stringDiff","wrapFile"],"entryPoint":"packages/common/random-access-storage/src/browser/index.ts","inputs":{"packages/common/random-access-storage/src/common/abstract-storage.ts":{"bytesInOutput":3338},"packages/common/random-access-storage/src/common/utils.ts":{"bytesInOutput":180},"packages/common/random-access-storage/src/common/directory.ts":{"bytesInOutput":923},"packages/common/random-access-storage/src/common/file.ts":{"bytesInOutput":1078},"packages/common/random-access-storage/src/common/index.ts":{"bytesInOutput":0},"packages/common/random-access-storage/src/common/memory-storage.ts":{"bytesInOutput":693},"packages/common/random-access-storage/src/common/storage.ts":{"bytesInOutput":288},"packages/common/random-access-storage/src/browser/index.ts":{"bytesInOutput":0},"packages/common/random-access-storage/src/browser/firefox-storage.ts":{"bytesInOutput":275},"packages/common/random-access-storage/src/browser/browser-storage.ts":{"bytesInOutput":769},"packages/common/random-access-storage/src/browser/idb-storage.ts":{"bytesInOutput":223},"packages/common/random-access-storage/src/browser/web-fs.ts":{"bytesInOutput":8412},"packages/common/random-access-storage/src/monitor.ts":{"bytesInOutput":2332},"packages/common/random-access-storage/src/browser/storage.ts":{"bytesInOutput":765}},"bytes":20556}}}
|
package/dist/lib/node/index.cjs
CHANGED
|
@@ -96,7 +96,7 @@ var Directory = class {
|
|
|
96
96
|
// packages/common/random-access-storage/src/common/file.ts
|
|
97
97
|
var import_pify = __toESM(require("pify"));
|
|
98
98
|
var import_log = require("@dxos/log");
|
|
99
|
-
var __dxlog_file = "/
|
|
99
|
+
var __dxlog_file = "/mnt/ramdisk/work/packages/common/random-access-storage/src/common/file.ts";
|
|
100
100
|
var pifyFields = (object, type, fields) => {
|
|
101
101
|
for (const field of fields) {
|
|
102
102
|
if (!object[field]) {
|
|
@@ -141,7 +141,7 @@ var wrapFile = (native, type) => {
|
|
|
141
141
|
};
|
|
142
142
|
|
|
143
143
|
// packages/common/random-access-storage/src/common/abstract-storage.ts
|
|
144
|
-
var __dxlog_file2 = "/
|
|
144
|
+
var __dxlog_file2 = "/mnt/ramdisk/work/packages/common/random-access-storage/src/common/abstract-storage.ts";
|
|
145
145
|
var AbstractStorage = class {
|
|
146
146
|
// TODO(burdon): Make required.
|
|
147
147
|
constructor(path) {
|
package/dist/lib/node/meta.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"inputs":{"packages/common/random-access-storage/src/common/utils.ts":{"bytes":
|
|
1
|
+
{"inputs":{"packages/common/random-access-storage/src/common/utils.ts":{"bytes":1285,"imports":[{"path":"node:path","kind":"import-statement","external":true}]},"packages/common/random-access-storage/src/common/directory.ts":{"bytes":4638,"imports":[{"path":"packages/common/random-access-storage/src/common/utils.ts","kind":"import-statement","original":"./utils"}]},"packages/common/random-access-storage/src/common/file.ts":{"bytes":6041,"imports":[{"path":"pify","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true}]},"packages/common/random-access-storage/src/common/abstract-storage.ts":{"bytes":14191,"imports":[{"path":"node:path","kind":"import-statement","external":true},{"path":"node:util","kind":"import-statement","external":true},{"path":"@dxos/debug","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true},{"path":"packages/common/random-access-storage/src/common/directory.ts","kind":"import-statement","original":"./directory"},{"path":"packages/common/random-access-storage/src/common/file.ts","kind":"import-statement","original":"./file"},{"path":"packages/common/random-access-storage/src/common/utils.ts","kind":"import-statement","original":"./utils"}]},"packages/common/random-access-storage/src/common/storage.ts":{"bytes":1856,"imports":[]},"packages/common/random-access-storage/src/common/memory-storage.ts":{"bytes":4338,"imports":[{"path":"random-access-memory","kind":"import-statement","external":true},{"path":"@dxos/util","kind":"import-statement","external":true},{"path":"packages/common/random-access-storage/src/common/abstract-storage.ts","kind":"import-statement","original":"./abstract-storage"},{"path":"packages/common/random-access-storage/src/common/storage.ts","kind":"import-statement","original":"./storage"}]},"packages/common/random-access-storage/src/common/index.ts":{"bytes":937,"imports":[{"path":"packages/common/random-access-storage/src/common/abstract-storage.ts","kind":"import-statement","original":"./abstract-storage"},{"path":"packages/common/random-access-storage/src/common/directory.ts","kind":"import-statement","original":"./directory"},{"path":"packages/common/random-access-storage/src/common/file.ts","kind":"import-statement","original":"./file"},{"path":"packages/common/random-access-storage/src/common/memory-storage.ts","kind":"import-statement","original":"./memory-storage"},{"path":"packages/common/random-access-storage/src/common/storage.ts","kind":"import-statement","original":"./storage"},{"path":"packages/common/random-access-storage/src/common/utils.ts","kind":"import-statement","original":"./utils"}]},"packages/common/random-access-storage/src/node/node-storage.ts":{"bytes":4777,"imports":[{"path":"del","kind":"import-statement","external":true},{"path":"node:fs/promises","kind":"import-statement","external":true},{"path":"node:path","kind":"import-statement","external":true},{"path":"random-access-file","kind":"import-statement","external":true},{"path":"packages/common/random-access-storage/src/common/index.ts","kind":"import-statement","original":"../common"}]},"packages/common/random-access-storage/src/node/storage.ts":{"bytes":2415,"imports":[{"path":"packages/common/random-access-storage/src/common/index.ts","kind":"import-statement","original":"../common"},{"path":"packages/common/random-access-storage/src/node/node-storage.ts","kind":"import-statement","original":"./node-storage"}]},"packages/common/random-access-storage/src/node/index.ts":{"bytes":558,"imports":[{"path":"packages/common/random-access-storage/src/common/index.ts","kind":"import-statement","original":"../common"},{"path":"packages/common/random-access-storage/src/node/storage.ts","kind":"import-statement","original":"./storage"}]},"packages/common/random-access-storage/src/index.ts":{"bytes":459,"imports":[{"path":"packages/common/random-access-storage/src/node/index.ts","kind":"import-statement","original":"./node"}]}},"outputs":{"packages/common/random-access-storage/dist/lib/node/index.cjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":19901},"packages/common/random-access-storage/dist/lib/node/index.cjs":{"imports":[{"path":"node:path","kind":"require-call","external":true},{"path":"node:util","kind":"require-call","external":true},{"path":"@dxos/debug","kind":"require-call","external":true},{"path":"@dxos/log","kind":"require-call","external":true},{"path":"node:path","kind":"require-call","external":true},{"path":"pify","kind":"require-call","external":true},{"path":"@dxos/log","kind":"require-call","external":true},{"path":"random-access-memory","kind":"require-call","external":true},{"path":"@dxos/util","kind":"require-call","external":true},{"path":"del","kind":"require-call","external":true},{"path":"node:fs/promises","kind":"require-call","external":true},{"path":"node:path","kind":"require-call","external":true},{"path":"random-access-file","kind":"require-call","external":true}],"exports":[],"entryPoint":"packages/common/random-access-storage/src/index.ts","inputs":{"packages/common/random-access-storage/src/index.ts":{"bytesInOutput":369},"packages/common/random-access-storage/src/common/abstract-storage.ts":{"bytesInOutput":3443},"packages/common/random-access-storage/src/common/utils.ts":{"bytesInOutput":203},"packages/common/random-access-storage/src/common/directory.ts":{"bytesInOutput":923},"packages/common/random-access-storage/src/common/file.ts":{"bytesInOutput":1134},"packages/common/random-access-storage/src/common/index.ts":{"bytesInOutput":0},"packages/common/random-access-storage/src/common/memory-storage.ts":{"bytesInOutput":780},"packages/common/random-access-storage/src/common/storage.ts":{"bytesInOutput":288},"packages/common/random-access-storage/src/node/index.ts":{"bytesInOutput":0},"packages/common/random-access-storage/src/node/node-storage.ts":{"bytesInOutput":1114},"packages/common/random-access-storage/src/node/storage.ts":{"bytesInOutput":369}},"bytes":10991}}}
|
|
@@ -35,10 +35,12 @@ export declare class WebFile extends EventEmitter implements File {
|
|
|
35
35
|
readonly deletable: boolean;
|
|
36
36
|
readonly truncatable: boolean;
|
|
37
37
|
readonly statable: boolean;
|
|
38
|
+
private readonly _fileName;
|
|
38
39
|
private readonly _fileHandle;
|
|
39
40
|
private readonly _destroy;
|
|
40
|
-
constructor({ file, destroy }: {
|
|
41
|
+
constructor({ fileName, file, destroy, }: {
|
|
41
42
|
file: Promise<FileSystemFileHandle>;
|
|
43
|
+
fileName: string;
|
|
42
44
|
destroy: () => Promise<void>;
|
|
43
45
|
});
|
|
44
46
|
destroyed: boolean;
|
|
@@ -52,8 +54,8 @@ export declare class WebFile extends EventEmitter implements File {
|
|
|
52
54
|
stat(): Promise<{
|
|
53
55
|
size: any;
|
|
54
56
|
}>;
|
|
57
|
+
truncate(offset: number): Promise<void>;
|
|
55
58
|
close(): Promise<void>;
|
|
56
59
|
destroy(): Promise<void>;
|
|
57
|
-
truncate(offset: number): Promise<void>;
|
|
58
60
|
}
|
|
59
61
|
//# sourceMappingURL=web-fs.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"web-fs.d.ts","sourceRoot":"","sources":["../../../../src/browser/web-fs.ts"],"names":[],"mappings":";;AAIA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAM5D,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,EAAE,WAAW,EAAe,QAAQ,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"web-fs.d.ts","sourceRoot":"","sources":["../../../../src/browser/web-fs.ts"],"names":[],"mappings":";;AAIA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAM5D,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,EAAE,WAAW,EAAe,QAAQ,EAAE,MAAM,WAAW,CAAC;AAGzF;;GAEG;AACH,qBAAa,KAAM,YAAW,OAAO;aAMP,IAAI,EAAE,MAAM;IALxC,QAAQ,CAAC,IAAI,qBAAqB;IAElC,SAAS,CAAC,QAAQ,CAAC,MAAM,oBAA2B;IACpD,SAAS,CAAC,KAAK,CAAC,EAAE,yBAAyB,CAAC;gBAEhB,IAAI,EAAE,MAAM;IAExC,IAAW,IAAI,WAEd;IAED,OAAO,CAAC,SAAS;YAOH,KAAK;YAwBL,WAAW;IASzB,eAAe,CAAC,GAAG,SAAK;IAUxB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,GAAG,GAAG,IAAI;IAWjE,OAAO,CAAC,WAAW;YAYL,OAAO;IASf,KAAK;IASX,OAAO,CAAC,gBAAgB;IASlB,WAAW,IAAI,OAAO,CAAC,QAAQ,CAAC;CA6BvC;AAGD,qBAAa,OAAQ,SAAQ,YAAa,YAAW,IAAI;IACvD,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAQ;IAChC,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAS;IACpC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAS;IACjC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAS;IACnC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAS;IAClC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAQ;IAClC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAQ;IAClC,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAQ;IACnC,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAQ;IACrC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAQ;IAClC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IAEnC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAgC;IAC5D,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAsB;gBAEnC,EACV,QAAQ,EACR,IAAI,EACJ,OAAO,GACR,EAAE;QACD,IAAI,EAAE,OAAO,CAAC,oBAAoB,CAAC,CAAC;QACpC,QAAQ,EAAE,MAAM,CAAC;QACjB,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;KAC9B;IAOD,SAAS,UAAS;IAClB,SAAS,SAAM;IAEf,QAAQ,SAAM;IACd,IAAI,EAAE,WAAW,CAAqB;IACtC,MAAM,EAAE,mBAAmB,CAOF;IAGnB,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM;IAclC,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM;IAgBjC,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM;IAyBhC,IAAI;;;IAcJ,QAAQ,CAAC,MAAM,EAAE,MAAM;IAYvB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAGtB,OAAO;CAId"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
export type StorageOperation = {
|
|
2
|
+
resource: string;
|
|
3
|
+
type: 'read' | 'write' | 'stat' | 'delete' | 'truncate';
|
|
4
|
+
size?: number;
|
|
5
|
+
};
|
|
6
|
+
export type OpHandle = {
|
|
7
|
+
end: () => void;
|
|
8
|
+
};
|
|
9
|
+
export type StatsBucket = {
|
|
10
|
+
resource: string;
|
|
11
|
+
beginTime: number;
|
|
12
|
+
endTime: number;
|
|
13
|
+
/**
|
|
14
|
+
* Fraction of time spent in storage operations.
|
|
15
|
+
*/
|
|
16
|
+
usage: number;
|
|
17
|
+
readOps: number;
|
|
18
|
+
readBytes: number;
|
|
19
|
+
readTime: number;
|
|
20
|
+
writeOps: number;
|
|
21
|
+
writeBytes: number;
|
|
22
|
+
writeTime: number;
|
|
23
|
+
otherOps: number;
|
|
24
|
+
otherTime: number;
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* Storage performance metrics.
|
|
28
|
+
*/
|
|
29
|
+
export declare class StorageMonitor {
|
|
30
|
+
private _enabled;
|
|
31
|
+
/**
|
|
32
|
+
* By resource.
|
|
33
|
+
*/
|
|
34
|
+
private readonly _buckets;
|
|
35
|
+
enable(): void;
|
|
36
|
+
beginOp(op: StorageOperation): OpHandle;
|
|
37
|
+
private _getOrInitBucket;
|
|
38
|
+
private _finalizeBuckets;
|
|
39
|
+
}
|
|
40
|
+
export declare const STORAGE_MONITOR: StorageMonitor;
|
|
41
|
+
//# sourceMappingURL=monitor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"monitor.d.ts","sourceRoot":"","sources":["../../../src/monitor.ts"],"names":[],"mappings":"AAMA,MAAM,MAAM,gBAAgB,GAAG;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,QAAQ,GAAG,UAAU,CAAC;IACxD,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,QAAQ,GAAG;IACrB,GAAG,EAAE,MAAM,IAAI,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAEhB;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IAEd,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IAEjB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAElB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAIF;;GAEG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAS;IAEzB;;OAEG;IACH,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAkC;IAE3D,MAAM;IASN,OAAO,CAAC,EAAE,EAAE,gBAAgB,GAAG,QAAQ;IAiCvC,OAAO,CAAC,gBAAgB;IAwBxB,OAAO,CAAC,gBAAgB;CAiBzB;AAED,eAAO,MAAM,eAAe,gBAAuB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dxos/random-access-storage",
|
|
3
|
-
"version": "0.1.55
|
|
3
|
+
"version": "0.1.55",
|
|
4
4
|
"description": "Multiple random storage types.",
|
|
5
5
|
"homepage": "https://dxos.org",
|
|
6
6
|
"bugs": "https://github.com/dxos/dxos/issues",
|
|
@@ -25,11 +25,11 @@
|
|
|
25
25
|
"random-access-storage": "^3.0.0",
|
|
26
26
|
"random-access-web": "^2.0.3",
|
|
27
27
|
"tiny-invariant": "^1.3.1",
|
|
28
|
-
"@dxos/async": "0.1.55
|
|
29
|
-
"@dxos/debug": "0.1.55
|
|
30
|
-
"@dxos/log": "0.1.55
|
|
31
|
-
"@dxos/node-std": "0.1.55
|
|
32
|
-
"@dxos/util": "0.1.55
|
|
28
|
+
"@dxos/async": "0.1.55",
|
|
29
|
+
"@dxos/debug": "0.1.55",
|
|
30
|
+
"@dxos/log": "0.1.55",
|
|
31
|
+
"@dxos/node-std": "0.1.55",
|
|
32
|
+
"@dxos/util": "0.1.55"
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
35
|
"@types/pify": "^3.0.2",
|
package/src/browser/web-fs.ts
CHANGED
|
@@ -11,6 +11,7 @@ import { synchronized } from '@dxos/async';
|
|
|
11
11
|
import { log } from '@dxos/log';
|
|
12
12
|
|
|
13
13
|
import { Directory, File, Storage, StorageType, getFullPath, DiskInfo } from '../common';
|
|
14
|
+
import { STORAGE_MONITOR } from '../monitor';
|
|
14
15
|
|
|
15
16
|
/**
|
|
16
17
|
* Web file systems.
|
|
@@ -90,6 +91,7 @@ export class WebFS implements Storage {
|
|
|
90
91
|
|
|
91
92
|
private _createFile(fullName: string) {
|
|
92
93
|
return new WebFile({
|
|
94
|
+
fileName: fullName,
|
|
93
95
|
file: this._initialize().then((root) => root.getFileHandle(fullName, { create: true })),
|
|
94
96
|
destroy: async () => {
|
|
95
97
|
this._files.delete(fullName);
|
|
@@ -169,18 +171,29 @@ export class WebFile extends EventEmitter implements File {
|
|
|
169
171
|
readonly deletable: boolean = true;
|
|
170
172
|
readonly truncatable: boolean = true;
|
|
171
173
|
readonly statable: boolean = true;
|
|
174
|
+
private readonly _fileName: string;
|
|
172
175
|
|
|
173
176
|
private readonly _fileHandle: Promise<FileSystemFileHandle>;
|
|
174
177
|
private readonly _destroy: () => Promise<void>;
|
|
175
178
|
|
|
176
|
-
constructor({
|
|
179
|
+
constructor({
|
|
180
|
+
fileName,
|
|
181
|
+
file,
|
|
182
|
+
destroy,
|
|
183
|
+
}: {
|
|
184
|
+
file: Promise<FileSystemFileHandle>;
|
|
185
|
+
fileName: string;
|
|
186
|
+
destroy: () => Promise<void>;
|
|
187
|
+
}) {
|
|
177
188
|
super();
|
|
189
|
+
this._fileName = fileName;
|
|
178
190
|
this._fileHandle = file;
|
|
179
191
|
this._destroy = destroy;
|
|
180
192
|
}
|
|
181
193
|
|
|
182
194
|
destroyed = false;
|
|
183
195
|
directory = '';
|
|
196
|
+
// TODO(dmaretskyi): is this used?
|
|
184
197
|
filename = '';
|
|
185
198
|
type: StorageType = StorageType.WEBFS;
|
|
186
199
|
native: RandomAccessStorage = {
|
|
@@ -194,51 +207,84 @@ export class WebFile extends EventEmitter implements File {
|
|
|
194
207
|
|
|
195
208
|
@synchronized
|
|
196
209
|
async write(offset: number, data: Buffer) {
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
210
|
+
const metric = STORAGE_MONITOR.beginOp({ resource: this._fileName, type: 'write', size: data.length });
|
|
211
|
+
try {
|
|
212
|
+
// TODO(mykola): Fix types.
|
|
213
|
+
const fileHandle: any = await this._fileHandle;
|
|
214
|
+
const writable = await fileHandle.createWritable({ keepExistingData: true });
|
|
215
|
+
await writable.write({ type: 'write', data, position: offset });
|
|
216
|
+
await writable.close();
|
|
217
|
+
} finally {
|
|
218
|
+
metric.end();
|
|
219
|
+
}
|
|
202
220
|
}
|
|
203
221
|
|
|
204
222
|
@synchronized
|
|
205
223
|
async read(offset: number, size: number) {
|
|
206
|
-
const
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
224
|
+
const metric = STORAGE_MONITOR.beginOp({ resource: this._fileName, type: 'read', size });
|
|
225
|
+
try {
|
|
226
|
+
const fileHandle: any = await this._fileHandle;
|
|
227
|
+
const file = await fileHandle.getFile();
|
|
228
|
+
if (offset + size > file.size) {
|
|
229
|
+
throw new Error('Read out of bounds');
|
|
230
|
+
}
|
|
231
|
+
// does not copy the buffer
|
|
232
|
+
return Buffer.from(await file.slice(offset, offset + size).arrayBuffer());
|
|
233
|
+
} finally {
|
|
234
|
+
metric.end();
|
|
210
235
|
}
|
|
211
|
-
// does not copy the buffer
|
|
212
|
-
return Buffer.from(await file.slice(offset, offset + size).arrayBuffer());
|
|
213
236
|
}
|
|
214
237
|
|
|
215
238
|
@synchronized
|
|
216
239
|
async del(offset: number, size: number) {
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
240
|
+
const metric = STORAGE_MONITOR.beginOp({ resource: this._fileName, type: 'delete', size });
|
|
241
|
+
try {
|
|
242
|
+
if (offset < 0 || size < 0) {
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
const fileHandle: any = await this._fileHandle;
|
|
246
|
+
const writable = await fileHandle.createWritable({ keepExistingData: true });
|
|
247
|
+
const file = await fileHandle.getFile();
|
|
248
|
+
let leftoverSize = 0;
|
|
249
|
+
if (offset + size < file.size) {
|
|
250
|
+
// does not copy the buffer
|
|
251
|
+
const leftover = Buffer.from(await file.slice(offset + size, file.size).arrayBuffer());
|
|
252
|
+
leftoverSize = leftover.length;
|
|
253
|
+
await writable.write({ type: 'write', data: leftover, position: offset });
|
|
254
|
+
}
|
|
230
255
|
|
|
231
|
-
|
|
232
|
-
|
|
256
|
+
await writable.write({ type: 'truncate', size: offset + leftoverSize });
|
|
257
|
+
await writable.close();
|
|
258
|
+
} finally {
|
|
259
|
+
metric.end();
|
|
260
|
+
}
|
|
233
261
|
}
|
|
234
262
|
|
|
235
263
|
@synchronized
|
|
236
264
|
async stat() {
|
|
237
|
-
const
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
265
|
+
const metric = STORAGE_MONITOR.beginOp({ resource: this._fileName, type: 'stat' });
|
|
266
|
+
try {
|
|
267
|
+
const fileHandle: any = await this._fileHandle;
|
|
268
|
+
const file = await fileHandle.getFile();
|
|
269
|
+
return {
|
|
270
|
+
size: file.size,
|
|
271
|
+
};
|
|
272
|
+
} finally {
|
|
273
|
+
metric.end();
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
@synchronized
|
|
278
|
+
async truncate(offset: number) {
|
|
279
|
+
const metric = STORAGE_MONITOR.beginOp({ resource: this._fileName, type: 'truncate' });
|
|
280
|
+
try {
|
|
281
|
+
const fileHandle: any = await this._fileHandle;
|
|
282
|
+
const writable = await fileHandle.createWritable({ keepExistingData: true });
|
|
283
|
+
await writable.write({ type: 'truncate', size: offset });
|
|
284
|
+
await writable.close();
|
|
285
|
+
} finally {
|
|
286
|
+
metric.end();
|
|
287
|
+
}
|
|
242
288
|
}
|
|
243
289
|
|
|
244
290
|
async close(): Promise<void> {}
|
|
@@ -248,12 +294,4 @@ export class WebFile extends EventEmitter implements File {
|
|
|
248
294
|
this.destroyed = true;
|
|
249
295
|
return await this._destroy();
|
|
250
296
|
}
|
|
251
|
-
|
|
252
|
-
@synchronized
|
|
253
|
-
async truncate(offset: number) {
|
|
254
|
-
const fileHandle: any = await this._fileHandle;
|
|
255
|
-
const writable = await fileHandle.createWritable({ keepExistingData: true });
|
|
256
|
-
await writable.write({ type: 'truncate', size: offset });
|
|
257
|
-
await writable.close();
|
|
258
|
-
}
|
|
259
297
|
}
|
package/src/monitor.ts
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2023 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { unrefTimeout } from '@dxos/async';
|
|
6
|
+
|
|
7
|
+
export type StorageOperation = {
|
|
8
|
+
resource: string;
|
|
9
|
+
type: 'read' | 'write' | 'stat' | 'delete' | 'truncate';
|
|
10
|
+
size?: number;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export type OpHandle = {
|
|
14
|
+
end: () => void;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export type StatsBucket = {
|
|
18
|
+
resource: string;
|
|
19
|
+
beginTime: number;
|
|
20
|
+
endTime: number;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Fraction of time spent in storage operations.
|
|
24
|
+
*/
|
|
25
|
+
usage: number;
|
|
26
|
+
|
|
27
|
+
readOps: number;
|
|
28
|
+
readBytes: number;
|
|
29
|
+
readTime: number;
|
|
30
|
+
|
|
31
|
+
writeOps: number;
|
|
32
|
+
writeBytes: number;
|
|
33
|
+
writeTime: number;
|
|
34
|
+
|
|
35
|
+
otherOps: number;
|
|
36
|
+
otherTime: number;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const BUCKET_COLLECTION_INTERVAL = 1_000;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Storage performance metrics.
|
|
43
|
+
*/
|
|
44
|
+
export class StorageMonitor {
|
|
45
|
+
private _enabled = false;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* By resource.
|
|
49
|
+
*/
|
|
50
|
+
private readonly _buckets = new Map<string, StatsBucket>();
|
|
51
|
+
|
|
52
|
+
enable() {
|
|
53
|
+
this._enabled = true;
|
|
54
|
+
|
|
55
|
+
const timer = setInterval(() => {
|
|
56
|
+
this._finalizeBuckets();
|
|
57
|
+
}, BUCKET_COLLECTION_INTERVAL);
|
|
58
|
+
unrefTimeout(timer);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
beginOp(op: StorageOperation): OpHandle {
|
|
62
|
+
if (!this._enabled) {
|
|
63
|
+
return {
|
|
64
|
+
end: () => {},
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const beginTime = performance.now();
|
|
69
|
+
return {
|
|
70
|
+
end: () => {
|
|
71
|
+
const endTime = performance.now();
|
|
72
|
+
const duration = endTime - beginTime;
|
|
73
|
+
|
|
74
|
+
const bucket = this._getOrInitBucket(op.resource);
|
|
75
|
+
switch (op.type) {
|
|
76
|
+
case 'read':
|
|
77
|
+
bucket.readOps++;
|
|
78
|
+
bucket.readBytes += op.size ?? 0;
|
|
79
|
+
bucket.readTime += duration;
|
|
80
|
+
break;
|
|
81
|
+
case 'write':
|
|
82
|
+
bucket.writeOps++;
|
|
83
|
+
bucket.writeBytes += op.size ?? 0;
|
|
84
|
+
bucket.writeTime += duration;
|
|
85
|
+
break;
|
|
86
|
+
default:
|
|
87
|
+
bucket.otherOps++;
|
|
88
|
+
bucket.otherTime += duration;
|
|
89
|
+
}
|
|
90
|
+
},
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
private _getOrInitBucket(resource: string): StatsBucket {
|
|
95
|
+
const bucket = this._buckets.get(resource);
|
|
96
|
+
if (bucket) {
|
|
97
|
+
return bucket;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const newBucket = {
|
|
101
|
+
resource,
|
|
102
|
+
beginTime: performance.now(),
|
|
103
|
+
endTime: 0,
|
|
104
|
+
usage: 0,
|
|
105
|
+
readOps: 0,
|
|
106
|
+
readBytes: 0,
|
|
107
|
+
readTime: 0,
|
|
108
|
+
writeOps: 0,
|
|
109
|
+
writeBytes: 0,
|
|
110
|
+
writeTime: 0,
|
|
111
|
+
otherOps: 0,
|
|
112
|
+
otherTime: 0,
|
|
113
|
+
};
|
|
114
|
+
this._buckets.set(resource, newBucket);
|
|
115
|
+
return newBucket;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
private _finalizeBuckets() {
|
|
119
|
+
const now = performance.now();
|
|
120
|
+
const toEmit = [];
|
|
121
|
+
for (const bucket of this._buckets.values()) {
|
|
122
|
+
bucket.endTime = now;
|
|
123
|
+
bucket.usage = (bucket.readTime + bucket.writeTime + bucket.otherTime) / (bucket.endTime - bucket.beginTime);
|
|
124
|
+
toEmit.push(bucket);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Clear the buckets.
|
|
128
|
+
this._buckets.clear();
|
|
129
|
+
for (const bucket of toEmit) {
|
|
130
|
+
this._getOrInitBucket(bucket.resource);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
((globalThis as any).__STORAGE_METRICS ??= []).push(...toEmit);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export const STORAGE_MONITOR = new StorageMonitor();
|
|
138
|
+
|
|
139
|
+
// TODO(dmaretskyi): Disabled due to performance concerns.
|
|
140
|
+
// STORAGE_MONITOR.enable();
|