@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,875 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* 列式存储实现
|
|
4
|
+
* 使用平行数组存储数据,降低 GC 压力,提高聚合和范围扫描性能
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.ColumnarStorage = void 0;
|
|
8
|
+
const types_1 = require("./types");
|
|
9
|
+
/**
|
|
10
|
+
* 类型化数组列实现
|
|
11
|
+
*/
|
|
12
|
+
class TypedArrayColumn {
|
|
13
|
+
constructor(name, type, capacity, createArray) {
|
|
14
|
+
this.name = name;
|
|
15
|
+
this.type = type;
|
|
16
|
+
this._capacity = capacity;
|
|
17
|
+
this._length = 0;
|
|
18
|
+
this.data = createArray(capacity);
|
|
19
|
+
this.nullBitmap = new Uint8Array(Math.ceil(capacity / 8));
|
|
20
|
+
}
|
|
21
|
+
get length() {
|
|
22
|
+
return this._length;
|
|
23
|
+
}
|
|
24
|
+
getData() {
|
|
25
|
+
return this.data;
|
|
26
|
+
}
|
|
27
|
+
get(index) {
|
|
28
|
+
if (index < 0 || index >= this._length) {
|
|
29
|
+
return undefined;
|
|
30
|
+
}
|
|
31
|
+
if (this.isNull(index)) {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
return this.getValue(index);
|
|
35
|
+
}
|
|
36
|
+
set(index, value) {
|
|
37
|
+
if (index < 0 || index >= this._capacity) {
|
|
38
|
+
throw new RangeError(`Index ${index} out of bounds`);
|
|
39
|
+
}
|
|
40
|
+
if (value === null || value === undefined) {
|
|
41
|
+
this.setNull(index, true);
|
|
42
|
+
} else {
|
|
43
|
+
this.setNull(index, false);
|
|
44
|
+
this.setValue(index, value);
|
|
45
|
+
}
|
|
46
|
+
if (index >= this._length) {
|
|
47
|
+
this._length = index + 1;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
push(value) {
|
|
51
|
+
if (this._length >= this._capacity) {
|
|
52
|
+
throw new Error("Column is full, call grow() first");
|
|
53
|
+
}
|
|
54
|
+
this.set(this._length, value);
|
|
55
|
+
}
|
|
56
|
+
fill(value, start, end) {
|
|
57
|
+
for (let i = start; i < end; i++) {
|
|
58
|
+
this.set(i, value);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
isNull(index) {
|
|
62
|
+
const byteIndex = Math.floor(index / 8);
|
|
63
|
+
const bitIndex = index % 8;
|
|
64
|
+
return (this.nullBitmap[byteIndex] & (1 << bitIndex)) !== 0;
|
|
65
|
+
}
|
|
66
|
+
setNull(index, isNull) {
|
|
67
|
+
const byteIndex = Math.floor(index / 8);
|
|
68
|
+
const bitIndex = index % 8;
|
|
69
|
+
if (isNull) {
|
|
70
|
+
this.nullBitmap[byteIndex] |= 1 << bitIndex;
|
|
71
|
+
} else {
|
|
72
|
+
this.nullBitmap[byteIndex] &= ~(1 << bitIndex);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
getMemoryUsage() {
|
|
76
|
+
return this.data.byteLength + this.nullBitmap.byteLength + 8;
|
|
77
|
+
}
|
|
78
|
+
getNonNullCount() {
|
|
79
|
+
let count = 0;
|
|
80
|
+
for (let i = 0; i < this._length; i++) {
|
|
81
|
+
if (!this.isNull(i)) {
|
|
82
|
+
count++;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return count;
|
|
86
|
+
}
|
|
87
|
+
grow(newCapacity) {
|
|
88
|
+
if (newCapacity <= this._capacity) {
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
const newData = this.createArray(newCapacity);
|
|
92
|
+
newData.set(this.data);
|
|
93
|
+
this.data = newData;
|
|
94
|
+
const newNullBitmap = new Uint8Array(Math.ceil(newCapacity / 8));
|
|
95
|
+
newNullBitmap.set(this.nullBitmap);
|
|
96
|
+
this.nullBitmap = newNullBitmap;
|
|
97
|
+
this._capacity = newCapacity;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Int8 列
|
|
102
|
+
*/
|
|
103
|
+
class Int8Column extends TypedArrayColumn {
|
|
104
|
+
constructor(name, capacity) {
|
|
105
|
+
super(name, types_1.ColumnType.Int8, capacity, (s) => new Int8Array(s));
|
|
106
|
+
}
|
|
107
|
+
getValue(index) {
|
|
108
|
+
return this.data[index];
|
|
109
|
+
}
|
|
110
|
+
setValue(index, value) {
|
|
111
|
+
this.data[index] = value;
|
|
112
|
+
}
|
|
113
|
+
createArray(size) {
|
|
114
|
+
return new Int8Array(size);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Int16 列
|
|
119
|
+
*/
|
|
120
|
+
class Int16Column extends TypedArrayColumn {
|
|
121
|
+
constructor(name, capacity) {
|
|
122
|
+
super(name, types_1.ColumnType.Int16, capacity, (s) => new Int16Array(s));
|
|
123
|
+
}
|
|
124
|
+
getValue(index) {
|
|
125
|
+
return this.data[index];
|
|
126
|
+
}
|
|
127
|
+
setValue(index, value) {
|
|
128
|
+
this.data[index] = value;
|
|
129
|
+
}
|
|
130
|
+
createArray(size) {
|
|
131
|
+
return new Int16Array(size);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Int32 列
|
|
136
|
+
*/
|
|
137
|
+
class Int32Column extends TypedArrayColumn {
|
|
138
|
+
constructor(name, capacity) {
|
|
139
|
+
super(name, types_1.ColumnType.Int32, capacity, (s) => new Int32Array(s));
|
|
140
|
+
}
|
|
141
|
+
getValue(index) {
|
|
142
|
+
return this.data[index];
|
|
143
|
+
}
|
|
144
|
+
setValue(index, value) {
|
|
145
|
+
this.data[index] = value;
|
|
146
|
+
}
|
|
147
|
+
createArray(size) {
|
|
148
|
+
return new Int32Array(size);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Int64 列(使用 BigInt64Array)
|
|
153
|
+
*/
|
|
154
|
+
class Int64Column extends TypedArrayColumn {
|
|
155
|
+
constructor(name, capacity) {
|
|
156
|
+
super(name, types_1.ColumnType.Int64, capacity, (s) => new BigInt64Array(s));
|
|
157
|
+
}
|
|
158
|
+
getValue(index) {
|
|
159
|
+
return this.data[index];
|
|
160
|
+
}
|
|
161
|
+
setValue(index, value) {
|
|
162
|
+
this.data[index] = BigInt(value);
|
|
163
|
+
}
|
|
164
|
+
createArray(size) {
|
|
165
|
+
return new BigInt64Array(size);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* UInt8 列
|
|
170
|
+
*/
|
|
171
|
+
class UInt8Column extends TypedArrayColumn {
|
|
172
|
+
constructor(name, capacity) {
|
|
173
|
+
super(name, types_1.ColumnType.UInt8, capacity, (s) => new Uint8Array(s));
|
|
174
|
+
}
|
|
175
|
+
getValue(index) {
|
|
176
|
+
return this.data[index];
|
|
177
|
+
}
|
|
178
|
+
setValue(index, value) {
|
|
179
|
+
this.data[index] = value;
|
|
180
|
+
}
|
|
181
|
+
createArray(size) {
|
|
182
|
+
return new Uint8Array(size);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* UInt16 列
|
|
187
|
+
*/
|
|
188
|
+
class UInt16Column extends TypedArrayColumn {
|
|
189
|
+
constructor(name, capacity) {
|
|
190
|
+
super(name, types_1.ColumnType.UInt16, capacity, (s) => new Uint16Array(s));
|
|
191
|
+
}
|
|
192
|
+
getValue(index) {
|
|
193
|
+
return this.data[index];
|
|
194
|
+
}
|
|
195
|
+
setValue(index, value) {
|
|
196
|
+
this.data[index] = value;
|
|
197
|
+
}
|
|
198
|
+
createArray(size) {
|
|
199
|
+
return new Uint16Array(size);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* UInt32 列
|
|
204
|
+
*/
|
|
205
|
+
class UInt32Column extends TypedArrayColumn {
|
|
206
|
+
constructor(name, capacity) {
|
|
207
|
+
super(name, types_1.ColumnType.UInt32, capacity, (s) => new Uint32Array(s));
|
|
208
|
+
}
|
|
209
|
+
getValue(index) {
|
|
210
|
+
return this.data[index];
|
|
211
|
+
}
|
|
212
|
+
setValue(index, value) {
|
|
213
|
+
this.data[index] = value;
|
|
214
|
+
}
|
|
215
|
+
createArray(size) {
|
|
216
|
+
return new Uint32Array(size);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* UInt64 列
|
|
221
|
+
*/
|
|
222
|
+
class UInt64Column extends TypedArrayColumn {
|
|
223
|
+
constructor(name, capacity) {
|
|
224
|
+
super(name, types_1.ColumnType.UInt64, capacity, (s) => new BigUint64Array(s));
|
|
225
|
+
}
|
|
226
|
+
getValue(index) {
|
|
227
|
+
return this.data[index];
|
|
228
|
+
}
|
|
229
|
+
setValue(index, value) {
|
|
230
|
+
this.data[index] = BigInt(value);
|
|
231
|
+
}
|
|
232
|
+
createArray(size) {
|
|
233
|
+
return new BigUint64Array(size);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Float32 列
|
|
238
|
+
*/
|
|
239
|
+
class Float32Column extends TypedArrayColumn {
|
|
240
|
+
constructor(name, capacity) {
|
|
241
|
+
super(name, types_1.ColumnType.Float32, capacity, (s) => new Float32Array(s));
|
|
242
|
+
}
|
|
243
|
+
getValue(index) {
|
|
244
|
+
return this.data[index];
|
|
245
|
+
}
|
|
246
|
+
setValue(index, value) {
|
|
247
|
+
this.data[index] = value;
|
|
248
|
+
}
|
|
249
|
+
createArray(size) {
|
|
250
|
+
return new Float32Array(size);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Float64 列
|
|
255
|
+
*/
|
|
256
|
+
class Float64Column extends TypedArrayColumn {
|
|
257
|
+
constructor(name, capacity) {
|
|
258
|
+
super(name, types_1.ColumnType.Float64, capacity, (s) => new Float64Array(s));
|
|
259
|
+
}
|
|
260
|
+
getValue(index) {
|
|
261
|
+
return this.data[index];
|
|
262
|
+
}
|
|
263
|
+
setValue(index, value) {
|
|
264
|
+
this.data[index] = value;
|
|
265
|
+
}
|
|
266
|
+
createArray(size) {
|
|
267
|
+
return new Float64Array(size);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* 字符串列
|
|
272
|
+
*/
|
|
273
|
+
class StringColumn {
|
|
274
|
+
constructor(name, capacity) {
|
|
275
|
+
this.type = types_1.ColumnType.String;
|
|
276
|
+
this.name = name;
|
|
277
|
+
this._capacity = capacity;
|
|
278
|
+
this._length = 0;
|
|
279
|
+
this.data = new Array(capacity);
|
|
280
|
+
this.nullBitmap = new Uint8Array(Math.ceil(capacity / 8));
|
|
281
|
+
}
|
|
282
|
+
get length() {
|
|
283
|
+
return this._length;
|
|
284
|
+
}
|
|
285
|
+
get(index) {
|
|
286
|
+
if (index < 0 || index >= this._length) {
|
|
287
|
+
return undefined;
|
|
288
|
+
}
|
|
289
|
+
if (this.isNull(index)) {
|
|
290
|
+
return null;
|
|
291
|
+
}
|
|
292
|
+
return this.data[index];
|
|
293
|
+
}
|
|
294
|
+
set(index, value) {
|
|
295
|
+
if (index < 0 || index >= this._capacity) {
|
|
296
|
+
throw new RangeError(`Index ${index} out of bounds`);
|
|
297
|
+
}
|
|
298
|
+
if (value === null || value === undefined) {
|
|
299
|
+
this.setNull(index, true);
|
|
300
|
+
this.data[index] = "";
|
|
301
|
+
} else {
|
|
302
|
+
this.setNull(index, false);
|
|
303
|
+
this.data[index] = String(value);
|
|
304
|
+
}
|
|
305
|
+
if (index >= this._length) {
|
|
306
|
+
this._length = index + 1;
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
push(value) {
|
|
310
|
+
if (this._length >= this._capacity) {
|
|
311
|
+
throw new Error("Column is full, call grow() first");
|
|
312
|
+
}
|
|
313
|
+
this.set(this._length, value);
|
|
314
|
+
}
|
|
315
|
+
fill(value, start, end) {
|
|
316
|
+
for (let i = start; i < end; i++) {
|
|
317
|
+
this.set(i, value);
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
getMemoryUsage() {
|
|
321
|
+
let total = this.nullBitmap.byteLength + 8;
|
|
322
|
+
for (let i = 0; i < this._length; i++) {
|
|
323
|
+
if (!this.isNull(i) && this.data[i]) {
|
|
324
|
+
total += this.data[i].length * 2;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
return total;
|
|
328
|
+
}
|
|
329
|
+
getNonNullCount() {
|
|
330
|
+
let count = 0;
|
|
331
|
+
for (let i = 0; i < this._length; i++) {
|
|
332
|
+
if (!this.isNull(i)) {
|
|
333
|
+
count++;
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
return count;
|
|
337
|
+
}
|
|
338
|
+
grow(newCapacity) {
|
|
339
|
+
if (newCapacity <= this._capacity) {
|
|
340
|
+
return;
|
|
341
|
+
}
|
|
342
|
+
this.data.length = newCapacity;
|
|
343
|
+
const newNullBitmap = new Uint8Array(Math.ceil(newCapacity / 8));
|
|
344
|
+
newNullBitmap.set(this.nullBitmap);
|
|
345
|
+
this.nullBitmap = newNullBitmap;
|
|
346
|
+
this._capacity = newCapacity;
|
|
347
|
+
}
|
|
348
|
+
isNull(index) {
|
|
349
|
+
const byteIndex = Math.floor(index / 8);
|
|
350
|
+
const bitIndex = index % 8;
|
|
351
|
+
return (this.nullBitmap[byteIndex] & (1 << bitIndex)) !== 0;
|
|
352
|
+
}
|
|
353
|
+
setNull(index, isNull) {
|
|
354
|
+
const byteIndex = Math.floor(index / 8);
|
|
355
|
+
const bitIndex = index % 8;
|
|
356
|
+
if (isNull) {
|
|
357
|
+
this.nullBitmap[byteIndex] |= 1 << bitIndex;
|
|
358
|
+
} else {
|
|
359
|
+
this.nullBitmap[byteIndex] &= ~(1 << bitIndex);
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
/**
|
|
364
|
+
* 布尔列
|
|
365
|
+
*/
|
|
366
|
+
class BooleanColumn {
|
|
367
|
+
constructor(name, capacity) {
|
|
368
|
+
this.type = types_1.ColumnType.Boolean;
|
|
369
|
+
this.name = name;
|
|
370
|
+
this._capacity = capacity;
|
|
371
|
+
this._length = 0;
|
|
372
|
+
this.data = new Uint8Array(capacity);
|
|
373
|
+
this.nullBitmap = new Uint8Array(Math.ceil(capacity / 8));
|
|
374
|
+
}
|
|
375
|
+
get length() {
|
|
376
|
+
return this._length;
|
|
377
|
+
}
|
|
378
|
+
get(index) {
|
|
379
|
+
if (index < 0 || index >= this._length) {
|
|
380
|
+
return undefined;
|
|
381
|
+
}
|
|
382
|
+
if (this.isNull(index)) {
|
|
383
|
+
return null;
|
|
384
|
+
}
|
|
385
|
+
return this.data[index] === 1;
|
|
386
|
+
}
|
|
387
|
+
set(index, value) {
|
|
388
|
+
if (index < 0 || index >= this._capacity) {
|
|
389
|
+
throw new RangeError(`Index ${index} out of bounds`);
|
|
390
|
+
}
|
|
391
|
+
if (value === null || value === undefined) {
|
|
392
|
+
this.setNull(index, true);
|
|
393
|
+
this.data[index] = 0;
|
|
394
|
+
} else {
|
|
395
|
+
this.setNull(index, false);
|
|
396
|
+
this.data[index] = value ? 1 : 0;
|
|
397
|
+
}
|
|
398
|
+
if (index >= this._length) {
|
|
399
|
+
this._length = index + 1;
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
push(value) {
|
|
403
|
+
if (this._length >= this._capacity) {
|
|
404
|
+
throw new Error("Column is full, call grow() first");
|
|
405
|
+
}
|
|
406
|
+
this.set(this._length, value);
|
|
407
|
+
}
|
|
408
|
+
fill(value, start, end) {
|
|
409
|
+
for (let i = start; i < end; i++) {
|
|
410
|
+
this.set(i, value);
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
getMemoryUsage() {
|
|
414
|
+
return this.data.byteLength + this.nullBitmap.byteLength + 8;
|
|
415
|
+
}
|
|
416
|
+
getNonNullCount() {
|
|
417
|
+
let count = 0;
|
|
418
|
+
for (let i = 0; i < this._length; i++) {
|
|
419
|
+
if (!this.isNull(i)) {
|
|
420
|
+
count++;
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
return count;
|
|
424
|
+
}
|
|
425
|
+
grow(newCapacity) {
|
|
426
|
+
if (newCapacity <= this._capacity) {
|
|
427
|
+
return;
|
|
428
|
+
}
|
|
429
|
+
const newData = new Uint8Array(newCapacity);
|
|
430
|
+
newData.set(this.data);
|
|
431
|
+
this.data = newData;
|
|
432
|
+
const newNullBitmap = new Uint8Array(Math.ceil(newCapacity / 8));
|
|
433
|
+
newNullBitmap.set(this.nullBitmap);
|
|
434
|
+
this.nullBitmap = newNullBitmap;
|
|
435
|
+
this._capacity = newCapacity;
|
|
436
|
+
}
|
|
437
|
+
isNull(index) {
|
|
438
|
+
const byteIndex = Math.floor(index / 8);
|
|
439
|
+
const bitIndex = index % 8;
|
|
440
|
+
return (this.nullBitmap[byteIndex] & (1 << bitIndex)) !== 0;
|
|
441
|
+
}
|
|
442
|
+
setNull(index, isNull) {
|
|
443
|
+
const byteIndex = Math.floor(index / 8);
|
|
444
|
+
const bitIndex = index % 8;
|
|
445
|
+
if (isNull) {
|
|
446
|
+
this.nullBitmap[byteIndex] |= 1 << bitIndex;
|
|
447
|
+
} else {
|
|
448
|
+
this.nullBitmap[byteIndex] &= ~(1 << bitIndex);
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
/**
|
|
453
|
+
* 列式存储
|
|
454
|
+
* 使用平行数组存储数据,降低 GC 压力
|
|
455
|
+
*/
|
|
456
|
+
class ColumnarStorage {
|
|
457
|
+
/**
|
|
458
|
+
* 创建列式存储实例
|
|
459
|
+
* @param options 配置选项
|
|
460
|
+
*/
|
|
461
|
+
constructor(options) {
|
|
462
|
+
this.columns = new Map();
|
|
463
|
+
this.columnOrder = [];
|
|
464
|
+
this.capacity = options.initialCapacity ?? 1024;
|
|
465
|
+
this.autoGrow = options.autoGrow ?? true;
|
|
466
|
+
for (const colDef of options.columns) {
|
|
467
|
+
this.addColumn(colDef);
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
/**
|
|
471
|
+
* 添加列
|
|
472
|
+
* @param definition 列定义
|
|
473
|
+
*/
|
|
474
|
+
addColumn(definition) {
|
|
475
|
+
if (this.columns.has(definition.name)) {
|
|
476
|
+
throw new Error(`Column "${definition.name}" already exists`);
|
|
477
|
+
}
|
|
478
|
+
const column = this.createColumn(definition);
|
|
479
|
+
this.columns.set(definition.name, column);
|
|
480
|
+
this.columnOrder.push(definition.name);
|
|
481
|
+
}
|
|
482
|
+
/**
|
|
483
|
+
* 创建列实例
|
|
484
|
+
*/
|
|
485
|
+
createColumn(definition) {
|
|
486
|
+
const { name, type } = definition;
|
|
487
|
+
switch (type) {
|
|
488
|
+
case types_1.ColumnType.Int8:
|
|
489
|
+
return new Int8Column(name, this.capacity);
|
|
490
|
+
case types_1.ColumnType.Int16:
|
|
491
|
+
return new Int16Column(name, this.capacity);
|
|
492
|
+
case types_1.ColumnType.Int32:
|
|
493
|
+
return new Int32Column(name, this.capacity);
|
|
494
|
+
case types_1.ColumnType.Int64:
|
|
495
|
+
return new Int64Column(name, this.capacity);
|
|
496
|
+
case types_1.ColumnType.UInt8:
|
|
497
|
+
return new UInt8Column(name, this.capacity);
|
|
498
|
+
case types_1.ColumnType.UInt16:
|
|
499
|
+
return new UInt16Column(name, this.capacity);
|
|
500
|
+
case types_1.ColumnType.UInt32:
|
|
501
|
+
return new UInt32Column(name, this.capacity);
|
|
502
|
+
case types_1.ColumnType.UInt64:
|
|
503
|
+
return new UInt64Column(name, this.capacity);
|
|
504
|
+
case types_1.ColumnType.Float32:
|
|
505
|
+
return new Float32Column(name, this.capacity);
|
|
506
|
+
case types_1.ColumnType.Float64:
|
|
507
|
+
return new Float64Column(name, this.capacity);
|
|
508
|
+
case types_1.ColumnType.String:
|
|
509
|
+
return new StringColumn(name, this.capacity);
|
|
510
|
+
case types_1.ColumnType.Boolean:
|
|
511
|
+
return new BooleanColumn(name, this.capacity);
|
|
512
|
+
default:
|
|
513
|
+
throw new Error(`Unsupported column type: ${type}`);
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
/**
|
|
517
|
+
* 获取行数
|
|
518
|
+
*/
|
|
519
|
+
get rowCount() {
|
|
520
|
+
if (this.columnOrder.length === 0) {
|
|
521
|
+
return 0;
|
|
522
|
+
}
|
|
523
|
+
const firstColumn = this.columns.get(this.columnOrder[0]);
|
|
524
|
+
return firstColumn ? firstColumn.length : 0;
|
|
525
|
+
}
|
|
526
|
+
/**
|
|
527
|
+
* 获取列数
|
|
528
|
+
*/
|
|
529
|
+
get columnCount() {
|
|
530
|
+
return this.columns.size;
|
|
531
|
+
}
|
|
532
|
+
/**
|
|
533
|
+
* 获取列名称列表
|
|
534
|
+
*/
|
|
535
|
+
getColumnNames() {
|
|
536
|
+
return [...this.columnOrder];
|
|
537
|
+
}
|
|
538
|
+
/**
|
|
539
|
+
* 获取列类型
|
|
540
|
+
* @param columnName 列名称
|
|
541
|
+
*/
|
|
542
|
+
getColumnType(columnName) {
|
|
543
|
+
const column = this.columns.get(columnName);
|
|
544
|
+
return column?.type;
|
|
545
|
+
}
|
|
546
|
+
/**
|
|
547
|
+
* 插入一行数据
|
|
548
|
+
* @param row 行数据
|
|
549
|
+
* @returns 插入的行索引
|
|
550
|
+
*/
|
|
551
|
+
insert(row) {
|
|
552
|
+
const rowIndex = this.rowCount;
|
|
553
|
+
if (rowIndex >= this.capacity && this.autoGrow) {
|
|
554
|
+
this.grow(this.capacity * 2);
|
|
555
|
+
}
|
|
556
|
+
for (const [colName, value] of Object.entries(row)) {
|
|
557
|
+
const column = this.columns.get(colName);
|
|
558
|
+
if (column) {
|
|
559
|
+
column.push(value);
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
for (const colName of this.columnOrder) {
|
|
563
|
+
const column = this.columns.get(colName);
|
|
564
|
+
if (column.length <= rowIndex) {
|
|
565
|
+
column.push(null);
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
return rowIndex;
|
|
569
|
+
}
|
|
570
|
+
/**
|
|
571
|
+
* 批量插入数据
|
|
572
|
+
* @param rows 行数据数组
|
|
573
|
+
* @returns 插入的行索引范围
|
|
574
|
+
*/
|
|
575
|
+
insertMany(rows) {
|
|
576
|
+
const start = this.rowCount;
|
|
577
|
+
for (const row of rows) {
|
|
578
|
+
this.insert(row);
|
|
579
|
+
}
|
|
580
|
+
return { start, end: this.rowCount };
|
|
581
|
+
}
|
|
582
|
+
/**
|
|
583
|
+
* 获取单行数据
|
|
584
|
+
* @param rowIndex 行索引
|
|
585
|
+
*/
|
|
586
|
+
getRow(rowIndex) {
|
|
587
|
+
if (rowIndex < 0 || rowIndex >= this.rowCount) {
|
|
588
|
+
return null;
|
|
589
|
+
}
|
|
590
|
+
const row = {};
|
|
591
|
+
for (const colName of this.columnOrder) {
|
|
592
|
+
const column = this.columns.get(colName);
|
|
593
|
+
row[colName] = column.get(rowIndex);
|
|
594
|
+
}
|
|
595
|
+
return row;
|
|
596
|
+
}
|
|
597
|
+
/**
|
|
598
|
+
* 更新单行数据
|
|
599
|
+
* @param rowIndex 行索引
|
|
600
|
+
* @param row 新数据
|
|
601
|
+
*/
|
|
602
|
+
updateRow(rowIndex, row) {
|
|
603
|
+
if (rowIndex < 0 || rowIndex >= this.rowCount) {
|
|
604
|
+
return false;
|
|
605
|
+
}
|
|
606
|
+
for (const [colName, value] of Object.entries(row)) {
|
|
607
|
+
const column = this.columns.get(colName);
|
|
608
|
+
if (column) {
|
|
609
|
+
column.set(rowIndex, value);
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
return true;
|
|
613
|
+
}
|
|
614
|
+
/**
|
|
615
|
+
* 获取单列数据
|
|
616
|
+
* @param columnName 列名称
|
|
617
|
+
*/
|
|
618
|
+
getColumn(columnName) {
|
|
619
|
+
const column = this.columns.get(columnName);
|
|
620
|
+
if (!column) {
|
|
621
|
+
return [];
|
|
622
|
+
}
|
|
623
|
+
const result = [];
|
|
624
|
+
for (let i = 0; i < column.length; i++) {
|
|
625
|
+
result.push(column.get(i));
|
|
626
|
+
}
|
|
627
|
+
return result;
|
|
628
|
+
}
|
|
629
|
+
/**
|
|
630
|
+
* 获取类型化数组列(仅数值类型)
|
|
631
|
+
* @param columnName 列名称
|
|
632
|
+
*/
|
|
633
|
+
getTypedColumn(columnName) {
|
|
634
|
+
const column = this.columns.get(columnName);
|
|
635
|
+
if (!column) {
|
|
636
|
+
return null;
|
|
637
|
+
}
|
|
638
|
+
if (column instanceof TypedArrayColumn) {
|
|
639
|
+
return column.getData();
|
|
640
|
+
}
|
|
641
|
+
return null;
|
|
642
|
+
}
|
|
643
|
+
/**
|
|
644
|
+
* 聚合计算
|
|
645
|
+
* @param columnName 列名称
|
|
646
|
+
* @param type 聚合类型
|
|
647
|
+
*/
|
|
648
|
+
aggregate(columnName, type) {
|
|
649
|
+
const column = this.columns.get(columnName);
|
|
650
|
+
if (!column) {
|
|
651
|
+
return {
|
|
652
|
+
type,
|
|
653
|
+
field: columnName,
|
|
654
|
+
value: null,
|
|
655
|
+
recordCount: 0,
|
|
656
|
+
};
|
|
657
|
+
}
|
|
658
|
+
const values = [];
|
|
659
|
+
for (let i = 0; i < column.length; i++) {
|
|
660
|
+
const val = column.get(i);
|
|
661
|
+
if (val !== null && val !== undefined) {
|
|
662
|
+
if (typeof val === "number" || typeof val === "bigint") {
|
|
663
|
+
values.push(val);
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
if (values.length === 0) {
|
|
668
|
+
return {
|
|
669
|
+
type,
|
|
670
|
+
field: columnName,
|
|
671
|
+
value: null,
|
|
672
|
+
recordCount: 0,
|
|
673
|
+
};
|
|
674
|
+
}
|
|
675
|
+
let value = null;
|
|
676
|
+
switch (type) {
|
|
677
|
+
case "sum": {
|
|
678
|
+
if (typeof values[0] === "bigint") {
|
|
679
|
+
value = values.reduce((a, b) => a + b, 0n);
|
|
680
|
+
} else {
|
|
681
|
+
value = values.reduce((a, b) => a + b, 0);
|
|
682
|
+
}
|
|
683
|
+
break;
|
|
684
|
+
}
|
|
685
|
+
case "avg": {
|
|
686
|
+
if (typeof values[0] === "bigint") {
|
|
687
|
+
const sum = values.reduce((a, b) => a + b, 0n);
|
|
688
|
+
value = Number(sum) / values.length;
|
|
689
|
+
} else {
|
|
690
|
+
value = values.reduce((a, b) => a + b, 0) / values.length;
|
|
691
|
+
}
|
|
692
|
+
break;
|
|
693
|
+
}
|
|
694
|
+
case "min": {
|
|
695
|
+
value = values.reduce((a, b) => (a < b ? a : b));
|
|
696
|
+
break;
|
|
697
|
+
}
|
|
698
|
+
case "max": {
|
|
699
|
+
value = values.reduce((a, b) => (a > b ? a : b));
|
|
700
|
+
break;
|
|
701
|
+
}
|
|
702
|
+
case "count": {
|
|
703
|
+
value = values.length;
|
|
704
|
+
break;
|
|
705
|
+
}
|
|
706
|
+
case "countDistinct": {
|
|
707
|
+
const unique = new Set(values);
|
|
708
|
+
value = unique.size;
|
|
709
|
+
break;
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
return {
|
|
713
|
+
type,
|
|
714
|
+
field: columnName,
|
|
715
|
+
value,
|
|
716
|
+
recordCount: values.length,
|
|
717
|
+
};
|
|
718
|
+
}
|
|
719
|
+
/**
|
|
720
|
+
* 范围扫描
|
|
721
|
+
* @param columnName 列名称
|
|
722
|
+
* @param condition 范围条件
|
|
723
|
+
*/
|
|
724
|
+
rangeScan(columnName, condition) {
|
|
725
|
+
const column = this.columns.get(columnName);
|
|
726
|
+
if (!column) {
|
|
727
|
+
return [];
|
|
728
|
+
}
|
|
729
|
+
const result = [];
|
|
730
|
+
for (let i = 0; i < column.length; i++) {
|
|
731
|
+
const value = column.get(i);
|
|
732
|
+
if (value === null || value === undefined) {
|
|
733
|
+
continue;
|
|
734
|
+
}
|
|
735
|
+
if (this.matchRange(value, condition)) {
|
|
736
|
+
result.push(i);
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
return result;
|
|
740
|
+
}
|
|
741
|
+
/**
|
|
742
|
+
* 匹配范围条件
|
|
743
|
+
*/
|
|
744
|
+
matchRange(value, condition) {
|
|
745
|
+
if (typeof value !== "number" && typeof value !== "bigint" && typeof value !== "string") {
|
|
746
|
+
return false;
|
|
747
|
+
}
|
|
748
|
+
const numValue = value;
|
|
749
|
+
if (condition.gt !== undefined && condition.gt !== null) {
|
|
750
|
+
if (!(numValue > condition.gt)) {
|
|
751
|
+
return false;
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
if (condition.gte !== undefined && condition.gte !== null) {
|
|
755
|
+
if (!(numValue >= condition.gte)) {
|
|
756
|
+
return false;
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
if (condition.lt !== undefined && condition.lt !== null) {
|
|
760
|
+
if (!(numValue < condition.lt)) {
|
|
761
|
+
return false;
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
if (condition.lte !== undefined && condition.lte !== null) {
|
|
765
|
+
if (!(numValue <= condition.lte)) {
|
|
766
|
+
return false;
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
return true;
|
|
770
|
+
}
|
|
771
|
+
/**
|
|
772
|
+
* 创建行迭代器
|
|
773
|
+
* @param start 起始索引
|
|
774
|
+
* @param end 结束索引
|
|
775
|
+
*/
|
|
776
|
+
*iterateRows(start = 0, end) {
|
|
777
|
+
const stop = end ?? this.rowCount;
|
|
778
|
+
for (let i = start; i < stop; i++) {
|
|
779
|
+
yield this.getRow(i);
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
/**
|
|
783
|
+
* 创建过滤迭代器
|
|
784
|
+
* @param predicate 过滤条件函数
|
|
785
|
+
*/
|
|
786
|
+
*filter(predicate) {
|
|
787
|
+
for (let i = 0; i < this.rowCount; i++) {
|
|
788
|
+
const row = this.getRow(i);
|
|
789
|
+
if (predicate(row, i)) {
|
|
790
|
+
yield row;
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
}
|
|
794
|
+
/**
|
|
795
|
+
* 扩容
|
|
796
|
+
* @param newCapacity 新容量
|
|
797
|
+
*/
|
|
798
|
+
grow(newCapacity) {
|
|
799
|
+
if (newCapacity <= this.capacity) {
|
|
800
|
+
return;
|
|
801
|
+
}
|
|
802
|
+
for (const column of this.columns.values()) {
|
|
803
|
+
column.grow(newCapacity);
|
|
804
|
+
}
|
|
805
|
+
this.capacity = newCapacity;
|
|
806
|
+
}
|
|
807
|
+
/**
|
|
808
|
+
* 清空数据
|
|
809
|
+
*/
|
|
810
|
+
clear() {
|
|
811
|
+
for (const colName of this.columnOrder) {
|
|
812
|
+
const column = this.columns.get(colName);
|
|
813
|
+
column.fill(null, 0, column.length);
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
/**
|
|
817
|
+
* 获取统计信息
|
|
818
|
+
*/
|
|
819
|
+
getStats() {
|
|
820
|
+
const columnStats = [];
|
|
821
|
+
for (const colName of this.columnOrder) {
|
|
822
|
+
const column = this.columns.get(colName);
|
|
823
|
+
columnStats.push({
|
|
824
|
+
name: colName,
|
|
825
|
+
type: column.type,
|
|
826
|
+
nonNullCount: column.getNonNullCount(),
|
|
827
|
+
memoryUsage: column.getMemoryUsage(),
|
|
828
|
+
});
|
|
829
|
+
}
|
|
830
|
+
const totalMemory = columnStats.reduce((sum, stat) => sum + stat.memoryUsage, 0);
|
|
831
|
+
return {
|
|
832
|
+
columnCount: this.columns.size,
|
|
833
|
+
rowCount: this.rowCount,
|
|
834
|
+
memoryUsage: totalMemory,
|
|
835
|
+
columns: columnStats,
|
|
836
|
+
};
|
|
837
|
+
}
|
|
838
|
+
/**
|
|
839
|
+
* 获取容量
|
|
840
|
+
*/
|
|
841
|
+
getCapacity() {
|
|
842
|
+
return this.capacity;
|
|
843
|
+
}
|
|
844
|
+
/**
|
|
845
|
+
* 删除行(标记为 null,不实际删除)
|
|
846
|
+
* @param rowIndex 行索引
|
|
847
|
+
*/
|
|
848
|
+
deleteRow(rowIndex) {
|
|
849
|
+
if (rowIndex < 0 || rowIndex >= this.rowCount) {
|
|
850
|
+
return false;
|
|
851
|
+
}
|
|
852
|
+
for (const column of this.columns.values()) {
|
|
853
|
+
column.set(rowIndex, null);
|
|
854
|
+
}
|
|
855
|
+
return true;
|
|
856
|
+
}
|
|
857
|
+
/**
|
|
858
|
+
* 按条件删除行
|
|
859
|
+
* @param predicate 条件函数
|
|
860
|
+
* @returns 删除的行数
|
|
861
|
+
*/
|
|
862
|
+
deleteWhere(predicate) {
|
|
863
|
+
let count = 0;
|
|
864
|
+
for (let i = 0; i < this.rowCount; i++) {
|
|
865
|
+
const row = this.getRow(i);
|
|
866
|
+
if (predicate(row, i)) {
|
|
867
|
+
this.deleteRow(i);
|
|
868
|
+
count++;
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
return count;
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
exports.ColumnarStorage = ColumnarStorage;
|
|
875
|
+
//# sourceMappingURL=ColumnarStorage.js.map
|