sliftutils 1.3.0 → 1.4.0
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/index.d.ts +147 -14
- package/package.json +1 -1
- package/storage/BulkDatabase2/BulkDatabase2.d.ts +84 -2
- package/storage/BulkDatabase2/BulkDatabase2.ts +76 -2
- package/storage/BulkDatabase2/BulkDatabaseBase.d.ts +29 -8
- package/storage/BulkDatabase2/BulkDatabaseBase.ts +565 -246
- package/storage/BulkDatabase2/BulkDatabaseFormat.d.ts +26 -3
- package/storage/BulkDatabase2/BulkDatabaseFormat.ts +124 -33
- package/storage/BulkDatabase2/mergeLock.d.ts +2 -0
- package/storage/BulkDatabase2/mergeLock.ts +48 -0
- package/storage/BulkDatabase2/streamLog.ts +21 -9
- package/storage/BulkDatabase2/syncClient.d.ts +2 -1
- package/storage/BulkDatabase2/syncClient.ts +19 -2
- package/storage/FileFolderAPI.tsx +6 -1
- package/yarn.lock +2213 -2213
package/index.d.ts
CHANGED
|
@@ -764,11 +764,93 @@ declare module "sliftutils/render-utils/observer" {
|
|
|
764
764
|
|
|
765
765
|
declare module "sliftutils/storage/BulkDatabase2/BulkDatabase2" {
|
|
766
766
|
import { BulkDatabaseBase } from "./BulkDatabaseBase";
|
|
767
|
-
export { BulkDatabaseBase, noopReactiveDeps } from "./BulkDatabaseBase";
|
|
767
|
+
export { BulkDatabaseBase, noopReactiveDeps, bulkDatabase2Timing } from "./BulkDatabaseBase";
|
|
768
768
|
export type { ReactiveDeps, StorageFactory } from "./BulkDatabaseBase";
|
|
769
|
+
/** Per-column on-disk size info, as reported by getColumnInfo/getReaderInfo. */
|
|
770
|
+
export type BulkColumnInfo = {
|
|
771
|
+
column: string;
|
|
772
|
+
byteSize: number;
|
|
773
|
+
};
|
|
774
|
+
/** A snapshot of the collection's shape (no row data), as reported by getReaderInfo. */
|
|
775
|
+
export type BulkReaderInfo = {
|
|
776
|
+
rowCount: number;
|
|
777
|
+
totalBytes: number;
|
|
778
|
+
keyCount: number;
|
|
779
|
+
sampleKey: string | undefined;
|
|
780
|
+
columns: BulkColumnInfo[];
|
|
781
|
+
};
|
|
782
|
+
/**
|
|
783
|
+
* The full public API of BulkDatabase2 (the static `clearCache()` aside). BulkDatabase2 implements
|
|
784
|
+
* this; an application that just wants to depend on the surface can type against this interface instead
|
|
785
|
+
* of reading the implementation. `T` is the row type and must have a string `key`.
|
|
786
|
+
*
|
|
787
|
+
* Reads resolve every key/column by the latest write-time across all storage tiers. Writes are
|
|
788
|
+
* column-merges: a write/update only changes the columns it includes; columns it omits keep their
|
|
789
|
+
* previous value (clear a column by writing it as `undefined`).
|
|
790
|
+
*/
|
|
791
|
+
export interface IBulkDatabase2<T extends {
|
|
792
|
+
key: string;
|
|
793
|
+
}> {
|
|
794
|
+
/** The collection name (its folder under the storage root). */
|
|
795
|
+
readonly name: string;
|
|
796
|
+
/** Write one full row (merging its columns onto any existing row for the key). */
|
|
797
|
+
write(entry: T): Promise<void>;
|
|
798
|
+
/** Write many full rows in one batch. */
|
|
799
|
+
writeBatch(entries: T[]): Promise<void>;
|
|
800
|
+
/** Update only the given columns of an existing key (key required). Warns and no-ops if the key isn't present. */
|
|
801
|
+
update(entry: Partial<T> & {
|
|
802
|
+
key: string;
|
|
803
|
+
}): Promise<void>;
|
|
804
|
+
/** Update many keys' partial columns in one batch. */
|
|
805
|
+
updateBatch(entries: (Partial<T> & {
|
|
806
|
+
key: string;
|
|
807
|
+
})[]): Promise<void>;
|
|
808
|
+
/** Delete a key. */
|
|
809
|
+
delete(key: string): Promise<void>;
|
|
810
|
+
/** Delete many keys in one batch. */
|
|
811
|
+
deleteBatch(keys: string[]): Promise<void>;
|
|
812
|
+
/** All live keys. */
|
|
813
|
+
getKeys(): Promise<string[]>;
|
|
814
|
+
/** One field's value for a key, or undefined if the key/column isn't set or the key is deleted. */
|
|
815
|
+
getSingleField<Column extends keyof T>(key: string, column: Column): Promise<T[Column] | undefined>;
|
|
816
|
+
/** A whole column as {key, value} for every live key. */
|
|
817
|
+
getColumn<Column extends keyof T>(column: Column): Promise<{
|
|
818
|
+
key: string;
|
|
819
|
+
value: T[Column];
|
|
820
|
+
}[]>;
|
|
821
|
+
/**
|
|
822
|
+
* Synchronous, reactive read of one field. Returns undefined while the base value is still loading
|
|
823
|
+
* (and re-renders once it arrives, under a mobx observer); reflects pending writes immediately.
|
|
824
|
+
*/
|
|
825
|
+
getSingleFieldSync<Column extends keyof T>(key: string, column: Column): T[Column] | undefined;
|
|
826
|
+
/** Synchronous, reactive read of a whole column. undefined while still loading. */
|
|
827
|
+
getColumnSync<Column extends keyof T>(column: Column): {
|
|
828
|
+
key: string;
|
|
829
|
+
value: T[Column];
|
|
830
|
+
}[] | undefined;
|
|
831
|
+
/** The columns present on disk and their byte sizes (no row data read). */
|
|
832
|
+
getColumnInfo(): Promise<BulkColumnInfo[]>;
|
|
833
|
+
/** A cheap snapshot of the collection's shape (row/key counts, total bytes, columns) — no row data. */
|
|
834
|
+
getReaderInfo(): Promise<BulkReaderInfo>;
|
|
835
|
+
/** Consolidate on-disk files. Optional to call; the database also does this in the background. */
|
|
836
|
+
compact(): Promise<void>;
|
|
837
|
+
/**
|
|
838
|
+
* Run one merge pass now (the same policy the database runs on a timer): consolidate recent
|
|
839
|
+
* fragmentation and dedup a key range if it's worth it. Returns whether it merged anything and
|
|
840
|
+
* whether it bailed because another tab/process holds the merge lock — so a scheduler can call this
|
|
841
|
+
* (e.g. every 30 minutes) and tell "nothing to do" from "someone else is already merging".
|
|
842
|
+
*/
|
|
843
|
+
tryMergeNow(): Promise<{
|
|
844
|
+
merged: boolean;
|
|
845
|
+
lockFailed: boolean;
|
|
846
|
+
}>;
|
|
847
|
+
/** Rewrite everything written in [timeLo, timeHi] into fresh key-sorted bulk file(s). Low-level;
|
|
848
|
+
* most callers want compact() or tryMergeNow(). */
|
|
849
|
+
merge(timeLo: number, timeHi: number): Promise<void>;
|
|
850
|
+
}
|
|
769
851
|
export declare class BulkDatabase2<T extends {
|
|
770
852
|
key: string;
|
|
771
|
-
}> extends BulkDatabaseBase<T> {
|
|
853
|
+
}> extends BulkDatabaseBase<T> implements IBulkDatabase2<T> {
|
|
772
854
|
constructor(name: string);
|
|
773
855
|
}
|
|
774
856
|
|
|
@@ -776,6 +858,12 @@ declare module "sliftutils/storage/BulkDatabase2/BulkDatabase2" {
|
|
|
776
858
|
|
|
777
859
|
declare module "sliftutils/storage/BulkDatabase2/BulkDatabaseBase" {
|
|
778
860
|
import type { FileStorage } from "../FileFolderAPI";
|
|
861
|
+
export declare const bulkDatabase2Timing: {
|
|
862
|
+
streamSealAgeMs: number;
|
|
863
|
+
mergeCheckIntervalMs: number;
|
|
864
|
+
firstMergeTriggerFiles: number;
|
|
865
|
+
firstMergeTriggerRangeMs: number;
|
|
866
|
+
};
|
|
779
867
|
export interface ReactiveDeps {
|
|
780
868
|
observe(signal: string): void;
|
|
781
869
|
invalidate(signal: string): void;
|
|
@@ -799,10 +887,13 @@ declare module "sliftutils/storage/BulkDatabase2/BulkDatabaseBase" {
|
|
|
799
887
|
private overlay;
|
|
800
888
|
private streamTimes;
|
|
801
889
|
private streamFileName;
|
|
802
|
-
private
|
|
890
|
+
private lastMergeCheck;
|
|
803
891
|
private getStreamFileName;
|
|
804
|
-
private
|
|
892
|
+
private invalidateOverlay;
|
|
893
|
+
private setOverlayRow;
|
|
894
|
+
private setOverlayDeleted;
|
|
805
895
|
private reader;
|
|
896
|
+
private buildReader;
|
|
806
897
|
private syncSetup;
|
|
807
898
|
private localTime;
|
|
808
899
|
private applyRemote;
|
|
@@ -811,20 +902,32 @@ declare module "sliftutils/storage/BulkDatabase2/BulkDatabaseBase" {
|
|
|
811
902
|
writeBatch(entries: T[]): Promise<void>;
|
|
812
903
|
delete(key: string): Promise<void>;
|
|
813
904
|
deleteBatch(keys: string[]): Promise<void>;
|
|
905
|
+
update(entry: Partial<T> & {
|
|
906
|
+
key: string;
|
|
907
|
+
}): Promise<void>;
|
|
908
|
+
updateBatch(entries: (Partial<T> & {
|
|
909
|
+
key: string;
|
|
910
|
+
})[]): Promise<void>;
|
|
911
|
+
private listFiles;
|
|
814
912
|
private writeBulkFile;
|
|
815
|
-
private listStreamFiles;
|
|
816
913
|
private loadStreamEntries;
|
|
817
914
|
private orderStreamEntries;
|
|
818
|
-
private
|
|
819
|
-
|
|
915
|
+
private maybeMerge;
|
|
916
|
+
tryMergeNow(): Promise<{
|
|
917
|
+
merged: boolean;
|
|
918
|
+
lockFailed: boolean;
|
|
919
|
+
}>;
|
|
820
920
|
compact(): Promise<void>;
|
|
821
|
-
|
|
921
|
+
merge(timeLo: number, timeHi: number): Promise<void>;
|
|
822
922
|
private makeRawGetRange;
|
|
823
923
|
private loadFileReader;
|
|
924
|
+
private readBulkHeader;
|
|
824
925
|
private fileLogicalSize;
|
|
825
926
|
private handleUnreadableFile;
|
|
826
|
-
private
|
|
827
|
-
private
|
|
927
|
+
private resolveReaders;
|
|
928
|
+
private mergeFileSet;
|
|
929
|
+
private canDeleteStream;
|
|
930
|
+
private testMerge;
|
|
828
931
|
private formatInfo;
|
|
829
932
|
private patchColumn;
|
|
830
933
|
getSingleField<Column extends keyof T>(key: string, column: Column): Promise<T[Column] | undefined>;
|
|
@@ -867,22 +970,45 @@ declare module "sliftutils/storage/BulkDatabase2/BulkDatabaseFormat" {
|
|
|
867
970
|
/// <reference types="node" />
|
|
868
971
|
export declare const KEY_COLUMN = "key";
|
|
869
972
|
export declare const EMPTY_BUFFER: Buffer;
|
|
870
|
-
export declare
|
|
973
|
+
export declare const ABSENT: unique symbol;
|
|
974
|
+
export declare const TARGET_FILE_BYTES: number;
|
|
975
|
+
export declare function buildFileBuffer(rows: Record<string, unknown>[], times: number[], targetBytes?: number): Buffer[];
|
|
871
976
|
export type BaseBulkDatabaseReader = {
|
|
872
977
|
rowCount: number;
|
|
873
978
|
totalBytes: number;
|
|
979
|
+
minTime: number;
|
|
980
|
+
maxTime: number;
|
|
981
|
+
minKey?: string;
|
|
982
|
+
maxKey?: string;
|
|
874
983
|
keys: string[];
|
|
875
984
|
columns: {
|
|
876
985
|
column: string;
|
|
877
986
|
byteSize: number;
|
|
878
987
|
}[];
|
|
879
|
-
|
|
988
|
+
keyTimes: Map<string, number>;
|
|
989
|
+
deleteTimes?: Map<string, number>;
|
|
880
990
|
getColumn: (column: string) => Promise<{
|
|
881
991
|
key: string;
|
|
882
992
|
value: unknown;
|
|
993
|
+
time: number;
|
|
883
994
|
}[]>;
|
|
884
|
-
getSingleField: (key: string, column: string) => Promise<
|
|
995
|
+
getSingleField: (key: string, column: string) => Promise<{
|
|
996
|
+
value: unknown;
|
|
997
|
+
time: number;
|
|
998
|
+
} | typeof ABSENT>;
|
|
885
999
|
};
|
|
1000
|
+
export type BulkHeaderInfo = {
|
|
1001
|
+
rowCount: number;
|
|
1002
|
+
minTime: number;
|
|
1003
|
+
maxTime: number;
|
|
1004
|
+
minKey?: string;
|
|
1005
|
+
maxKey?: string;
|
|
1006
|
+
columns: {
|
|
1007
|
+
column: string;
|
|
1008
|
+
byteSize: number;
|
|
1009
|
+
}[];
|
|
1010
|
+
};
|
|
1011
|
+
export declare function loadBulkHeader(getRange: (start: number, end: number) => Promise<Buffer>, totalBytes: number): Promise<BulkHeaderInfo>;
|
|
886
1012
|
export declare function loadBulkDatabase(config: {
|
|
887
1013
|
totalBytes: number;
|
|
888
1014
|
getRange: (start: number, end: number) => Promise<Buffer>;
|
|
@@ -911,6 +1037,12 @@ declare module "sliftutils/storage/BulkDatabase2/blockCache" {
|
|
|
911
1037
|
|
|
912
1038
|
}
|
|
913
1039
|
|
|
1040
|
+
declare module "sliftutils/storage/BulkDatabase2/mergeLock" {
|
|
1041
|
+
export declare function tryAcquireMergeLock(collection: string, holderId: string): boolean;
|
|
1042
|
+
export declare function releaseMergeLock(collection: string, holderId: string): void;
|
|
1043
|
+
|
|
1044
|
+
}
|
|
1045
|
+
|
|
914
1046
|
declare module "sliftutils/storage/BulkDatabase2/streamLog" {
|
|
915
1047
|
/// <reference types="node" />
|
|
916
1048
|
/// <reference types="node" />
|
|
@@ -948,8 +1080,9 @@ declare module "sliftutils/storage/BulkDatabase2/syncClient" {
|
|
|
948
1080
|
value?: unknown;
|
|
949
1081
|
};
|
|
950
1082
|
export declare function isSyncSupported(): boolean;
|
|
951
|
-
export declare function connect(collection: string, onWrite: (write: RemoteWrite) => void): Promise<RemoteWrite[]>;
|
|
1083
|
+
export declare function connect(collection: string, onWrite: (write: RemoteWrite) => void, onSeal?: () => void): Promise<RemoteWrite[]>;
|
|
952
1084
|
export declare function broadcast(collection: string, write: RemoteWrite): void;
|
|
1085
|
+
export declare function broadcastSeal(collection: string): void;
|
|
953
1086
|
|
|
954
1087
|
}
|
|
955
1088
|
|
package/package.json
CHANGED
|
@@ -1,8 +1,90 @@
|
|
|
1
1
|
import { BulkDatabaseBase } from "./BulkDatabaseBase";
|
|
2
|
-
export { BulkDatabaseBase, noopReactiveDeps } from "./BulkDatabaseBase";
|
|
2
|
+
export { BulkDatabaseBase, noopReactiveDeps, bulkDatabase2Timing } from "./BulkDatabaseBase";
|
|
3
3
|
export type { ReactiveDeps, StorageFactory } from "./BulkDatabaseBase";
|
|
4
|
+
/** Per-column on-disk size info, as reported by getColumnInfo/getReaderInfo. */
|
|
5
|
+
export type BulkColumnInfo = {
|
|
6
|
+
column: string;
|
|
7
|
+
byteSize: number;
|
|
8
|
+
};
|
|
9
|
+
/** A snapshot of the collection's shape (no row data), as reported by getReaderInfo. */
|
|
10
|
+
export type BulkReaderInfo = {
|
|
11
|
+
rowCount: number;
|
|
12
|
+
totalBytes: number;
|
|
13
|
+
keyCount: number;
|
|
14
|
+
sampleKey: string | undefined;
|
|
15
|
+
columns: BulkColumnInfo[];
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* The full public API of BulkDatabase2 (the static `clearCache()` aside). BulkDatabase2 implements
|
|
19
|
+
* this; an application that just wants to depend on the surface can type against this interface instead
|
|
20
|
+
* of reading the implementation. `T` is the row type and must have a string `key`.
|
|
21
|
+
*
|
|
22
|
+
* Reads resolve every key/column by the latest write-time across all storage tiers. Writes are
|
|
23
|
+
* column-merges: a write/update only changes the columns it includes; columns it omits keep their
|
|
24
|
+
* previous value (clear a column by writing it as `undefined`).
|
|
25
|
+
*/
|
|
26
|
+
export interface IBulkDatabase2<T extends {
|
|
27
|
+
key: string;
|
|
28
|
+
}> {
|
|
29
|
+
/** The collection name (its folder under the storage root). */
|
|
30
|
+
readonly name: string;
|
|
31
|
+
/** Write one full row (merging its columns onto any existing row for the key). */
|
|
32
|
+
write(entry: T): Promise<void>;
|
|
33
|
+
/** Write many full rows in one batch. */
|
|
34
|
+
writeBatch(entries: T[]): Promise<void>;
|
|
35
|
+
/** Update only the given columns of an existing key (key required). Warns and no-ops if the key isn't present. */
|
|
36
|
+
update(entry: Partial<T> & {
|
|
37
|
+
key: string;
|
|
38
|
+
}): Promise<void>;
|
|
39
|
+
/** Update many keys' partial columns in one batch. */
|
|
40
|
+
updateBatch(entries: (Partial<T> & {
|
|
41
|
+
key: string;
|
|
42
|
+
})[]): Promise<void>;
|
|
43
|
+
/** Delete a key. */
|
|
44
|
+
delete(key: string): Promise<void>;
|
|
45
|
+
/** Delete many keys in one batch. */
|
|
46
|
+
deleteBatch(keys: string[]): Promise<void>;
|
|
47
|
+
/** All live keys. */
|
|
48
|
+
getKeys(): Promise<string[]>;
|
|
49
|
+
/** One field's value for a key, or undefined if the key/column isn't set or the key is deleted. */
|
|
50
|
+
getSingleField<Column extends keyof T>(key: string, column: Column): Promise<T[Column] | undefined>;
|
|
51
|
+
/** A whole column as {key, value} for every live key. */
|
|
52
|
+
getColumn<Column extends keyof T>(column: Column): Promise<{
|
|
53
|
+
key: string;
|
|
54
|
+
value: T[Column];
|
|
55
|
+
}[]>;
|
|
56
|
+
/**
|
|
57
|
+
* Synchronous, reactive read of one field. Returns undefined while the base value is still loading
|
|
58
|
+
* (and re-renders once it arrives, under a mobx observer); reflects pending writes immediately.
|
|
59
|
+
*/
|
|
60
|
+
getSingleFieldSync<Column extends keyof T>(key: string, column: Column): T[Column] | undefined;
|
|
61
|
+
/** Synchronous, reactive read of a whole column. undefined while still loading. */
|
|
62
|
+
getColumnSync<Column extends keyof T>(column: Column): {
|
|
63
|
+
key: string;
|
|
64
|
+
value: T[Column];
|
|
65
|
+
}[] | undefined;
|
|
66
|
+
/** The columns present on disk and their byte sizes (no row data read). */
|
|
67
|
+
getColumnInfo(): Promise<BulkColumnInfo[]>;
|
|
68
|
+
/** A cheap snapshot of the collection's shape (row/key counts, total bytes, columns) — no row data. */
|
|
69
|
+
getReaderInfo(): Promise<BulkReaderInfo>;
|
|
70
|
+
/** Consolidate on-disk files. Optional to call; the database also does this in the background. */
|
|
71
|
+
compact(): Promise<void>;
|
|
72
|
+
/**
|
|
73
|
+
* Run one merge pass now (the same policy the database runs on a timer): consolidate recent
|
|
74
|
+
* fragmentation and dedup a key range if it's worth it. Returns whether it merged anything and
|
|
75
|
+
* whether it bailed because another tab/process holds the merge lock — so a scheduler can call this
|
|
76
|
+
* (e.g. every 30 minutes) and tell "nothing to do" from "someone else is already merging".
|
|
77
|
+
*/
|
|
78
|
+
tryMergeNow(): Promise<{
|
|
79
|
+
merged: boolean;
|
|
80
|
+
lockFailed: boolean;
|
|
81
|
+
}>;
|
|
82
|
+
/** Rewrite everything written in [timeLo, timeHi] into fresh key-sorted bulk file(s). Low-level;
|
|
83
|
+
* most callers want compact() or tryMergeNow(). */
|
|
84
|
+
merge(timeLo: number, timeHi: number): Promise<void>;
|
|
85
|
+
}
|
|
4
86
|
export declare class BulkDatabase2<T extends {
|
|
5
87
|
key: string;
|
|
6
|
-
}> extends BulkDatabaseBase<T> {
|
|
88
|
+
}> extends BulkDatabaseBase<T> implements IBulkDatabase2<T> {
|
|
7
89
|
constructor(name: string);
|
|
8
90
|
}
|
|
@@ -2,9 +2,83 @@ import { getFileStorageNested2 } from "../FileFolderAPI";
|
|
|
2
2
|
import { observable, runInAction } from "../../render-utils/mobxTyped";
|
|
3
3
|
import { BulkDatabaseBase, ReactiveDeps } from "./BulkDatabaseBase";
|
|
4
4
|
|
|
5
|
-
export { BulkDatabaseBase, noopReactiveDeps } from "./BulkDatabaseBase";
|
|
5
|
+
export { BulkDatabaseBase, noopReactiveDeps, bulkDatabase2Timing } from "./BulkDatabaseBase";
|
|
6
6
|
export type { ReactiveDeps, StorageFactory } from "./BulkDatabaseBase";
|
|
7
7
|
|
|
8
|
+
/** Per-column on-disk size info, as reported by getColumnInfo/getReaderInfo. */
|
|
9
|
+
export type BulkColumnInfo = { column: string; byteSize: number };
|
|
10
|
+
|
|
11
|
+
/** A snapshot of the collection's shape (no row data), as reported by getReaderInfo. */
|
|
12
|
+
export type BulkReaderInfo = {
|
|
13
|
+
rowCount: number;
|
|
14
|
+
totalBytes: number;
|
|
15
|
+
keyCount: number;
|
|
16
|
+
sampleKey: string | undefined;
|
|
17
|
+
columns: BulkColumnInfo[];
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* The full public API of BulkDatabase2 (the static `clearCache()` aside). BulkDatabase2 implements
|
|
22
|
+
* this; an application that just wants to depend on the surface can type against this interface instead
|
|
23
|
+
* of reading the implementation. `T` is the row type and must have a string `key`.
|
|
24
|
+
*
|
|
25
|
+
* Reads resolve every key/column by the latest write-time across all storage tiers. Writes are
|
|
26
|
+
* column-merges: a write/update only changes the columns it includes; columns it omits keep their
|
|
27
|
+
* previous value (clear a column by writing it as `undefined`).
|
|
28
|
+
*/
|
|
29
|
+
export interface IBulkDatabase2<T extends { key: string }> {
|
|
30
|
+
/** The collection name (its folder under the storage root). */
|
|
31
|
+
readonly name: string;
|
|
32
|
+
|
|
33
|
+
/** Write one full row (merging its columns onto any existing row for the key). */
|
|
34
|
+
write(entry: T): Promise<void>;
|
|
35
|
+
/** Write many full rows in one batch. */
|
|
36
|
+
writeBatch(entries: T[]): Promise<void>;
|
|
37
|
+
/** Update only the given columns of an existing key (key required). Warns and no-ops if the key isn't present. */
|
|
38
|
+
update(entry: Partial<T> & { key: string }): Promise<void>;
|
|
39
|
+
/** Update many keys' partial columns in one batch. */
|
|
40
|
+
updateBatch(entries: (Partial<T> & { key: string })[]): Promise<void>;
|
|
41
|
+
/** Delete a key. */
|
|
42
|
+
delete(key: string): Promise<void>;
|
|
43
|
+
/** Delete many keys in one batch. */
|
|
44
|
+
deleteBatch(keys: string[]): Promise<void>;
|
|
45
|
+
|
|
46
|
+
/** All live keys. */
|
|
47
|
+
getKeys(): Promise<string[]>;
|
|
48
|
+
/** One field's value for a key, or undefined if the key/column isn't set or the key is deleted. */
|
|
49
|
+
getSingleField<Column extends keyof T>(key: string, column: Column): Promise<T[Column] | undefined>;
|
|
50
|
+
/** A whole column as {key, value} for every live key. */
|
|
51
|
+
getColumn<Column extends keyof T>(column: Column): Promise<{ key: string; value: T[Column] }[]>;
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Synchronous, reactive read of one field. Returns undefined while the base value is still loading
|
|
55
|
+
* (and re-renders once it arrives, under a mobx observer); reflects pending writes immediately.
|
|
56
|
+
*/
|
|
57
|
+
getSingleFieldSync<Column extends keyof T>(key: string, column: Column): T[Column] | undefined;
|
|
58
|
+
/** Synchronous, reactive read of a whole column. undefined while still loading. */
|
|
59
|
+
getColumnSync<Column extends keyof T>(column: Column): { key: string; value: T[Column] }[] | undefined;
|
|
60
|
+
|
|
61
|
+
/** The columns present on disk and their byte sizes (no row data read). */
|
|
62
|
+
getColumnInfo(): Promise<BulkColumnInfo[]>;
|
|
63
|
+
/** A cheap snapshot of the collection's shape (row/key counts, total bytes, columns) — no row data. */
|
|
64
|
+
getReaderInfo(): Promise<BulkReaderInfo>;
|
|
65
|
+
|
|
66
|
+
/** Consolidate on-disk files. Optional to call; the database also does this in the background. */
|
|
67
|
+
compact(): Promise<void>;
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Run one merge pass now (the same policy the database runs on a timer): consolidate recent
|
|
71
|
+
* fragmentation and dedup a key range if it's worth it. Returns whether it merged anything and
|
|
72
|
+
* whether it bailed because another tab/process holds the merge lock — so a scheduler can call this
|
|
73
|
+
* (e.g. every 30 minutes) and tell "nothing to do" from "someone else is already merging".
|
|
74
|
+
*/
|
|
75
|
+
tryMergeNow(): Promise<{ merged: boolean; lockFailed: boolean }>;
|
|
76
|
+
|
|
77
|
+
/** Rewrite everything written in [timeLo, timeHi] into fresh key-sorted bulk file(s). Low-level;
|
|
78
|
+
* most callers want compact() or tryMergeNow(). */
|
|
79
|
+
merge(timeLo: number, timeHi: number): Promise<void>;
|
|
80
|
+
}
|
|
81
|
+
|
|
8
82
|
// mobx-backed reactivity: each signal string gets its own observable box. observe() reads it (so an
|
|
9
83
|
// observer/autorun that calls it tracks that box) and invalidate() bumps it (so those reactions re-run).
|
|
10
84
|
// This reproduces the fine-grained per-key + load-version reactivity the class had when it used
|
|
@@ -34,7 +108,7 @@ class MobxReactiveDeps implements ReactiveDeps {
|
|
|
34
108
|
// Backwards-compatible BulkDatabase2: the mobx-reactive flavor. All behavior lives in BulkDatabaseBase;
|
|
35
109
|
// this just supplies mobx reactivity and the default (getFileStorageNested2) storage backend, so the
|
|
36
110
|
// sync reads (getSingleFieldSync / getColumnSync) stay observable for mobx components.
|
|
37
|
-
export class BulkDatabase2<T extends { key: string }> extends BulkDatabaseBase<T> {
|
|
111
|
+
export class BulkDatabase2<T extends { key: string }> extends BulkDatabaseBase<T> implements IBulkDatabase2<T> {
|
|
38
112
|
constructor(name: string) {
|
|
39
113
|
super(name, new MobxReactiveDeps(), getFileStorageNested2);
|
|
40
114
|
}
|
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
import type { FileStorage } from "../FileFolderAPI";
|
|
2
|
+
export declare const bulkDatabase2Timing: {
|
|
3
|
+
streamSealAgeMs: number;
|
|
4
|
+
mergeCheckIntervalMs: number;
|
|
5
|
+
firstMergeTriggerFiles: number;
|
|
6
|
+
firstMergeTriggerRangeMs: number;
|
|
7
|
+
};
|
|
2
8
|
export interface ReactiveDeps {
|
|
3
9
|
observe(signal: string): void;
|
|
4
10
|
invalidate(signal: string): void;
|
|
@@ -22,10 +28,13 @@ export declare class BulkDatabaseBase<T extends {
|
|
|
22
28
|
private overlay;
|
|
23
29
|
private streamTimes;
|
|
24
30
|
private streamFileName;
|
|
25
|
-
private
|
|
31
|
+
private lastMergeCheck;
|
|
26
32
|
private getStreamFileName;
|
|
27
|
-
private
|
|
33
|
+
private invalidateOverlay;
|
|
34
|
+
private setOverlayRow;
|
|
35
|
+
private setOverlayDeleted;
|
|
28
36
|
private reader;
|
|
37
|
+
private buildReader;
|
|
29
38
|
private syncSetup;
|
|
30
39
|
private localTime;
|
|
31
40
|
private applyRemote;
|
|
@@ -34,20 +43,32 @@ export declare class BulkDatabaseBase<T extends {
|
|
|
34
43
|
writeBatch(entries: T[]): Promise<void>;
|
|
35
44
|
delete(key: string): Promise<void>;
|
|
36
45
|
deleteBatch(keys: string[]): Promise<void>;
|
|
46
|
+
update(entry: Partial<T> & {
|
|
47
|
+
key: string;
|
|
48
|
+
}): Promise<void>;
|
|
49
|
+
updateBatch(entries: (Partial<T> & {
|
|
50
|
+
key: string;
|
|
51
|
+
})[]): Promise<void>;
|
|
52
|
+
private listFiles;
|
|
37
53
|
private writeBulkFile;
|
|
38
|
-
private listStreamFiles;
|
|
39
54
|
private loadStreamEntries;
|
|
40
55
|
private orderStreamEntries;
|
|
41
|
-
private
|
|
42
|
-
|
|
56
|
+
private maybeMerge;
|
|
57
|
+
tryMergeNow(): Promise<{
|
|
58
|
+
merged: boolean;
|
|
59
|
+
lockFailed: boolean;
|
|
60
|
+
}>;
|
|
43
61
|
compact(): Promise<void>;
|
|
44
|
-
|
|
62
|
+
merge(timeLo: number, timeHi: number): Promise<void>;
|
|
45
63
|
private makeRawGetRange;
|
|
46
64
|
private loadFileReader;
|
|
65
|
+
private readBulkHeader;
|
|
47
66
|
private fileLogicalSize;
|
|
48
67
|
private handleUnreadableFile;
|
|
49
|
-
private
|
|
50
|
-
private
|
|
68
|
+
private resolveReaders;
|
|
69
|
+
private mergeFileSet;
|
|
70
|
+
private canDeleteStream;
|
|
71
|
+
private testMerge;
|
|
51
72
|
private formatInfo;
|
|
52
73
|
private patchColumn;
|
|
53
74
|
getSingleField<Column extends keyof T>(key: string, column: Column): Promise<T[Column] | undefined>;
|