@yydb/light-db 0.0.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/dist/api/LightDB.d.ts +194 -0
- package/dist/api/LightDB.d.ts.map +1 -0
- package/dist/api/LightDB.js +299 -0
- package/dist/api/LightDB.js.map +1 -0
- package/dist/api/Transaction.d.ts +100 -0
- package/dist/api/Transaction.d.ts.map +1 -0
- package/dist/api/Transaction.js +263 -0
- package/dist/api/Transaction.js.map +1 -0
- package/dist/api/index.d.ts +24 -0
- package/dist/api/index.d.ts.map +1 -0
- package/dist/api/index.js +54 -0
- package/dist/api/index.js.map +1 -0
- package/dist/api/types.d.ts +154 -0
- package/dist/api/types.d.ts.map +1 -0
- package/dist/api/types.js +7 -0
- package/dist/api/types.js.map +1 -0
- package/dist/collection/Collection.d.ts +235 -0
- package/dist/collection/Collection.d.ts.map +1 -0
- package/dist/collection/Collection.js +671 -0
- package/dist/collection/Collection.js.map +1 -0
- package/dist/collection/QueryBuilder.d.ts +225 -0
- package/dist/collection/QueryBuilder.d.ts.map +1 -0
- package/dist/collection/QueryBuilder.js +475 -0
- package/dist/collection/QueryBuilder.js.map +1 -0
- package/dist/collection/QueryParser.d.ts +117 -0
- package/dist/collection/QueryParser.d.ts.map +1 -0
- package/dist/collection/QueryParser.js +438 -0
- package/dist/collection/QueryParser.js.map +1 -0
- package/dist/collection/index.d.ts +42 -0
- package/dist/collection/index.d.ts.map +1 -0
- package/dist/collection/index.js +41 -0
- package/dist/collection/index.js.map +1 -0
- package/dist/collection/types.d.ts +365 -0
- package/dist/collection/types.d.ts.map +1 -0
- package/dist/collection/types.js +7 -0
- package/dist/collection/types.js.map +1 -0
- package/dist/constants/index.d.ts +51 -0
- package/dist/constants/index.d.ts.map +1 -0
- package/dist/constants/index.js +68 -0
- package/dist/constants/index.js.map +1 -0
- package/dist/errors/index.d.ts +69 -0
- package/dist/errors/index.d.ts.map +1 -0
- package/dist/errors/index.js +132 -0
- package/dist/errors/index.js.map +1 -0
- package/dist/index.d.ts +220 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +729 -0
- package/dist/index.js.map +1 -0
- package/dist/indexes/BPlusTree.d.ts +181 -0
- package/dist/indexes/BPlusTree.d.ts.map +1 -0
- package/dist/indexes/BPlusTree.js +528 -0
- package/dist/indexes/BPlusTree.js.map +1 -0
- package/dist/indexes/IndexManager.d.ts +236 -0
- package/dist/indexes/IndexManager.d.ts.map +1 -0
- package/dist/indexes/IndexManager.js +502 -0
- package/dist/indexes/IndexManager.js.map +1 -0
- package/dist/indexes/PrimaryIndex.d.ts +240 -0
- package/dist/indexes/PrimaryIndex.d.ts.map +1 -0
- package/dist/indexes/PrimaryIndex.js +354 -0
- package/dist/indexes/PrimaryIndex.js.map +1 -0
- package/dist/indexes/SecondaryIndex.d.ts +204 -0
- package/dist/indexes/SecondaryIndex.d.ts.map +1 -0
- package/dist/indexes/SecondaryIndex.js +480 -0
- package/dist/indexes/SecondaryIndex.js.map +1 -0
- package/dist/indexes/errors.d.ts +66 -0
- package/dist/indexes/errors.d.ts.map +1 -0
- package/dist/indexes/errors.js +117 -0
- package/dist/indexes/errors.js.map +1 -0
- package/dist/indexes/index.d.ts +52 -0
- package/dist/indexes/index.d.ts.map +1 -0
- package/dist/indexes/index.js +131 -0
- package/dist/indexes/index.js.map +1 -0
- package/dist/indexes/types.d.ts +246 -0
- package/dist/indexes/types.d.ts.map +1 -0
- package/dist/indexes/types.js +30 -0
- package/dist/indexes/types.js.map +1 -0
- package/dist/performance/BatchWALWriter.d.ts +185 -0
- package/dist/performance/BatchWALWriter.d.ts.map +1 -0
- package/dist/performance/BatchWALWriter.js +490 -0
- package/dist/performance/BatchWALWriter.js.map +1 -0
- package/dist/performance/ColumnarStorage.d.ts +138 -0
- package/dist/performance/ColumnarStorage.d.ts.map +1 -0
- package/dist/performance/ColumnarStorage.js +875 -0
- package/dist/performance/ColumnarStorage.js.map +1 -0
- package/dist/performance/LazyQuery.d.ts +307 -0
- package/dist/performance/LazyQuery.d.ts.map +1 -0
- package/dist/performance/LazyQuery.js +588 -0
- package/dist/performance/LazyQuery.js.map +1 -0
- package/dist/performance/OptimizedBuffer.d.ts +375 -0
- package/dist/performance/OptimizedBuffer.d.ts.map +1 -0
- package/dist/performance/OptimizedBuffer.js +730 -0
- package/dist/performance/OptimizedBuffer.js.map +1 -0
- package/dist/performance/RWLock.d.ts +260 -0
- package/dist/performance/RWLock.d.ts.map +1 -0
- package/dist/performance/RWLock.js +570 -0
- package/dist/performance/RWLock.js.map +1 -0
- package/dist/performance/index.d.ts +41 -0
- package/dist/performance/index.d.ts.map +1 -0
- package/dist/performance/index.js +162 -0
- package/dist/performance/index.js.map +1 -0
- package/dist/performance/types.d.ts +247 -0
- package/dist/performance/types.d.ts.map +1 -0
- package/dist/performance/types.js +26 -0
- package/dist/performance/types.js.map +1 -0
- package/dist/storage/Checkpoint.d.ts +128 -0
- package/dist/storage/Checkpoint.d.ts.map +1 -0
- package/dist/storage/Checkpoint.js +251 -0
- package/dist/storage/Checkpoint.js.map +1 -0
- package/dist/storage/LightFile.d.ts +227 -0
- package/dist/storage/LightFile.d.ts.map +1 -0
- package/dist/storage/LightFile.js +526 -0
- package/dist/storage/LightFile.js.map +1 -0
- package/dist/storage/Recovery.d.ts +172 -0
- package/dist/storage/Recovery.d.ts.map +1 -0
- package/dist/storage/Recovery.js +399 -0
- package/dist/storage/Recovery.js.map +1 -0
- package/dist/storage/SHMFile.d.ts +243 -0
- package/dist/storage/SHMFile.d.ts.map +1 -0
- package/dist/storage/SHMFile.js +436 -0
- package/dist/storage/SHMFile.js.map +1 -0
- package/dist/storage/StorageEngine.d.ts +146 -0
- package/dist/storage/StorageEngine.d.ts.map +1 -0
- package/dist/storage/StorageEngine.js +353 -0
- package/dist/storage/StorageEngine.js.map +1 -0
- package/dist/storage/WALFile.d.ts +248 -0
- package/dist/storage/WALFile.d.ts.map +1 -0
- package/dist/storage/WALFile.js +597 -0
- package/dist/storage/WALFile.js.map +1 -0
- package/dist/storage/index.d.ts +10 -0
- package/dist/storage/index.d.ts.map +1 -0
- package/dist/storage/index.js +153 -0
- package/dist/storage/index.js.map +1 -0
- package/dist/types/index.d.ts +220 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +7 -0
- package/dist/types/index.js.map +1 -0
- package/dist/utils/binary.d.ts +271 -0
- package/dist/utils/binary.d.ts.map +1 -0
- package/dist/utils/binary.js +454 -0
- package/dist/utils/binary.js.map +1 -0
- package/dist/utils/file.d.ts +166 -0
- package/dist/utils/file.d.ts.map +1 -0
- package/dist/utils/file.js +346 -0
- package/dist/utils/file.js.map +1 -0
- package/dist/utils/index.d.ts +6 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +39 -0
- package/dist/utils/index.js.map +1 -0
- package/package.json +37 -0
- package/readme.md +124 -0
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* LightDB 索引引擎类型定义
|
|
4
|
+
* 包含所有索引相关的接口、类型和结构体定义
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.BPlusTreeNodeType = exports.IndexType = void 0;
|
|
8
|
+
/**
|
|
9
|
+
* 索引类型枚举
|
|
10
|
+
*/
|
|
11
|
+
var IndexType;
|
|
12
|
+
(function (IndexType) {
|
|
13
|
+
/** 主键索引(B+树) */
|
|
14
|
+
IndexType["Primary"] = "primary";
|
|
15
|
+
/** 二级索引(Map + Set) */
|
|
16
|
+
IndexType["Secondary"] = "secondary";
|
|
17
|
+
/** 唯一索引 */
|
|
18
|
+
IndexType["Unique"] = "unique";
|
|
19
|
+
})(IndexType || (exports.IndexType = IndexType = {}));
|
|
20
|
+
/**
|
|
21
|
+
* B+ 树节点类型
|
|
22
|
+
*/
|
|
23
|
+
var BPlusTreeNodeType;
|
|
24
|
+
(function (BPlusTreeNodeType) {
|
|
25
|
+
/** 内部节点 */
|
|
26
|
+
BPlusTreeNodeType["Internal"] = "internal";
|
|
27
|
+
/** 叶子节点 */
|
|
28
|
+
BPlusTreeNodeType["Leaf"] = "leaf";
|
|
29
|
+
})(BPlusTreeNodeType || (exports.BPlusTreeNodeType = BPlusTreeNodeType = {}));
|
|
30
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/indexes/types.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AA+CH;;GAEG;AACH,IAAY,SAOX;AAPD,WAAY,SAAS;IACjB,gBAAgB;IAChB,gCAAmB,CAAA;IACnB,sBAAsB;IACtB,oCAAuB,CAAA;IACvB,WAAW;IACX,8BAAiB,CAAA;AACrB,CAAC,EAPW,SAAS,yBAAT,SAAS,QAOpB;AAwED;;GAEG;AACH,IAAY,iBAKX;AALD,WAAY,iBAAiB;IACzB,WAAW;IACX,0CAAqB,CAAA;IACrB,WAAW;IACX,kCAAa,CAAA;AACjB,CAAC,EALW,iBAAiB,iCAAjB,iBAAiB,QAK5B"}
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 异步批量写入器
|
|
3
|
+
* 将多个写操作的 WAL 记录暂存于内存队列,定时或队列满时一次性写入
|
|
4
|
+
*/
|
|
5
|
+
import { BatchWriteOptions, BatchWriteStats, BatchFlushResult } from "./types";
|
|
6
|
+
/**
|
|
7
|
+
* WAL 记录接口
|
|
8
|
+
*/
|
|
9
|
+
export interface WalRecordEntry {
|
|
10
|
+
/** 日志序列号 */
|
|
11
|
+
lsn: bigint;
|
|
12
|
+
/** 事务 ID */
|
|
13
|
+
transactionId: bigint;
|
|
14
|
+
/** 操作类型 */
|
|
15
|
+
operationType: number;
|
|
16
|
+
/** 键 */
|
|
17
|
+
key: string;
|
|
18
|
+
/** 值 */
|
|
19
|
+
value: Buffer | null;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* 异步批量 WAL 写入器
|
|
23
|
+
* 支持合并写入、定时刷新和灵活的 fsync 策略
|
|
24
|
+
*/
|
|
25
|
+
export declare class BatchWalWriter {
|
|
26
|
+
private filePath;
|
|
27
|
+
private handle;
|
|
28
|
+
private queue;
|
|
29
|
+
private queueCapacity;
|
|
30
|
+
private batchSize;
|
|
31
|
+
private flushIntervalMs;
|
|
32
|
+
private fsyncStrategy;
|
|
33
|
+
private fsyncBatchSize;
|
|
34
|
+
private fsyncIntervalMs;
|
|
35
|
+
private flushTimer;
|
|
36
|
+
private fsyncTimer;
|
|
37
|
+
private currentOffset;
|
|
38
|
+
private writeCountSinceFsync;
|
|
39
|
+
private lastFlushTime;
|
|
40
|
+
private lastFsyncTime;
|
|
41
|
+
private totalWritten;
|
|
42
|
+
private isFlushing;
|
|
43
|
+
private pendingFlush;
|
|
44
|
+
private closed;
|
|
45
|
+
/**
|
|
46
|
+
* 创建批量 WAL 写入器
|
|
47
|
+
* @param filePath 文件路径
|
|
48
|
+
* @param options 配置选项
|
|
49
|
+
*/
|
|
50
|
+
constructor(filePath: string, options?: BatchWriteOptions);
|
|
51
|
+
/**
|
|
52
|
+
* 打开文件
|
|
53
|
+
*/
|
|
54
|
+
open(): Promise<void>;
|
|
55
|
+
/**
|
|
56
|
+
* 启动定时器
|
|
57
|
+
*/
|
|
58
|
+
private startTimers;
|
|
59
|
+
/**
|
|
60
|
+
* 停止定时器
|
|
61
|
+
*/
|
|
62
|
+
private stopTimers;
|
|
63
|
+
/**
|
|
64
|
+
* 序列化 WAL 记录
|
|
65
|
+
*/
|
|
66
|
+
private serializeRecord;
|
|
67
|
+
/**
|
|
68
|
+
* 计算校验和
|
|
69
|
+
*/
|
|
70
|
+
private calculateChecksum;
|
|
71
|
+
/**
|
|
72
|
+
* 获取 CRC32 表
|
|
73
|
+
*/
|
|
74
|
+
private crc32Table;
|
|
75
|
+
private getCrc32Table;
|
|
76
|
+
/**
|
|
77
|
+
* 添加记录到队列
|
|
78
|
+
* @param record WAL 记录
|
|
79
|
+
*/
|
|
80
|
+
append(record: WalRecordEntry): Promise<void>;
|
|
81
|
+
/**
|
|
82
|
+
* 批量添加记录
|
|
83
|
+
* @param records WAL 记录数组
|
|
84
|
+
*/
|
|
85
|
+
appendMany(records: WalRecordEntry[]): Promise<void>;
|
|
86
|
+
/**
|
|
87
|
+
* 刷新队列到磁盘
|
|
88
|
+
*/
|
|
89
|
+
flush(): Promise<BatchFlushResult>;
|
|
90
|
+
/**
|
|
91
|
+
* 同步到磁盘
|
|
92
|
+
*/
|
|
93
|
+
fsync(): Promise<void>;
|
|
94
|
+
/**
|
|
95
|
+
* 获取统计信息
|
|
96
|
+
*/
|
|
97
|
+
getStats(): BatchWriteStats;
|
|
98
|
+
/**
|
|
99
|
+
* 获取当前偏移量
|
|
100
|
+
*/
|
|
101
|
+
getCurrentOffset(): bigint;
|
|
102
|
+
/**
|
|
103
|
+
* 获取文件路径
|
|
104
|
+
*/
|
|
105
|
+
getFilePath(): string;
|
|
106
|
+
/**
|
|
107
|
+
* 清空队列
|
|
108
|
+
*/
|
|
109
|
+
clearQueue(): void;
|
|
110
|
+
/**
|
|
111
|
+
* 关闭写入器
|
|
112
|
+
*/
|
|
113
|
+
close(): Promise<void>;
|
|
114
|
+
/**
|
|
115
|
+
* 清空文件
|
|
116
|
+
*/
|
|
117
|
+
clear(): Promise<void>;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* 批量写入管理器
|
|
121
|
+
* 提供更高层的批量写入接口
|
|
122
|
+
*/
|
|
123
|
+
export declare class BatchWriteManager {
|
|
124
|
+
private writers;
|
|
125
|
+
private defaultOptions;
|
|
126
|
+
/**
|
|
127
|
+
* 创建批量写入管理器
|
|
128
|
+
* @param defaultOptions 默认配置
|
|
129
|
+
*/
|
|
130
|
+
constructor(defaultOptions?: BatchWriteOptions);
|
|
131
|
+
/**
|
|
132
|
+
* 获取或创建写入器
|
|
133
|
+
* @param name 写入器名称
|
|
134
|
+
* @param filePath 文件路径
|
|
135
|
+
* @param options 配置选项
|
|
136
|
+
*/
|
|
137
|
+
getWriter(name: string, filePath: string, options?: BatchWriteOptions): Promise<BatchWalWriter>;
|
|
138
|
+
/**
|
|
139
|
+
* 写入记录
|
|
140
|
+
* @param name 写入器名称
|
|
141
|
+
* @param record WAL 记录
|
|
142
|
+
*/
|
|
143
|
+
append(name: string, record: WalRecordEntry): Promise<void>;
|
|
144
|
+
/**
|
|
145
|
+
* 刷新指定写入器
|
|
146
|
+
* @param name 写入器名称
|
|
147
|
+
*/
|
|
148
|
+
flush(name: string): Promise<BatchFlushResult>;
|
|
149
|
+
/**
|
|
150
|
+
* 刷新所有写入器
|
|
151
|
+
*/
|
|
152
|
+
flushAll(): Promise<Map<string, BatchFlushResult>>;
|
|
153
|
+
/**
|
|
154
|
+
* 同步指定写入器
|
|
155
|
+
* @param name 写入器名称
|
|
156
|
+
*/
|
|
157
|
+
fsync(name: string): Promise<void>;
|
|
158
|
+
/**
|
|
159
|
+
* 同步所有写入器
|
|
160
|
+
*/
|
|
161
|
+
fsyncAll(): Promise<void>;
|
|
162
|
+
/**
|
|
163
|
+
* 关闭指定写入器
|
|
164
|
+
* @param name 写入器名称
|
|
165
|
+
*/
|
|
166
|
+
closeWriter(name: string): Promise<void>;
|
|
167
|
+
/**
|
|
168
|
+
* 关闭所有写入器
|
|
169
|
+
*/
|
|
170
|
+
closeAll(): Promise<void>;
|
|
171
|
+
/**
|
|
172
|
+
* 获取所有写入器名称
|
|
173
|
+
*/
|
|
174
|
+
getWriterNames(): string[];
|
|
175
|
+
/**
|
|
176
|
+
* 获取写入器统计信息
|
|
177
|
+
* @param name 写入器名称
|
|
178
|
+
*/
|
|
179
|
+
getStats(name: string): BatchWriteStats | undefined;
|
|
180
|
+
/**
|
|
181
|
+
* 获取所有写入器统计信息
|
|
182
|
+
*/
|
|
183
|
+
getAllStats(): Map<string, BatchWriteStats>;
|
|
184
|
+
}
|
|
185
|
+
//# sourceMappingURL=BatchWalWriter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BatchWalWriter.d.ts","sourceRoot":"","sources":["../../src/performance/BatchWalWriter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,490 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* 异步批量写入器
|
|
4
|
+
* 将多个写操作的 WAL 记录暂存于内存队列,定时或队列满时一次性写入
|
|
5
|
+
*/
|
|
6
|
+
var __createBinding =
|
|
7
|
+
(this && this.__createBinding) ||
|
|
8
|
+
(Object.create
|
|
9
|
+
? function (o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
12
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
13
|
+
desc = {
|
|
14
|
+
enumerable: true,
|
|
15
|
+
get: function () {
|
|
16
|
+
return m[k];
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
Object.defineProperty(o, k2, desc);
|
|
21
|
+
}
|
|
22
|
+
: function (o, m, k, k2) {
|
|
23
|
+
if (k2 === undefined) k2 = k;
|
|
24
|
+
o[k2] = m[k];
|
|
25
|
+
});
|
|
26
|
+
var __setModuleDefault =
|
|
27
|
+
(this && this.__setModuleDefault) ||
|
|
28
|
+
(Object.create
|
|
29
|
+
? function (o, v) {
|
|
30
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
31
|
+
}
|
|
32
|
+
: function (o, v) {
|
|
33
|
+
o["default"] = v;
|
|
34
|
+
});
|
|
35
|
+
var __importStar =
|
|
36
|
+
(this && this.__importStar) ||
|
|
37
|
+
(function () {
|
|
38
|
+
var ownKeys = function (o) {
|
|
39
|
+
ownKeys =
|
|
40
|
+
Object.getOwnPropertyNames ||
|
|
41
|
+
function (o) {
|
|
42
|
+
var ar = [];
|
|
43
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
44
|
+
return ar;
|
|
45
|
+
};
|
|
46
|
+
return ownKeys(o);
|
|
47
|
+
};
|
|
48
|
+
return function (mod) {
|
|
49
|
+
if (mod && mod.__esModule) return mod;
|
|
50
|
+
var result = {};
|
|
51
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
52
|
+
__setModuleDefault(result, mod);
|
|
53
|
+
return result;
|
|
54
|
+
};
|
|
55
|
+
})();
|
|
56
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
57
|
+
exports.BatchWriteManager = exports.BatchWalWriter = void 0;
|
|
58
|
+
const fs = __importStar(require("fs/promises"));
|
|
59
|
+
const OptimizedBuffer_1 = require("./OptimizedBuffer");
|
|
60
|
+
/**
|
|
61
|
+
* 异步批量 WAL 写入器
|
|
62
|
+
* 支持合并写入、定时刷新和灵活的 fsync 策略
|
|
63
|
+
*/
|
|
64
|
+
class BatchWalWriter {
|
|
65
|
+
/**
|
|
66
|
+
* 创建批量 WAL 写入器
|
|
67
|
+
* @param filePath 文件路径
|
|
68
|
+
* @param options 配置选项
|
|
69
|
+
*/
|
|
70
|
+
constructor(filePath, options = {}) {
|
|
71
|
+
this.handle = null;
|
|
72
|
+
this.flushTimer = null;
|
|
73
|
+
this.fsyncTimer = null;
|
|
74
|
+
/**
|
|
75
|
+
* 获取 CRC32 表
|
|
76
|
+
*/
|
|
77
|
+
this.crc32Table = null;
|
|
78
|
+
this.filePath = filePath;
|
|
79
|
+
this.queue = [];
|
|
80
|
+
this.queueCapacity = options.batchSize ? options.batchSize * 2 : 2000;
|
|
81
|
+
this.batchSize = options.batchSize ?? 100;
|
|
82
|
+
this.flushIntervalMs = options.flushIntervalMs ?? 100;
|
|
83
|
+
this.fsyncStrategy = options.fsyncStrategy ?? "batch";
|
|
84
|
+
this.fsyncBatchSize = options.fsyncBatchSize ?? 1000;
|
|
85
|
+
this.fsyncIntervalMs = options.fsyncIntervalMs ?? 1000;
|
|
86
|
+
this.currentOffset = 0n;
|
|
87
|
+
this.writeCountSinceFsync = 0;
|
|
88
|
+
this.lastFlushTime = 0;
|
|
89
|
+
this.lastFsyncTime = 0;
|
|
90
|
+
this.totalWritten = 0;
|
|
91
|
+
this.isFlushing = false;
|
|
92
|
+
this.pendingFlush = false;
|
|
93
|
+
this.closed = false;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* 打开文件
|
|
97
|
+
*/
|
|
98
|
+
async open() {
|
|
99
|
+
if (this.handle) {
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
try {
|
|
103
|
+
const stats = await fs.stat(this.filePath);
|
|
104
|
+
this.handle = await fs.open(this.filePath, "r+");
|
|
105
|
+
this.currentOffset = BigInt(stats.size);
|
|
106
|
+
} catch {
|
|
107
|
+
this.handle = await fs.open(this.filePath, "w+");
|
|
108
|
+
this.currentOffset = 0n;
|
|
109
|
+
}
|
|
110
|
+
this.startTimers();
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* 启动定时器
|
|
114
|
+
*/
|
|
115
|
+
startTimers() {
|
|
116
|
+
if (this.flushIntervalMs > 0) {
|
|
117
|
+
this.flushTimer = setInterval(() => {
|
|
118
|
+
this.flush().catch(() => {});
|
|
119
|
+
}, this.flushIntervalMs);
|
|
120
|
+
}
|
|
121
|
+
if (this.fsyncStrategy === "interval" && this.fsyncIntervalMs > 0) {
|
|
122
|
+
this.fsyncTimer = setInterval(() => {
|
|
123
|
+
this.fsync().catch(() => {});
|
|
124
|
+
}, this.fsyncIntervalMs);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* 停止定时器
|
|
129
|
+
*/
|
|
130
|
+
stopTimers() {
|
|
131
|
+
if (this.flushTimer) {
|
|
132
|
+
clearInterval(this.flushTimer);
|
|
133
|
+
this.flushTimer = null;
|
|
134
|
+
}
|
|
135
|
+
if (this.fsyncTimer) {
|
|
136
|
+
clearInterval(this.fsyncTimer);
|
|
137
|
+
this.fsyncTimer = null;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* 序列化 WAL 记录
|
|
142
|
+
*/
|
|
143
|
+
serializeRecord(record) {
|
|
144
|
+
const keyLen = Buffer.byteLength(record.key, "utf8");
|
|
145
|
+
const valueLen = record.value ? record.value.length : 0;
|
|
146
|
+
const headerSize = 8 + 8 + 1 + 4 + 4;
|
|
147
|
+
const totalSize = headerSize + keyLen + valueLen + 4;
|
|
148
|
+
const writer = new OptimizedBuffer_1.OptimizedBufferWriter(totalSize);
|
|
149
|
+
writer.writeBigUInt64LE(record.lsn);
|
|
150
|
+
writer.writeBigUInt64LE(record.transactionId);
|
|
151
|
+
writer.writeUInt8(record.operationType);
|
|
152
|
+
writer.writeUInt32LE(keyLen);
|
|
153
|
+
writer.writeUInt32LE(valueLen);
|
|
154
|
+
writer.writeStringRaw(record.key);
|
|
155
|
+
if (record.value && valueLen > 0) {
|
|
156
|
+
writer.writeBuffer(record.value);
|
|
157
|
+
}
|
|
158
|
+
const checksum = this.calculateChecksum(writer.data, 0, writer.position);
|
|
159
|
+
writer.writeUInt32LE(checksum);
|
|
160
|
+
return writer.data;
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* 计算校验和
|
|
164
|
+
*/
|
|
165
|
+
calculateChecksum(buffer, offset, length) {
|
|
166
|
+
let crc = 0xffffffff;
|
|
167
|
+
const table = this.getCrc32Table();
|
|
168
|
+
for (let i = offset; i < offset + length; i++) {
|
|
169
|
+
const byte = buffer[i];
|
|
170
|
+
crc = (crc >>> 8) ^ table[(crc ^ byte) & 0xff];
|
|
171
|
+
}
|
|
172
|
+
return (crc ^ 0xffffffff) >>> 0;
|
|
173
|
+
}
|
|
174
|
+
getCrc32Table() {
|
|
175
|
+
if (!this.crc32Table) {
|
|
176
|
+
this.crc32Table = new Uint32Array(256);
|
|
177
|
+
for (let i = 0; i < 256; i++) {
|
|
178
|
+
let crc = i;
|
|
179
|
+
for (let j = 0; j < 8; j++) {
|
|
180
|
+
crc = crc & 1 ? 0xedb88320 ^ (crc >>> 1) : crc >>> 1;
|
|
181
|
+
}
|
|
182
|
+
this.crc32Table[i] = crc;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
return this.crc32Table;
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* 添加记录到队列
|
|
189
|
+
* @param record WAL 记录
|
|
190
|
+
*/
|
|
191
|
+
async append(record) {
|
|
192
|
+
if (this.closed) {
|
|
193
|
+
throw new Error("BatchWALWriter is closed");
|
|
194
|
+
}
|
|
195
|
+
const buffer = this.serializeRecord(record);
|
|
196
|
+
if (this.queue.length >= this.queueCapacity) {
|
|
197
|
+
await this.flush();
|
|
198
|
+
}
|
|
199
|
+
this.queue.push({ record, buffer });
|
|
200
|
+
if (this.queue.length >= this.batchSize) {
|
|
201
|
+
await this.flush();
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* 批量添加记录
|
|
206
|
+
* @param records WAL 记录数组
|
|
207
|
+
*/
|
|
208
|
+
async appendMany(records) {
|
|
209
|
+
for (const record of records) {
|
|
210
|
+
await this.append(record);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* 刷新队列到磁盘
|
|
215
|
+
*/
|
|
216
|
+
async flush() {
|
|
217
|
+
if (this.closed) {
|
|
218
|
+
return {
|
|
219
|
+
recordsWritten: 0,
|
|
220
|
+
bytesWritten: 0,
|
|
221
|
+
durationMs: 0,
|
|
222
|
+
fsynced: false,
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
if (this.isFlushing) {
|
|
226
|
+
this.pendingFlush = true;
|
|
227
|
+
return {
|
|
228
|
+
recordsWritten: 0,
|
|
229
|
+
bytesWritten: 0,
|
|
230
|
+
durationMs: 0,
|
|
231
|
+
fsynced: false,
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
if (this.queue.length === 0) {
|
|
235
|
+
return {
|
|
236
|
+
recordsWritten: 0,
|
|
237
|
+
bytesWritten: 0,
|
|
238
|
+
durationMs: 0,
|
|
239
|
+
fsynced: false,
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
this.isFlushing = true;
|
|
243
|
+
const startTime = Date.now();
|
|
244
|
+
try {
|
|
245
|
+
if (!this.handle) {
|
|
246
|
+
await this.open();
|
|
247
|
+
}
|
|
248
|
+
const entries = this.queue.splice(0, this.queue.length);
|
|
249
|
+
const concatenator = new OptimizedBuffer_1.BufferConcatenator();
|
|
250
|
+
for (const entry of entries) {
|
|
251
|
+
concatenator.append(entry.buffer);
|
|
252
|
+
}
|
|
253
|
+
const buffer = concatenator.concat();
|
|
254
|
+
const bytesWritten = buffer.length;
|
|
255
|
+
await this.handle.write(buffer, 0, buffer.length, Number(this.currentOffset));
|
|
256
|
+
this.currentOffset += BigInt(bytesWritten);
|
|
257
|
+
this.totalWritten += entries.length;
|
|
258
|
+
this.writeCountSinceFsync += entries.length;
|
|
259
|
+
this.lastFlushTime = Date.now();
|
|
260
|
+
let fsynced = false;
|
|
261
|
+
if (this.fsyncStrategy === "always") {
|
|
262
|
+
await this.fsync();
|
|
263
|
+
fsynced = true;
|
|
264
|
+
} else if (this.fsyncStrategy === "batch" && this.writeCountSinceFsync >= this.fsyncBatchSize) {
|
|
265
|
+
await this.fsync();
|
|
266
|
+
fsynced = true;
|
|
267
|
+
}
|
|
268
|
+
const durationMs = Date.now() - startTime;
|
|
269
|
+
return {
|
|
270
|
+
recordsWritten: entries.length,
|
|
271
|
+
bytesWritten,
|
|
272
|
+
durationMs,
|
|
273
|
+
fsynced,
|
|
274
|
+
};
|
|
275
|
+
} finally {
|
|
276
|
+
this.isFlushing = false;
|
|
277
|
+
if (this.pendingFlush) {
|
|
278
|
+
this.pendingFlush = false;
|
|
279
|
+
this.flush().catch(() => {});
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* 同步到磁盘
|
|
285
|
+
*/
|
|
286
|
+
async fsync() {
|
|
287
|
+
if (this.closed || !this.handle) {
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
await this.handle.sync();
|
|
291
|
+
this.writeCountSinceFsync = 0;
|
|
292
|
+
this.lastFsyncTime = Date.now();
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* 获取统计信息
|
|
296
|
+
*/
|
|
297
|
+
getStats() {
|
|
298
|
+
return {
|
|
299
|
+
pendingCount: this.queue.length,
|
|
300
|
+
writtenCount: this.totalWritten,
|
|
301
|
+
lastFlushTime: this.lastFlushTime,
|
|
302
|
+
lastFsyncTime: this.lastFsyncTime,
|
|
303
|
+
queueCapacity: this.queueCapacity,
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* 获取当前偏移量
|
|
308
|
+
*/
|
|
309
|
+
getCurrentOffset() {
|
|
310
|
+
return this.currentOffset;
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
* 获取文件路径
|
|
314
|
+
*/
|
|
315
|
+
getFilePath() {
|
|
316
|
+
return this.filePath;
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* 清空队列
|
|
320
|
+
*/
|
|
321
|
+
clearQueue() {
|
|
322
|
+
this.queue = [];
|
|
323
|
+
}
|
|
324
|
+
/**
|
|
325
|
+
* 关闭写入器
|
|
326
|
+
*/
|
|
327
|
+
async close() {
|
|
328
|
+
if (this.closed) {
|
|
329
|
+
return;
|
|
330
|
+
}
|
|
331
|
+
this.closed = true;
|
|
332
|
+
this.stopTimers();
|
|
333
|
+
await this.flush();
|
|
334
|
+
if (this.fsyncStrategy !== "manual") {
|
|
335
|
+
await this.fsync();
|
|
336
|
+
}
|
|
337
|
+
if (this.handle) {
|
|
338
|
+
await this.handle.close();
|
|
339
|
+
this.handle = null;
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
/**
|
|
343
|
+
* 清空文件
|
|
344
|
+
*/
|
|
345
|
+
async clear() {
|
|
346
|
+
await this.close();
|
|
347
|
+
await fs.truncate(this.filePath, 0);
|
|
348
|
+
this.queue = [];
|
|
349
|
+
this.currentOffset = 0n;
|
|
350
|
+
this.writeCountSinceFsync = 0;
|
|
351
|
+
this.totalWritten = 0;
|
|
352
|
+
this.closed = false;
|
|
353
|
+
await this.open();
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
exports.BatchWalWriter = BatchWalWriter;
|
|
357
|
+
/**
|
|
358
|
+
* 批量写入管理器
|
|
359
|
+
* 提供更高层的批量写入接口
|
|
360
|
+
*/
|
|
361
|
+
class BatchWriteManager {
|
|
362
|
+
/**
|
|
363
|
+
* 创建批量写入管理器
|
|
364
|
+
* @param defaultOptions 默认配置
|
|
365
|
+
*/
|
|
366
|
+
constructor(defaultOptions = {}) {
|
|
367
|
+
this.writers = new Map();
|
|
368
|
+
this.defaultOptions = defaultOptions;
|
|
369
|
+
}
|
|
370
|
+
/**
|
|
371
|
+
* 获取或创建写入器
|
|
372
|
+
* @param name 写入器名称
|
|
373
|
+
* @param filePath 文件路径
|
|
374
|
+
* @param options 配置选项
|
|
375
|
+
*/
|
|
376
|
+
async getWriter(name, filePath, options) {
|
|
377
|
+
let writer = this.writers.get(name);
|
|
378
|
+
if (!writer) {
|
|
379
|
+
writer = new BatchWalWriter(filePath, {
|
|
380
|
+
...this.defaultOptions,
|
|
381
|
+
...options,
|
|
382
|
+
});
|
|
383
|
+
await writer.open();
|
|
384
|
+
this.writers.set(name, writer);
|
|
385
|
+
}
|
|
386
|
+
return writer;
|
|
387
|
+
}
|
|
388
|
+
/**
|
|
389
|
+
* 写入记录
|
|
390
|
+
* @param name 写入器名称
|
|
391
|
+
* @param record WAL 记录
|
|
392
|
+
*/
|
|
393
|
+
async append(name, record) {
|
|
394
|
+
const writer = this.writers.get(name);
|
|
395
|
+
if (!writer) {
|
|
396
|
+
throw new Error(`Writer "${name}" not found`);
|
|
397
|
+
}
|
|
398
|
+
await writer.append(record);
|
|
399
|
+
}
|
|
400
|
+
/**
|
|
401
|
+
* 刷新指定写入器
|
|
402
|
+
* @param name 写入器名称
|
|
403
|
+
*/
|
|
404
|
+
async flush(name) {
|
|
405
|
+
const writer = this.writers.get(name);
|
|
406
|
+
if (!writer) {
|
|
407
|
+
throw new Error(`Writer "${name}" not found`);
|
|
408
|
+
}
|
|
409
|
+
return writer.flush();
|
|
410
|
+
}
|
|
411
|
+
/**
|
|
412
|
+
* 刷新所有写入器
|
|
413
|
+
*/
|
|
414
|
+
async flushAll() {
|
|
415
|
+
const results = new Map();
|
|
416
|
+
for (const [name, writer] of this.writers) {
|
|
417
|
+
results.set(name, await writer.flush());
|
|
418
|
+
}
|
|
419
|
+
return results;
|
|
420
|
+
}
|
|
421
|
+
/**
|
|
422
|
+
* 同步指定写入器
|
|
423
|
+
* @param name 写入器名称
|
|
424
|
+
*/
|
|
425
|
+
async fsync(name) {
|
|
426
|
+
const writer = this.writers.get(name);
|
|
427
|
+
if (!writer) {
|
|
428
|
+
throw new Error(`Writer "${name}" not found`);
|
|
429
|
+
}
|
|
430
|
+
await writer.fsync();
|
|
431
|
+
}
|
|
432
|
+
/**
|
|
433
|
+
* 同步所有写入器
|
|
434
|
+
*/
|
|
435
|
+
async fsyncAll() {
|
|
436
|
+
const promises = [];
|
|
437
|
+
for (const writer of this.writers.values()) {
|
|
438
|
+
promises.push(writer.fsync());
|
|
439
|
+
}
|
|
440
|
+
await Promise.all(promises);
|
|
441
|
+
}
|
|
442
|
+
/**
|
|
443
|
+
* 关闭指定写入器
|
|
444
|
+
* @param name 写入器名称
|
|
445
|
+
*/
|
|
446
|
+
async closeWriter(name) {
|
|
447
|
+
const writer = this.writers.get(name);
|
|
448
|
+
if (writer) {
|
|
449
|
+
await writer.close();
|
|
450
|
+
this.writers.delete(name);
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
/**
|
|
454
|
+
* 关闭所有写入器
|
|
455
|
+
*/
|
|
456
|
+
async closeAll() {
|
|
457
|
+
const promises = [];
|
|
458
|
+
for (const writer of this.writers.values()) {
|
|
459
|
+
promises.push(writer.close());
|
|
460
|
+
}
|
|
461
|
+
await Promise.all(promises);
|
|
462
|
+
this.writers.clear();
|
|
463
|
+
}
|
|
464
|
+
/**
|
|
465
|
+
* 获取所有写入器名称
|
|
466
|
+
*/
|
|
467
|
+
getWriterNames() {
|
|
468
|
+
return Array.from(this.writers.keys());
|
|
469
|
+
}
|
|
470
|
+
/**
|
|
471
|
+
* 获取写入器统计信息
|
|
472
|
+
* @param name 写入器名称
|
|
473
|
+
*/
|
|
474
|
+
getStats(name) {
|
|
475
|
+
const writer = this.writers.get(name);
|
|
476
|
+
return writer?.getStats();
|
|
477
|
+
}
|
|
478
|
+
/**
|
|
479
|
+
* 获取所有写入器统计信息
|
|
480
|
+
*/
|
|
481
|
+
getAllStats() {
|
|
482
|
+
const stats = new Map();
|
|
483
|
+
for (const [name, writer] of this.writers) {
|
|
484
|
+
stats.set(name, writer.getStats());
|
|
485
|
+
}
|
|
486
|
+
return stats;
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
exports.BatchWriteManager = BatchWriteManager;
|
|
490
|
+
//# sourceMappingURL=BatchWalWriter.js.map
|