sliftutils 1.3.1 → 1.4.1

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 CHANGED
@@ -834,6 +834,19 @@ declare module "sliftutils/storage/BulkDatabase2/BulkDatabase2" {
834
834
  getReaderInfo(): Promise<BulkReaderInfo>;
835
835
  /** Consolidate on-disk files. Optional to call; the database also does this in the background. */
836
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>;
837
850
  }
838
851
  export declare class BulkDatabase2<T extends {
839
852
  key: string;
@@ -847,11 +860,9 @@ declare module "sliftutils/storage/BulkDatabase2/BulkDatabaseBase" {
847
860
  import type { FileStorage } from "../FileFolderAPI";
848
861
  export declare const bulkDatabase2Timing: {
849
862
  streamSealAgeMs: number;
850
- foldDataAgeMs: number;
851
- foldTriggerAgeMs: number;
852
- foldCheckIntervalMs: number;
853
- cleanupAgeMs: number;
854
- cleanupIntervalMs: number;
863
+ mergeCheckIntervalMs: number;
864
+ firstMergeTriggerFiles: number;
865
+ firstMergeTriggerRangeMs: number;
855
866
  };
856
867
  export interface ReactiveDeps {
857
868
  observe(signal: string): void;
@@ -876,13 +887,13 @@ declare module "sliftutils/storage/BulkDatabase2/BulkDatabaseBase" {
876
887
  private overlay;
877
888
  private streamTimes;
878
889
  private streamFileName;
879
- private lastCleanup;
880
- private lastFoldCheck;
890
+ private lastMergeCheck;
881
891
  private getStreamFileName;
882
892
  private invalidateOverlay;
883
893
  private setOverlayRow;
884
894
  private setOverlayDeleted;
885
895
  private reader;
896
+ private buildReader;
886
897
  private syncSetup;
887
898
  private localTime;
888
899
  private applyRemote;
@@ -897,22 +908,26 @@ declare module "sliftutils/storage/BulkDatabase2/BulkDatabaseBase" {
897
908
  updateBatch(entries: (Partial<T> & {
898
909
  key: string;
899
910
  })[]): Promise<void>;
900
- private getValidFiles;
901
- private commitManifest;
911
+ private listFiles;
902
912
  private writeBulkFile;
903
- private consolidate;
904
913
  private loadStreamEntries;
905
914
  private orderStreamEntries;
906
- private maybeRolloverStream;
915
+ private maybeMerge;
916
+ tryMergeNow(): Promise<{
917
+ merged: boolean;
918
+ lockFailed: boolean;
919
+ }>;
907
920
  compact(): Promise<void>;
921
+ merge(timeLo: number, timeHi: number): Promise<void>;
908
922
  private makeRawGetRange;
909
923
  private loadFileReader;
924
+ private readBulkHeader;
910
925
  private fileLogicalSize;
911
926
  private handleUnreadableFile;
912
- private mergeFilesBase;
913
- private mergeFiles;
914
- private mergeFilesLocked;
915
- private cleanup;
927
+ private resolveReaders;
928
+ private mergeFileSet;
929
+ private canDeleteStream;
930
+ private testMerge;
916
931
  private formatInfo;
917
932
  private patchColumn;
918
933
  getSingleField<Column extends keyof T>(key: string, column: Column): Promise<T[Column] | undefined>;
@@ -956,12 +971,15 @@ declare module "sliftutils/storage/BulkDatabase2/BulkDatabaseFormat" {
956
971
  export declare const KEY_COLUMN = "key";
957
972
  export declare const EMPTY_BUFFER: Buffer;
958
973
  export declare const ABSENT: unique symbol;
959
- export declare function buildFileBuffer(rows: Record<string, unknown>[], times: number[]): Buffer[];
974
+ export declare const TARGET_FILE_BYTES: number;
975
+ export declare function buildFileBuffer(rows: Record<string, unknown>[], times: number[], targetBytes?: number): Buffer[];
960
976
  export type BaseBulkDatabaseReader = {
961
977
  rowCount: number;
962
978
  totalBytes: number;
963
979
  minTime: number;
964
980
  maxTime: number;
981
+ minKey?: string;
982
+ maxKey?: string;
965
983
  keys: string[];
966
984
  columns: {
967
985
  column: string;
@@ -979,6 +997,18 @@ declare module "sliftutils/storage/BulkDatabase2/BulkDatabaseFormat" {
979
997
  time: number;
980
998
  } | typeof ABSENT>;
981
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>;
982
1012
  export declare function loadBulkDatabase(config: {
983
1013
  totalBytes: number;
984
1014
  getRange: (start: number, end: number) => Promise<Buffer>;
@@ -1007,27 +1037,6 @@ declare module "sliftutils/storage/BulkDatabase2/blockCache" {
1007
1037
 
1008
1038
  }
1009
1039
 
1010
- declare module "sliftutils/storage/BulkDatabase2/manifest" {
1011
- export declare const MANIFEST_EXTENSION = ".manifest";
1012
- export type Manifest = {
1013
- startTime: number;
1014
- validBulkFiles: string[];
1015
- ignoredStreamFiles: string[];
1016
- readFiles: string[];
1017
- };
1018
- export declare function isManifestName(name: string): boolean;
1019
- export declare function manifestFileName(startTime: number, writerId: string, counter: number): string;
1020
- export declare function parseManifestStartTime(name: string): number | undefined;
1021
- export declare function chooseManifest(manifests: {
1022
- name: string;
1023
- manifest: Manifest;
1024
- }[]): {
1025
- name: string;
1026
- manifest: Manifest;
1027
- } | undefined;
1028
-
1029
- }
1030
-
1031
1040
  declare module "sliftutils/storage/BulkDatabase2/mergeLock" {
1032
1041
  export declare function tryAcquireMergeLock(collection: string, holderId: string): boolean;
1033
1042
  export declare function releaseMergeLock(collection: string, holderId: string): void;
@@ -1071,8 +1080,9 @@ declare module "sliftutils/storage/BulkDatabase2/syncClient" {
1071
1080
  value?: unknown;
1072
1081
  };
1073
1082
  export declare function isSyncSupported(): boolean;
1074
- 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[]>;
1075
1084
  export declare function broadcast(collection: string, write: RemoteWrite): void;
1085
+ export declare function broadcastSeal(collection: string): void;
1076
1086
 
1077
1087
  }
1078
1088
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sliftutils",
3
- "version": "1.3.1",
3
+ "version": "1.4.1",
4
4
  "main": "index.js",
5
5
  "license": "MIT",
6
6
  "files": [
@@ -69,6 +69,19 @@ export interface IBulkDatabase2<T extends {
69
69
  getReaderInfo(): Promise<BulkReaderInfo>;
70
70
  /** Consolidate on-disk files. Optional to call; the database also does this in the background. */
71
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>;
72
85
  }
73
86
  export declare class BulkDatabase2<T extends {
74
87
  key: string;
@@ -65,6 +65,18 @@ export interface IBulkDatabase2<T extends { key: string }> {
65
65
 
66
66
  /** Consolidate on-disk files. Optional to call; the database also does this in the background. */
67
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>;
68
80
  }
69
81
 
70
82
  // mobx-backed reactivity: each signal string gets its own observable box. observe() reads it (so an
@@ -1,11 +1,9 @@
1
1
  import type { FileStorage } from "../FileFolderAPI";
2
2
  export declare const bulkDatabase2Timing: {
3
3
  streamSealAgeMs: number;
4
- foldDataAgeMs: number;
5
- foldTriggerAgeMs: number;
6
- foldCheckIntervalMs: number;
7
- cleanupAgeMs: number;
8
- cleanupIntervalMs: number;
4
+ mergeCheckIntervalMs: number;
5
+ firstMergeTriggerFiles: number;
6
+ firstMergeTriggerRangeMs: number;
9
7
  };
10
8
  export interface ReactiveDeps {
11
9
  observe(signal: string): void;
@@ -30,13 +28,13 @@ export declare class BulkDatabaseBase<T extends {
30
28
  private overlay;
31
29
  private streamTimes;
32
30
  private streamFileName;
33
- private lastCleanup;
34
- private lastFoldCheck;
31
+ private lastMergeCheck;
35
32
  private getStreamFileName;
36
33
  private invalidateOverlay;
37
34
  private setOverlayRow;
38
35
  private setOverlayDeleted;
39
36
  private reader;
37
+ private buildReader;
40
38
  private syncSetup;
41
39
  private localTime;
42
40
  private applyRemote;
@@ -51,22 +49,26 @@ export declare class BulkDatabaseBase<T extends {
51
49
  updateBatch(entries: (Partial<T> & {
52
50
  key: string;
53
51
  })[]): Promise<void>;
54
- private getValidFiles;
55
- private commitManifest;
52
+ private listFiles;
56
53
  private writeBulkFile;
57
- private consolidate;
58
54
  private loadStreamEntries;
59
55
  private orderStreamEntries;
60
- private maybeRolloverStream;
56
+ private maybeMerge;
57
+ tryMergeNow(): Promise<{
58
+ merged: boolean;
59
+ lockFailed: boolean;
60
+ }>;
61
61
  compact(): Promise<void>;
62
+ merge(timeLo: number, timeHi: number): Promise<void>;
62
63
  private makeRawGetRange;
63
64
  private loadFileReader;
65
+ private readBulkHeader;
64
66
  private fileLogicalSize;
65
67
  private handleUnreadableFile;
66
- private mergeFilesBase;
67
- private mergeFiles;
68
- private mergeFilesLocked;
69
- private cleanup;
68
+ private resolveReaders;
69
+ private mergeFileSet;
70
+ private canDeleteStream;
71
+ private testMerge;
70
72
  private formatInfo;
71
73
  private patchColumn;
72
74
  getSingleField<Column extends keyof T>(key: string, column: Column): Promise<T[Column] | undefined>;