@yydb/light-db 0.0.0 → 0.0.11
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/database.d.ts +48 -0
- package/dist/api/database.d.ts.map +1 -0
- package/dist/api/database.js +120 -0
- package/dist/api/database.js.map +1 -0
- package/dist/api/index.d.ts +7 -22
- package/dist/api/index.d.ts.map +1 -1
- package/dist/api/index.js +5 -52
- package/dist/api/index.js.map +1 -1
- package/dist/api/schema.d.ts +33 -0
- package/dist/api/schema.d.ts.map +1 -0
- package/dist/api/schema.js +80 -0
- package/dist/api/schema.js.map +1 -0
- package/dist/api/transaction.d.ts +26 -0
- package/dist/api/transaction.d.ts.map +1 -0
- package/dist/api/transaction.js +52 -0
- package/dist/api/transaction.js.map +1 -0
- package/dist/api/types.d.ts +55 -148
- package/dist/api/types.d.ts.map +1 -1
- package/dist/api/types.js +6 -5
- package/dist/api/types.js.map +1 -1
- package/dist/codec/binary.d.ts +196 -0
- package/dist/codec/binary.d.ts.map +1 -0
- package/dist/codec/binary.js +342 -0
- package/dist/codec/binary.js.map +1 -0
- package/dist/codec/checksum.d.ts +21 -0
- package/dist/codec/checksum.d.ts.map +1 -0
- package/dist/codec/checksum.js +46 -0
- package/dist/codec/checksum.js.map +1 -0
- package/dist/codec/index.d.ts +12 -0
- package/dist/codec/index.d.ts.map +1 -0
- package/dist/codec/index.js +10 -0
- package/dist/codec/index.js.map +1 -0
- package/dist/codec/page.d.ts +114 -0
- package/dist/codec/page.d.ts.map +1 -0
- package/dist/codec/page.js +225 -0
- package/dist/codec/page.js.map +1 -0
- package/dist/codec/record.d.ts +62 -0
- package/dist/codec/record.d.ts.map +1 -0
- package/dist/codec/record.js +82 -0
- package/dist/codec/record.js.map +1 -0
- package/dist/core/broadcast.d.ts +39 -0
- package/dist/core/broadcast.d.ts.map +1 -0
- package/dist/core/broadcast.js +54 -0
- package/dist/core/broadcast.js.map +1 -0
- package/dist/core/checkpoint.d.ts +23 -0
- package/dist/core/checkpoint.d.ts.map +1 -0
- package/dist/core/checkpoint.js +49 -0
- package/dist/core/checkpoint.js.map +1 -0
- package/dist/core/engine.d.ts +142 -0
- package/dist/core/engine.d.ts.map +1 -0
- package/dist/core/engine.js +304 -0
- package/dist/core/engine.js.map +1 -0
- package/dist/core/index.d.ts +17 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +13 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/lease.d.ts +32 -0
- package/dist/core/lease.d.ts.map +1 -0
- package/dist/core/lease.js +81 -0
- package/dist/core/lease.js.map +1 -0
- package/dist/core/records.d.ts +49 -0
- package/dist/core/records.d.ts.map +1 -0
- package/dist/core/records.js +70 -0
- package/dist/core/records.js.map +1 -0
- package/dist/core/recovery.d.ts +43 -0
- package/dist/core/recovery.d.ts.map +1 -0
- package/dist/core/recovery.js +99 -0
- package/dist/core/recovery.js.map +1 -0
- package/dist/core/wal.d.ts +50 -0
- package/dist/core/wal.d.ts.map +1 -0
- package/dist/core/wal.js +114 -0
- package/dist/core/wal.js.map +1 -0
- package/dist/errors/index.d.ts +44 -66
- package/dist/errors/index.d.ts.map +1 -1
- package/dist/errors/index.js +43 -128
- package/dist/errors/index.js.map +1 -1
- package/dist/index.d.ts +14 -215
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +14 -724
- package/dist/index.js.map +1 -1
- package/dist/storage/StorageAdapter.d.ts +97 -0
- package/dist/storage/StorageAdapter.d.ts.map +1 -0
- package/dist/storage/StorageAdapter.js +9 -0
- package/dist/storage/StorageAdapter.js.map +1 -0
- package/dist/storage/index.d.ts +9 -8
- package/dist/storage/index.d.ts.map +1 -1
- package/dist/storage/index.js +8 -151
- package/dist/storage/index.js.map +1 -1
- package/dist/storage/indexeddb/IndexedDbStorageAdapter.d.ts +140 -0
- package/dist/storage/indexeddb/IndexedDbStorageAdapter.d.ts.map +1 -0
- package/dist/storage/indexeddb/IndexedDbStorageAdapter.js +403 -0
- package/dist/storage/indexeddb/IndexedDbStorageAdapter.js.map +1 -0
- package/dist/storage/memory/MemoryStorageAdapter.d.ts +76 -0
- package/dist/storage/memory/MemoryStorageAdapter.d.ts.map +1 -0
- package/dist/storage/memory/MemoryStorageAdapter.js +212 -0
- package/dist/storage/memory/MemoryStorageAdapter.js.map +1 -0
- package/dist/storage/opfs/OpfsStorageAdapter.d.ts +141 -0
- package/dist/storage/opfs/OpfsStorageAdapter.d.ts.map +1 -0
- package/dist/storage/opfs/OpfsStorageAdapter.js +400 -0
- package/dist/storage/opfs/OpfsStorageAdapter.js.map +1 -0
- package/package.json +48 -36
- package/readme.md +80 -94
- package/dist/api/LightDB.d.ts +0 -194
- package/dist/api/LightDB.d.ts.map +0 -1
- package/dist/api/LightDB.js +0 -299
- package/dist/api/LightDB.js.map +0 -1
- package/dist/api/Transaction.d.ts +0 -100
- package/dist/api/Transaction.d.ts.map +0 -1
- package/dist/api/Transaction.js +0 -263
- package/dist/api/Transaction.js.map +0 -1
- package/dist/collection/Collection.d.ts +0 -235
- package/dist/collection/Collection.d.ts.map +0 -1
- package/dist/collection/Collection.js +0 -671
- package/dist/collection/Collection.js.map +0 -1
- package/dist/collection/QueryBuilder.d.ts +0 -225
- package/dist/collection/QueryBuilder.d.ts.map +0 -1
- package/dist/collection/QueryBuilder.js +0 -475
- package/dist/collection/QueryBuilder.js.map +0 -1
- package/dist/collection/QueryParser.d.ts +0 -117
- package/dist/collection/QueryParser.d.ts.map +0 -1
- package/dist/collection/QueryParser.js +0 -438
- package/dist/collection/QueryParser.js.map +0 -1
- package/dist/collection/index.d.ts +0 -42
- package/dist/collection/index.d.ts.map +0 -1
- package/dist/collection/index.js +0 -41
- package/dist/collection/index.js.map +0 -1
- package/dist/collection/types.d.ts +0 -365
- package/dist/collection/types.d.ts.map +0 -1
- package/dist/collection/types.js +0 -7
- package/dist/collection/types.js.map +0 -1
- package/dist/constants/index.d.ts +0 -51
- package/dist/constants/index.d.ts.map +0 -1
- package/dist/constants/index.js +0 -68
- package/dist/constants/index.js.map +0 -1
- package/dist/indexes/BPlusTree.d.ts +0 -181
- package/dist/indexes/BPlusTree.d.ts.map +0 -1
- package/dist/indexes/BPlusTree.js +0 -528
- package/dist/indexes/BPlusTree.js.map +0 -1
- package/dist/indexes/IndexManager.d.ts +0 -236
- package/dist/indexes/IndexManager.d.ts.map +0 -1
- package/dist/indexes/IndexManager.js +0 -502
- package/dist/indexes/IndexManager.js.map +0 -1
- package/dist/indexes/PrimaryIndex.d.ts +0 -240
- package/dist/indexes/PrimaryIndex.d.ts.map +0 -1
- package/dist/indexes/PrimaryIndex.js +0 -354
- package/dist/indexes/PrimaryIndex.js.map +0 -1
- package/dist/indexes/SecondaryIndex.d.ts +0 -204
- package/dist/indexes/SecondaryIndex.d.ts.map +0 -1
- package/dist/indexes/SecondaryIndex.js +0 -480
- package/dist/indexes/SecondaryIndex.js.map +0 -1
- package/dist/indexes/errors.d.ts +0 -66
- package/dist/indexes/errors.d.ts.map +0 -1
- package/dist/indexes/errors.js +0 -117
- package/dist/indexes/errors.js.map +0 -1
- package/dist/indexes/index.d.ts +0 -52
- package/dist/indexes/index.d.ts.map +0 -1
- package/dist/indexes/index.js +0 -131
- package/dist/indexes/index.js.map +0 -1
- package/dist/indexes/types.d.ts +0 -246
- package/dist/indexes/types.d.ts.map +0 -1
- package/dist/indexes/types.js +0 -30
- package/dist/indexes/types.js.map +0 -1
- package/dist/performance/BatchWALWriter.d.ts +0 -185
- package/dist/performance/BatchWALWriter.d.ts.map +0 -1
- package/dist/performance/BatchWALWriter.js +0 -490
- package/dist/performance/BatchWALWriter.js.map +0 -1
- package/dist/performance/ColumnarStorage.d.ts +0 -138
- package/dist/performance/ColumnarStorage.d.ts.map +0 -1
- package/dist/performance/ColumnarStorage.js +0 -875
- package/dist/performance/ColumnarStorage.js.map +0 -1
- package/dist/performance/LazyQuery.d.ts +0 -307
- package/dist/performance/LazyQuery.d.ts.map +0 -1
- package/dist/performance/LazyQuery.js +0 -588
- package/dist/performance/LazyQuery.js.map +0 -1
- package/dist/performance/OptimizedBuffer.d.ts +0 -375
- package/dist/performance/OptimizedBuffer.d.ts.map +0 -1
- package/dist/performance/OptimizedBuffer.js +0 -730
- package/dist/performance/OptimizedBuffer.js.map +0 -1
- package/dist/performance/RWLock.d.ts +0 -260
- package/dist/performance/RWLock.d.ts.map +0 -1
- package/dist/performance/RWLock.js +0 -570
- package/dist/performance/RWLock.js.map +0 -1
- package/dist/performance/index.d.ts +0 -41
- package/dist/performance/index.d.ts.map +0 -1
- package/dist/performance/index.js +0 -162
- package/dist/performance/index.js.map +0 -1
- package/dist/performance/types.d.ts +0 -247
- package/dist/performance/types.d.ts.map +0 -1
- package/dist/performance/types.js +0 -26
- package/dist/performance/types.js.map +0 -1
- package/dist/storage/Checkpoint.d.ts +0 -128
- package/dist/storage/Checkpoint.d.ts.map +0 -1
- package/dist/storage/Checkpoint.js +0 -251
- package/dist/storage/Checkpoint.js.map +0 -1
- package/dist/storage/LightFile.d.ts +0 -227
- package/dist/storage/LightFile.d.ts.map +0 -1
- package/dist/storage/LightFile.js +0 -526
- package/dist/storage/LightFile.js.map +0 -1
- package/dist/storage/Recovery.d.ts +0 -172
- package/dist/storage/Recovery.d.ts.map +0 -1
- package/dist/storage/Recovery.js +0 -399
- package/dist/storage/Recovery.js.map +0 -1
- package/dist/storage/SHMFile.d.ts +0 -243
- package/dist/storage/SHMFile.d.ts.map +0 -1
- package/dist/storage/SHMFile.js +0 -436
- package/dist/storage/SHMFile.js.map +0 -1
- package/dist/storage/StorageEngine.d.ts +0 -146
- package/dist/storage/StorageEngine.d.ts.map +0 -1
- package/dist/storage/StorageEngine.js +0 -353
- package/dist/storage/StorageEngine.js.map +0 -1
- package/dist/storage/WALFile.d.ts +0 -248
- package/dist/storage/WALFile.d.ts.map +0 -1
- package/dist/storage/WALFile.js +0 -597
- package/dist/storage/WALFile.js.map +0 -1
- package/dist/types/index.d.ts +0 -220
- package/dist/types/index.d.ts.map +0 -1
- package/dist/types/index.js +0 -7
- package/dist/types/index.js.map +0 -1
- package/dist/utils/binary.d.ts +0 -271
- package/dist/utils/binary.d.ts.map +0 -1
- package/dist/utils/binary.js +0 -454
- package/dist/utils/binary.js.map +0 -1
- package/dist/utils/file.d.ts +0 -166
- package/dist/utils/file.d.ts.map +0 -1
- package/dist/utils/file.js +0 -346
- package/dist/utils/file.js.map +0 -1
- package/dist/utils/index.d.ts +0 -6
- package/dist/utils/index.d.ts.map +0 -1
- package/dist/utils/index.js +0 -39
- package/dist/utils/index.js.map +0 -1
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 页与快照编解码
|
|
3
|
+
*
|
|
4
|
+
* 快照由一个固定长度头部和若干固定长度页组成,全部基于 `Uint8Array`。
|
|
5
|
+
*/
|
|
6
|
+
import { ByteReader, ByteWriter, BinaryUtils, ChecksumMismatchError } from './binary';
|
|
7
|
+
import { crc32 } from './checksum';
|
|
8
|
+
/** 快照魔数:`LIGH` */
|
|
9
|
+
export const SNAPSHOT_MAGIC = 0x4c494748;
|
|
10
|
+
/** 快照格式版本 */
|
|
11
|
+
export const SNAPSHOT_VERSION = 1;
|
|
12
|
+
/** 默认页大小:4KB */
|
|
13
|
+
export const DEFAULT_PAGE_SIZE = 4096;
|
|
14
|
+
/** 快照头部长度:魔数(4) + 版本(4) + 页大小(4) + 最近快照 LSN(8) + 保留(16) */
|
|
15
|
+
export const SNAPSHOT_HEADER_SIZE = 36;
|
|
16
|
+
/** 页头部长度:页号(4) + 记录数(2) + 空闲空间(2) */
|
|
17
|
+
export const PAGE_HEADER_SIZE = 8;
|
|
18
|
+
/** 页尾校验和长度 */
|
|
19
|
+
export const PAGE_CHECKSUM_SIZE = 4;
|
|
20
|
+
/** 记录尾校验和长度 */
|
|
21
|
+
export const RECORD_CHECKSUM_SIZE = 4;
|
|
22
|
+
/** 单条记录超出页容量 */
|
|
23
|
+
export class RecordTooLargeError extends Error {
|
|
24
|
+
/** 记录所需字节数 */
|
|
25
|
+
size;
|
|
26
|
+
/** 页可用字节数 */
|
|
27
|
+
capacity;
|
|
28
|
+
constructor(size, capacity) {
|
|
29
|
+
super(`Record needs ${size} bytes but a page only has ${capacity}`);
|
|
30
|
+
this.name = 'RecordTooLargeError';
|
|
31
|
+
this.size = size;
|
|
32
|
+
this.capacity = capacity;
|
|
33
|
+
Object.setPrototypeOf(this, RecordTooLargeError.prototype);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
/** 快照格式错误 */
|
|
37
|
+
export class SnapshotFormatError extends Error {
|
|
38
|
+
/** 失败原因 */
|
|
39
|
+
reason;
|
|
40
|
+
constructor(reason) {
|
|
41
|
+
super(`Snapshot format error: ${reason}`);
|
|
42
|
+
this.name = 'SnapshotFormatError';
|
|
43
|
+
this.reason = reason;
|
|
44
|
+
Object.setPrototypeOf(this, SnapshotFormatError.prototype);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* 计算记录编码后的字节数
|
|
49
|
+
* @param key 键
|
|
50
|
+
* @param value 值
|
|
51
|
+
*/
|
|
52
|
+
export function recordSize(key, value) {
|
|
53
|
+
return 4 + BinaryUtils.byteLength(key) + 4 + value.length + RECORD_CHECKSUM_SIZE;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* 序列化快照头部
|
|
57
|
+
* @param header 头部
|
|
58
|
+
*/
|
|
59
|
+
export function encodeHeader(header) {
|
|
60
|
+
const writer = new ByteWriter(SNAPSHOT_HEADER_SIZE);
|
|
61
|
+
writer.writeUInt32LE(header.magic);
|
|
62
|
+
writer.writeUInt32LE(header.version);
|
|
63
|
+
writer.writeUInt32LE(header.pageSize);
|
|
64
|
+
writer.writeBigUInt64LE(header.lastSnapshotLsn);
|
|
65
|
+
writer.writeBytes(BinaryUtils.alloc(16));
|
|
66
|
+
return writer.data;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* 反序列化快照头部
|
|
70
|
+
* @param data 数据
|
|
71
|
+
*/
|
|
72
|
+
export function decodeHeader(data) {
|
|
73
|
+
if (data.length < SNAPSHOT_HEADER_SIZE) {
|
|
74
|
+
throw new SnapshotFormatError(`header needs ${SNAPSHOT_HEADER_SIZE} bytes, got ${data.length}`);
|
|
75
|
+
}
|
|
76
|
+
const reader = new ByteReader(data);
|
|
77
|
+
const magic = reader.readUInt32LE();
|
|
78
|
+
const version = reader.readUInt32LE();
|
|
79
|
+
const pageSize = reader.readUInt32LE();
|
|
80
|
+
const lastSnapshotLsn = reader.readBigUInt64LE();
|
|
81
|
+
if (magic !== SNAPSHOT_MAGIC) {
|
|
82
|
+
throw new SnapshotFormatError(`unexpected magic ${magic}`);
|
|
83
|
+
}
|
|
84
|
+
if (pageSize <= 0) {
|
|
85
|
+
throw new SnapshotFormatError(`invalid page size ${pageSize}`);
|
|
86
|
+
}
|
|
87
|
+
return { magic, version, pageSize, lastSnapshotLsn };
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* 序列化单条记录
|
|
91
|
+
* @param record 记录
|
|
92
|
+
*/
|
|
93
|
+
export function encodeRecord(record) {
|
|
94
|
+
const writer = new ByteWriter(recordSize(record.key, record.value));
|
|
95
|
+
writer.writeString(record.key);
|
|
96
|
+
writer.writeBytesWithLength(record.value);
|
|
97
|
+
writer.writeChecksum(0);
|
|
98
|
+
return writer.data;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* 序列化页
|
|
102
|
+
* @param page 页
|
|
103
|
+
* @param pageSize 页大小
|
|
104
|
+
*/
|
|
105
|
+
export function encodePage(page, pageSize = DEFAULT_PAGE_SIZE) {
|
|
106
|
+
const capacity = pageSize - PAGE_HEADER_SIZE - PAGE_CHECKSUM_SIZE;
|
|
107
|
+
const payload = [];
|
|
108
|
+
let payloadLength = 0;
|
|
109
|
+
for (const record of page.records) {
|
|
110
|
+
const encoded = encodeRecord(record);
|
|
111
|
+
payload.push(encoded);
|
|
112
|
+
payloadLength += encoded.length;
|
|
113
|
+
}
|
|
114
|
+
if (payloadLength > capacity) {
|
|
115
|
+
throw new RecordTooLargeError(payloadLength, capacity);
|
|
116
|
+
}
|
|
117
|
+
const writer = new ByteWriter(pageSize);
|
|
118
|
+
writer.writeUInt32LE(page.pageId);
|
|
119
|
+
writer.writeUInt16LE(page.records.length);
|
|
120
|
+
writer.writeUInt16LE(capacity - payloadLength);
|
|
121
|
+
for (const part of payload) {
|
|
122
|
+
writer.writeBytes(part);
|
|
123
|
+
}
|
|
124
|
+
writer.writeBytes(BinaryUtils.alloc(pageSize - PAGE_CHECKSUM_SIZE - writer.position));
|
|
125
|
+
writer.writeChecksum(0);
|
|
126
|
+
return writer.data;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* 反序列化页
|
|
130
|
+
* @param data 页数据
|
|
131
|
+
* @param pageId 期望页号
|
|
132
|
+
*/
|
|
133
|
+
export function decodePage(data, pageId) {
|
|
134
|
+
if (data.length < PAGE_HEADER_SIZE + PAGE_CHECKSUM_SIZE) {
|
|
135
|
+
throw new SnapshotFormatError(`page ${pageId} is shorter than its header`);
|
|
136
|
+
}
|
|
137
|
+
const checksumView = new DataView(data.buffer, data.byteOffset + data.length - PAGE_CHECKSUM_SIZE, PAGE_CHECKSUM_SIZE);
|
|
138
|
+
const expectedChecksum = checksumView.getUint32(0, true);
|
|
139
|
+
const actualChecksum = crc32(data, 0, data.length - PAGE_CHECKSUM_SIZE);
|
|
140
|
+
if (actualChecksum !== expectedChecksum) {
|
|
141
|
+
throw new ChecksumMismatchError(expectedChecksum, actualChecksum, 0);
|
|
142
|
+
}
|
|
143
|
+
const reader = new ByteReader(data);
|
|
144
|
+
const readPageId = reader.readUInt32LE();
|
|
145
|
+
const recordCount = reader.readUInt16LE();
|
|
146
|
+
reader.readUInt16LE();
|
|
147
|
+
if (readPageId !== pageId) {
|
|
148
|
+
throw new SnapshotFormatError(`expected page ${pageId}, got ${readPageId}`);
|
|
149
|
+
}
|
|
150
|
+
const records = [];
|
|
151
|
+
for (let i = 0; i < recordCount; i++) {
|
|
152
|
+
const start = reader.position;
|
|
153
|
+
const key = reader.readString();
|
|
154
|
+
const value = BinaryUtils.copy(reader.readBytesWithLength());
|
|
155
|
+
reader.readAndVerifyChecksum(start);
|
|
156
|
+
records.push({ key, value });
|
|
157
|
+
}
|
|
158
|
+
return { pageId, records };
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* 将记录打包成页
|
|
162
|
+
* @param records 记录映射
|
|
163
|
+
* @param pageSize 页大小
|
|
164
|
+
*/
|
|
165
|
+
export function packRecords(records, pageSize = DEFAULT_PAGE_SIZE) {
|
|
166
|
+
const capacity = pageSize - PAGE_HEADER_SIZE - PAGE_CHECKSUM_SIZE;
|
|
167
|
+
const pages = [];
|
|
168
|
+
let current = { pageId: 0, records: [] };
|
|
169
|
+
let used = 0;
|
|
170
|
+
for (const [key, value] of records) {
|
|
171
|
+
const size = recordSize(key, value);
|
|
172
|
+
if (size > capacity) {
|
|
173
|
+
throw new RecordTooLargeError(size, capacity);
|
|
174
|
+
}
|
|
175
|
+
if (current.records.length > 0 && used + size > capacity) {
|
|
176
|
+
pages.push(current);
|
|
177
|
+
current = { pageId: pages.length, records: [] };
|
|
178
|
+
used = 0;
|
|
179
|
+
}
|
|
180
|
+
current.records.push({ key, value });
|
|
181
|
+
used += size;
|
|
182
|
+
}
|
|
183
|
+
if (current.records.length > 0) {
|
|
184
|
+
pages.push(current);
|
|
185
|
+
}
|
|
186
|
+
return pages;
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* 序列化完整快照
|
|
190
|
+
* @param records 记录映射
|
|
191
|
+
* @param lastSnapshotLsn 最近快照 LSN
|
|
192
|
+
* @param pageSize 页大小
|
|
193
|
+
*/
|
|
194
|
+
export function encodeSnapshot(records, lastSnapshotLsn, pageSize = DEFAULT_PAGE_SIZE) {
|
|
195
|
+
const header = encodeHeader({
|
|
196
|
+
magic: SNAPSHOT_MAGIC,
|
|
197
|
+
version: SNAPSHOT_VERSION,
|
|
198
|
+
pageSize,
|
|
199
|
+
lastSnapshotLsn,
|
|
200
|
+
});
|
|
201
|
+
const pages = packRecords(records, pageSize);
|
|
202
|
+
const parts = [header];
|
|
203
|
+
for (const page of pages) {
|
|
204
|
+
parts.push(encodePage(page, pageSize));
|
|
205
|
+
}
|
|
206
|
+
return BinaryUtils.concat(parts);
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* 反序列化完整快照
|
|
210
|
+
* @param data 数据
|
|
211
|
+
*/
|
|
212
|
+
export function decodeSnapshot(data) {
|
|
213
|
+
const header = decodeHeader(data);
|
|
214
|
+
const pageCount = Math.floor((data.length - SNAPSHOT_HEADER_SIZE) / header.pageSize);
|
|
215
|
+
const records = new Map();
|
|
216
|
+
for (let pageId = 0; pageId < pageCount; pageId++) {
|
|
217
|
+
const start = SNAPSHOT_HEADER_SIZE + pageId * header.pageSize;
|
|
218
|
+
const page = decodePage(data.subarray(start, start + header.pageSize), pageId);
|
|
219
|
+
for (const record of page.records) {
|
|
220
|
+
records.set(record.key, record.value);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
return { header, records, pageCount };
|
|
224
|
+
}
|
|
225
|
+
//# sourceMappingURL=page.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"page.js","sourceRoot":"","sources":["../../src/codec/page.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,WAAW,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAC;AACtF,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAEnC,kBAAkB;AAClB,MAAM,CAAC,MAAM,cAAc,GAAG,UAAU,CAAC;AAEzC,aAAa;AACb,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,CAAC;AAElC,gBAAgB;AAChB,MAAM,CAAC,MAAM,iBAAiB,GAAG,IAAI,CAAC;AAEtC,2DAA2D;AAC3D,MAAM,CAAC,MAAM,oBAAoB,GAAG,EAAE,CAAC;AAEvC,qCAAqC;AACrC,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,CAAC;AAElC,cAAc;AACd,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,CAAC;AAEpC,eAAe;AACf,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,CAAC;AA8BtC,gBAAgB;AAChB,MAAM,OAAO,mBAAoB,SAAQ,KAAK;IAC1C,cAAc;IACE,IAAI,CAAS;IAE7B,aAAa;IACG,QAAQ,CAAS;IAEjC,YAAY,IAAY,EAAE,QAAgB;QACtC,KAAK,CAAC,gBAAgB,IAAI,8BAA8B,QAAQ,EAAE,CAAC,CAAC;QACpE,IAAI,CAAC,IAAI,GAAG,qBAAqB,CAAC;QAClC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,mBAAmB,CAAC,SAAS,CAAC,CAAC;IAC/D,CAAC;CACJ;AAED,aAAa;AACb,MAAM,OAAO,mBAAoB,SAAQ,KAAK;IAC1C,WAAW;IACK,MAAM,CAAS;IAE/B,YAAY,MAAc;QACtB,KAAK,CAAC,0BAA0B,MAAM,EAAE,CAAC,CAAC;QAC1C,IAAI,CAAC,IAAI,GAAG,qBAAqB,CAAC;QAClC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,mBAAmB,CAAC,SAAS,CAAC,CAAC;IAC/D,CAAC;CACJ;AAED;;;;GAIG;AACH,MAAM,UAAU,UAAU,CAAC,GAAW,EAAE,KAAiB;IACrD,OAAO,CAAC,GAAG,WAAW,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,MAAM,GAAG,oBAAoB,CAAC;AACrF,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,MAAsB;IAC/C,MAAM,MAAM,GAAG,IAAI,UAAU,CAAC,oBAAoB,CAAC,CAAC;IACpD,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACnC,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IACrC,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IACtC,MAAM,CAAC,gBAAgB,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC;IAChD,MAAM,CAAC,UAAU,CAAC,WAAW,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC;IACzC,OAAO,MAAM,CAAC,IAAI,CAAC;AACvB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,IAAgB;IACzC,IAAI,IAAI,CAAC,MAAM,GAAG,oBAAoB,EAAE,CAAC;QACrC,MAAM,IAAI,mBAAmB,CAAC,gBAAgB,oBAAoB,eAAe,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;IACpG,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,UAAU,CAAC,IAAI,CAAC,CAAC;IACpC,MAAM,KAAK,GAAG,MAAM,CAAC,YAAY,EAAE,CAAC;IACpC,MAAM,OAAO,GAAG,MAAM,CAAC,YAAY,EAAE,CAAC;IACtC,MAAM,QAAQ,GAAG,MAAM,CAAC,YAAY,EAAE,CAAC;IACvC,MAAM,eAAe,GAAG,MAAM,CAAC,eAAe,EAAE,CAAC;IAEjD,IAAI,KAAK,KAAK,cAAc,EAAE,CAAC;QAC3B,MAAM,IAAI,mBAAmB,CAAC,oBAAoB,KAAK,EAAE,CAAC,CAAC;IAC/D,CAAC;IAED,IAAI,QAAQ,IAAI,CAAC,EAAE,CAAC;QAChB,MAAM,IAAI,mBAAmB,CAAC,qBAAqB,QAAQ,EAAE,CAAC,CAAC;IACnE,CAAC;IAED,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAE,CAAC;AACzD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,MAAoB;IAC7C,MAAM,MAAM,GAAG,IAAI,UAAU,CAAC,UAAU,CAAC,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;IACpE,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IAC/B,MAAM,CAAC,oBAAoB,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAC1C,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;IACxB,OAAO,MAAM,CAAC,IAAI,CAAC;AACvB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,UAAU,CAAC,IAAU,EAAE,WAAmB,iBAAiB;IACvE,MAAM,QAAQ,GAAG,QAAQ,GAAG,gBAAgB,GAAG,kBAAkB,CAAC;IAClE,MAAM,OAAO,GAAiB,EAAE,CAAC;IACjC,IAAI,aAAa,GAAG,CAAC,CAAC;IAEtB,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;QAChC,MAAM,OAAO,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;QACrC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACtB,aAAa,IAAI,OAAO,CAAC,MAAM,CAAC;IACpC,CAAC;IAED,IAAI,aAAa,GAAG,QAAQ,EAAE,CAAC;QAC3B,MAAM,IAAI,mBAAmB,CAAC,aAAa,EAAE,QAAQ,CAAC,CAAC;IAC3D,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,UAAU,CAAC,QAAQ,CAAC,CAAC;IACxC,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAClC,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IAC1C,MAAM,CAAC,aAAa,CAAC,QAAQ,GAAG,aAAa,CAAC,CAAC;IAC/C,KAAK,MAAM,IAAI,IAAI,OAAO,EAAE,CAAC;QACzB,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;IAC5B,CAAC;IACD,MAAM,CAAC,UAAU,CAAC,WAAW,CAAC,KAAK,CAAC,QAAQ,GAAG,kBAAkB,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC;IACtF,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;IACxB,OAAO,MAAM,CAAC,IAAI,CAAC;AACvB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,UAAU,CAAC,IAAgB,EAAE,MAAc;IACvD,IAAI,IAAI,CAAC,MAAM,GAAG,gBAAgB,GAAG,kBAAkB,EAAE,CAAC;QACtD,MAAM,IAAI,mBAAmB,CAAC,QAAQ,MAAM,6BAA6B,CAAC,CAAC;IAC/E,CAAC;IAED,MAAM,YAAY,GAAG,IAAI,QAAQ,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,MAAM,GAAG,kBAAkB,EAAE,kBAAkB,CAAC,CAAC;IACvH,MAAM,gBAAgB,GAAG,YAAY,CAAC,SAAS,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;IACzD,MAAM,cAAc,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,EAAE,IAAI,CAAC,MAAM,GAAG,kBAAkB,CAAC,CAAC;IACxE,IAAI,cAAc,KAAK,gBAAgB,EAAE,CAAC;QACtC,MAAM,IAAI,qBAAqB,CAAC,gBAAgB,EAAE,cAAc,EAAE,CAAC,CAAC,CAAC;IACzE,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,UAAU,CAAC,IAAI,CAAC,CAAC;IACpC,MAAM,UAAU,GAAG,MAAM,CAAC,YAAY,EAAE,CAAC;IACzC,MAAM,WAAW,GAAG,MAAM,CAAC,YAAY,EAAE,CAAC;IAC1C,MAAM,CAAC,YAAY,EAAE,CAAC;IAEtB,IAAI,UAAU,KAAK,MAAM,EAAE,CAAC;QACxB,MAAM,IAAI,mBAAmB,CAAC,iBAAiB,MAAM,SAAS,UAAU,EAAE,CAAC,CAAC;IAChF,CAAC;IAED,MAAM,OAAO,GAAmB,EAAE,CAAC;IACnC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,WAAW,EAAE,CAAC,EAAE,EAAE,CAAC;QACnC,MAAM,KAAK,GAAG,MAAM,CAAC,QAAQ,CAAC;QAC9B,MAAM,GAAG,GAAG,MAAM,CAAC,UAAU,EAAE,CAAC;QAChC,MAAM,KAAK,GAAG,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,mBAAmB,EAAE,CAAC,CAAC;QAC7D,MAAM,CAAC,qBAAqB,CAAC,KAAK,CAAC,CAAC;QACpC,OAAO,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC,CAAC;IACjC,CAAC;IAED,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC;AAC/B,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,WAAW,CAAC,OAAwC,EAAE,WAAmB,iBAAiB;IACtG,MAAM,QAAQ,GAAG,QAAQ,GAAG,gBAAgB,GAAG,kBAAkB,CAAC;IAClE,MAAM,KAAK,GAAW,EAAE,CAAC;IACzB,IAAI,OAAO,GAAS,EAAE,MAAM,EAAE,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;IAC/C,IAAI,IAAI,GAAG,CAAC,CAAC;IAEb,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,OAAO,EAAE,CAAC;QACjC,MAAM,IAAI,GAAG,UAAU,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QACpC,IAAI,IAAI,GAAG,QAAQ,EAAE,CAAC;YAClB,MAAM,IAAI,mBAAmB,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;QAClD,CAAC;QAED,IAAI,OAAO,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,IAAI,GAAG,IAAI,GAAG,QAAQ,EAAE,CAAC;YACvD,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YACpB,OAAO,GAAG,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;YAChD,IAAI,GAAG,CAAC,CAAC;QACb,CAAC;QAED,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC,CAAC;QACrC,IAAI,IAAI,IAAI,CAAC;IACjB,CAAC;IAED,IAAI,OAAO,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC7B,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACxB,CAAC;IAED,OAAO,KAAK,CAAC;AACjB,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAC1B,OAAwC,EACxC,eAAuB,EACvB,WAAmB,iBAAiB;IAEpC,MAAM,MAAM,GAAG,YAAY,CAAC;QACxB,KAAK,EAAE,cAAc;QACrB,OAAO,EAAE,gBAAgB;QACzB,QAAQ;QACR,eAAe;KAClB,CAAC,CAAC;IAEH,MAAM,KAAK,GAAG,WAAW,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IAC7C,MAAM,KAAK,GAAiB,CAAC,MAAM,CAAC,CAAC;IACrC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACvB,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC;IAC3C,CAAC;IAED,OAAO,WAAW,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AACrC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,IAAgB;IAK3C,MAAM,MAAM,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;IAClC,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,MAAM,GAAG,oBAAoB,CAAC,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC;IACrF,MAAM,OAAO,GAAG,IAAI,GAAG,EAAsB,CAAC;IAE9C,KAAK,IAAI,MAAM,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,EAAE,MAAM,EAAE,EAAE,CAAC;QAChD,MAAM,KAAK,GAAG,oBAAoB,GAAG,MAAM,GAAG,MAAM,CAAC,QAAQ,CAAC;QAC9D,MAAM,IAAI,GAAG,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,KAAK,GAAG,MAAM,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAC;QAC/E,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YAChC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC;QAC1C,CAAC;IACL,CAAC;IAED,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC;AAC1C,CAAC"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WAL 记录编解码
|
|
3
|
+
*
|
|
4
|
+
* 记录布局(小端):
|
|
5
|
+
* LSN(8) + 事务号(8) + 操作(1) + 键长度(4) + 值长度(4) + 键 + 值 + CRC32(4)。
|
|
6
|
+
*/
|
|
7
|
+
/** WAL 记录头部长度(不含尾部校验和) */
|
|
8
|
+
export declare const WAL_RECORD_HEADER_SIZE = 25;
|
|
9
|
+
/** WAL 记录尾部校验和长度 */
|
|
10
|
+
export declare const WAL_RECORD_CHECKSUM_SIZE = 4;
|
|
11
|
+
/** WAL 操作类型 */
|
|
12
|
+
export declare enum WalOperation {
|
|
13
|
+
/** 写入或覆盖键 */
|
|
14
|
+
Put = 1,
|
|
15
|
+
/** 删除键 */
|
|
16
|
+
Delete = 2,
|
|
17
|
+
/** 检查点标记 */
|
|
18
|
+
Checkpoint = 16
|
|
19
|
+
}
|
|
20
|
+
/** WAL 记录 */
|
|
21
|
+
export interface WalRecord {
|
|
22
|
+
/** 日志序列号,单调递增 */
|
|
23
|
+
lsn: bigint;
|
|
24
|
+
/** 事务号,0 表示自动提交 */
|
|
25
|
+
transactionId: bigint;
|
|
26
|
+
/** 操作类型 */
|
|
27
|
+
operation: WalOperation;
|
|
28
|
+
/** 键 */
|
|
29
|
+
key: string;
|
|
30
|
+
/** 值,删除或检查点标记为空 */
|
|
31
|
+
value: Uint8Array | null;
|
|
32
|
+
}
|
|
33
|
+
/** WAL 解码结果 */
|
|
34
|
+
export type WalDecodeResult = {
|
|
35
|
+
status: 'ok';
|
|
36
|
+
record: WalRecord;
|
|
37
|
+
bytesRead: number;
|
|
38
|
+
} | {
|
|
39
|
+
status: 'incomplete';
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* 计算记录编码大小
|
|
43
|
+
* @param key 键
|
|
44
|
+
* @param value 值
|
|
45
|
+
*/
|
|
46
|
+
export declare function walRecordSize(key: string, value: Uint8Array | null): number;
|
|
47
|
+
/**
|
|
48
|
+
* 序列化 WAL 记录
|
|
49
|
+
* @param record 记录
|
|
50
|
+
*/
|
|
51
|
+
export declare function encodeWalRecord(record: WalRecord): Uint8Array;
|
|
52
|
+
/**
|
|
53
|
+
* 反序列化 WAL 记录
|
|
54
|
+
*
|
|
55
|
+
* 尾部不完整(进程在写入中途退出)返回 `incomplete`,由恢复流程丢弃该尾部。
|
|
56
|
+
* 校验和不匹配属于真实损坏,会抛出 `ChecksumMismatchError`。
|
|
57
|
+
*
|
|
58
|
+
* @param data 数据
|
|
59
|
+
* @param offset 起始偏移量
|
|
60
|
+
*/
|
|
61
|
+
export declare function decodeWalRecord(data: Uint8Array, offset?: number): WalDecodeResult;
|
|
62
|
+
//# sourceMappingURL=record.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"record.d.ts","sourceRoot":"","sources":["../../src/codec/record.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,0BAA0B;AAC1B,eAAO,MAAM,sBAAsB,KAAK,CAAC;AAEzC,oBAAoB;AACpB,eAAO,MAAM,wBAAwB,IAAI,CAAC;AAE1C,eAAe;AACf,oBAAY,YAAY;IACpB,aAAa;IACb,GAAG,IAAO;IACV,UAAU;IACV,MAAM,IAAO;IACb,YAAY;IACZ,UAAU,KAAO;CACpB;AAED,aAAa;AACb,MAAM,WAAW,SAAS;IACtB,iBAAiB;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,mBAAmB;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW;IACX,SAAS,EAAE,YAAY,CAAC;IACxB,QAAQ;IACR,GAAG,EAAE,MAAM,CAAC;IACZ,mBAAmB;IACnB,KAAK,EAAE,UAAU,GAAG,IAAI,CAAC;CAC5B;AAED,eAAe;AACf,MAAM,MAAM,eAAe,GAAG;IAAE,MAAM,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,SAAS,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,MAAM,EAAE,YAAY,CAAA;CAAE,CAAC;AAEhH;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,GAAG,IAAI,GAAG,MAAM,CAI3E;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,SAAS,GAAG,UAAU,CAe7D;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,UAAU,EAAE,MAAM,GAAE,MAAU,GAAG,eAAe,CA2BrF"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WAL 记录编解码
|
|
3
|
+
*
|
|
4
|
+
* 记录布局(小端):
|
|
5
|
+
* LSN(8) + 事务号(8) + 操作(1) + 键长度(4) + 值长度(4) + 键 + 值 + CRC32(4)。
|
|
6
|
+
*/
|
|
7
|
+
import { ByteReader, ByteWriter, BinaryUtils } from './binary';
|
|
8
|
+
/** WAL 记录头部长度(不含尾部校验和) */
|
|
9
|
+
export const WAL_RECORD_HEADER_SIZE = 25;
|
|
10
|
+
/** WAL 记录尾部校验和长度 */
|
|
11
|
+
export const WAL_RECORD_CHECKSUM_SIZE = 4;
|
|
12
|
+
/** WAL 操作类型 */
|
|
13
|
+
export var WalOperation;
|
|
14
|
+
(function (WalOperation) {
|
|
15
|
+
/** 写入或覆盖键 */
|
|
16
|
+
WalOperation[WalOperation["Put"] = 1] = "Put";
|
|
17
|
+
/** 删除键 */
|
|
18
|
+
WalOperation[WalOperation["Delete"] = 2] = "Delete";
|
|
19
|
+
/** 检查点标记 */
|
|
20
|
+
WalOperation[WalOperation["Checkpoint"] = 16] = "Checkpoint";
|
|
21
|
+
})(WalOperation || (WalOperation = {}));
|
|
22
|
+
/**
|
|
23
|
+
* 计算记录编码大小
|
|
24
|
+
* @param key 键
|
|
25
|
+
* @param value 值
|
|
26
|
+
*/
|
|
27
|
+
export function walRecordSize(key, value) {
|
|
28
|
+
const keyLength = BinaryUtils.byteLength(key);
|
|
29
|
+
const valueLength = value === null ? 0 : value.length;
|
|
30
|
+
return WAL_RECORD_HEADER_SIZE + keyLength + valueLength + WAL_RECORD_CHECKSUM_SIZE;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* 序列化 WAL 记录
|
|
34
|
+
* @param record 记录
|
|
35
|
+
*/
|
|
36
|
+
export function encodeWalRecord(record) {
|
|
37
|
+
const key = BinaryUtils.encode(record.key);
|
|
38
|
+
const value = record.value ?? new Uint8Array(0);
|
|
39
|
+
const writer = new ByteWriter(walRecordSize(record.key, record.value));
|
|
40
|
+
writer.writeBigUInt64LE(record.lsn);
|
|
41
|
+
writer.writeBigUInt64LE(record.transactionId);
|
|
42
|
+
writer.writeUInt8(record.operation);
|
|
43
|
+
writer.writeUInt32LE(key.length);
|
|
44
|
+
writer.writeUInt32LE(value.length);
|
|
45
|
+
writer.writeBytes(key);
|
|
46
|
+
writer.writeBytes(value);
|
|
47
|
+
writer.writeChecksum(0);
|
|
48
|
+
return writer.data;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* 反序列化 WAL 记录
|
|
52
|
+
*
|
|
53
|
+
* 尾部不完整(进程在写入中途退出)返回 `incomplete`,由恢复流程丢弃该尾部。
|
|
54
|
+
* 校验和不匹配属于真实损坏,会抛出 `ChecksumMismatchError`。
|
|
55
|
+
*
|
|
56
|
+
* @param data 数据
|
|
57
|
+
* @param offset 起始偏移量
|
|
58
|
+
*/
|
|
59
|
+
export function decodeWalRecord(data, offset = 0) {
|
|
60
|
+
const reader = new ByteReader(data, offset);
|
|
61
|
+
if (!reader.hasRemaining(WAL_RECORD_HEADER_SIZE)) {
|
|
62
|
+
return { status: 'incomplete' };
|
|
63
|
+
}
|
|
64
|
+
const start = reader.position;
|
|
65
|
+
const lsn = reader.readBigUInt64LE();
|
|
66
|
+
const transactionId = reader.readBigUInt64LE();
|
|
67
|
+
const operation = reader.readUInt8();
|
|
68
|
+
const keyLength = reader.readUInt32LE();
|
|
69
|
+
const valueLength = reader.readUInt32LE();
|
|
70
|
+
if (!reader.hasRemaining(keyLength + valueLength + WAL_RECORD_CHECKSUM_SIZE)) {
|
|
71
|
+
return { status: 'incomplete' };
|
|
72
|
+
}
|
|
73
|
+
const key = BinaryUtils.decode(reader.readBytes(keyLength));
|
|
74
|
+
const value = valueLength > 0 ? BinaryUtils.copy(reader.readBytes(valueLength)) : null;
|
|
75
|
+
reader.readAndVerifyChecksum(start);
|
|
76
|
+
return {
|
|
77
|
+
status: 'ok',
|
|
78
|
+
record: { lsn, transactionId, operation, key, value },
|
|
79
|
+
bytesRead: reader.position - start,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=record.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"record.js","sourceRoot":"","sources":["../../src/codec/record.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 跨标签页通知
|
|
3
|
+
*
|
|
4
|
+
* 多标签页各自持有内存视图,提交、schema 变更和关闭需要广播,
|
|
5
|
+
* 其他标签页据此丢弃陈旧视图。
|
|
6
|
+
*/
|
|
7
|
+
/** 数据库事件类型 */
|
|
8
|
+
export type DatabaseEventType = 'commit' | 'schema' | 'close';
|
|
9
|
+
/** 数据库事件 */
|
|
10
|
+
export interface DatabaseEvent {
|
|
11
|
+
/** 事件类型 */
|
|
12
|
+
type: DatabaseEventType;
|
|
13
|
+
/** 数据库名 */
|
|
14
|
+
name: string;
|
|
15
|
+
/** 提交后的 LSN,仅 `commit` 事件携带 */
|
|
16
|
+
lsn?: string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* 数据库事件广播器
|
|
20
|
+
*/
|
|
21
|
+
export declare class DatabaseBroadcaster {
|
|
22
|
+
private readonly channel;
|
|
23
|
+
constructor(name: string);
|
|
24
|
+
/**
|
|
25
|
+
* 发送事件
|
|
26
|
+
* @param event 事件
|
|
27
|
+
*/
|
|
28
|
+
notify(event: DatabaseEvent): void;
|
|
29
|
+
/** 关闭广播 */
|
|
30
|
+
close(): void;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* 监听数据库事件
|
|
34
|
+
* @param name 数据库名
|
|
35
|
+
* @param handler 处理函数
|
|
36
|
+
* @returns 取消监听
|
|
37
|
+
*/
|
|
38
|
+
export declare function listenDatabaseEvents(name: string, handler: (event: DatabaseEvent) => void): () => void;
|
|
39
|
+
//# sourceMappingURL=broadcast.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"broadcast.d.ts","sourceRoot":"","sources":["../../src/core/broadcast.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,cAAc;AACd,MAAM,MAAM,iBAAiB,GAAG,QAAQ,GAAG,QAAQ,GAAG,OAAO,CAAC;AAE9D,YAAY;AACZ,MAAM,WAAW,aAAa;IAC1B,WAAW;IACX,IAAI,EAAE,iBAAiB,CAAC;IACxB,WAAW;IACX,IAAI,EAAE,MAAM,CAAC;IACb,+BAA+B;IAC/B,GAAG,CAAC,EAAE,MAAM,CAAC;CAChB;AASD;;GAEG;AACH,qBAAa,mBAAmB;IAC5B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA8B;gBAE1C,IAAI,EAAE,MAAM;IAIxB;;;OAGG;IACI,MAAM,CAAC,KAAK,EAAE,aAAa,GAAG,IAAI;IAIzC,WAAW;IACJ,KAAK,IAAI,IAAI;CAGvB;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,GAAG,MAAM,IAAI,CActG"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 跨标签页通知
|
|
3
|
+
*
|
|
4
|
+
* 多标签页各自持有内存视图,提交、schema 变更和关闭需要广播,
|
|
5
|
+
* 其他标签页据此丢弃陈旧视图。
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* 数据库事件广播器
|
|
9
|
+
*/
|
|
10
|
+
export class DatabaseBroadcaster {
|
|
11
|
+
channel;
|
|
12
|
+
constructor(name) {
|
|
13
|
+
this.channel = createChannel(`yydb:${name}`);
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* 发送事件
|
|
17
|
+
* @param event 事件
|
|
18
|
+
*/
|
|
19
|
+
notify(event) {
|
|
20
|
+
this.channel?.postMessage(event);
|
|
21
|
+
}
|
|
22
|
+
/** 关闭广播 */
|
|
23
|
+
close() {
|
|
24
|
+
this.channel?.close();
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* 监听数据库事件
|
|
29
|
+
* @param name 数据库名
|
|
30
|
+
* @param handler 处理函数
|
|
31
|
+
* @returns 取消监听
|
|
32
|
+
*/
|
|
33
|
+
export function listenDatabaseEvents(name, handler) {
|
|
34
|
+
const channel = createChannel(`yydb:${name}`);
|
|
35
|
+
if (!channel) {
|
|
36
|
+
return () => undefined;
|
|
37
|
+
}
|
|
38
|
+
channel.onmessage = (event) => {
|
|
39
|
+
const data = event.data;
|
|
40
|
+
if (data && data.name === name) {
|
|
41
|
+
handler(data);
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
return () => channel.close();
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* 创建广播通道
|
|
48
|
+
* @param channelName 通道名
|
|
49
|
+
*/
|
|
50
|
+
function createChannel(channelName) {
|
|
51
|
+
const constructor = globalThis.BroadcastChannel;
|
|
52
|
+
return constructor ? new constructor(channelName) : null;
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=broadcast.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"broadcast.js","sourceRoot":"","sources":["../../src/core/broadcast.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAsBH;;GAEG;AACH,MAAM,OAAO,mBAAmB;IACX,OAAO,CAA8B;IAEtD,YAAY,IAAY;QACpB,IAAI,CAAC,OAAO,GAAG,aAAa,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC;IACjD,CAAC;IAED;;;OAGG;IACI,MAAM,CAAC,KAAoB;QAC9B,IAAI,CAAC,OAAO,EAAE,WAAW,CAAC,KAAK,CAAC,CAAC;IACrC,CAAC;IAED,WAAW;IACJ,KAAK;QACR,IAAI,CAAC,OAAO,EAAE,KAAK,EAAE,CAAC;IAC1B,CAAC;CACJ;AAED;;;;;GAKG;AACH,MAAM,UAAU,oBAAoB,CAAC,IAAY,EAAE,OAAuC;IACtF,MAAM,OAAO,GAAG,aAAa,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC;IAC9C,IAAI,CAAC,OAAO,EAAE,CAAC;QACX,OAAO,GAAG,EAAE,CAAC,SAAS,CAAC;IAC3B,CAAC;IAED,OAAO,CAAC,SAAS,GAAG,CAAC,KAAK,EAAE,EAAE;QAC1B,MAAM,IAAI,GAAG,KAAK,CAAC,IAA4B,CAAC;QAChD,IAAI,IAAI,IAAI,IAAI,CAAC,IAAI,KAAK,IAAI,EAAE,CAAC;YAC7B,OAAO,CAAC,IAAI,CAAC,CAAC;QAClB,CAAC;IACL,CAAC,CAAC;IAEF,OAAO,GAAG,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;AACjC,CAAC;AAED;;;GAGG;AACH,SAAS,aAAa,CAAC,WAAmB;IACtC,MAAM,WAAW,GAAI,UAA2F,CAAC,gBAAgB,CAAC;IAClI,OAAO,WAAW,CAAC,CAAC,CAAC,IAAI,WAAW,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AAC7D,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 检查点
|
|
3
|
+
*
|
|
4
|
+
* 把内存记录写成一份新快照,再用适配器的 `rename` 原子发布。
|
|
5
|
+
* 崩溃发生在发布前时旧快照仍然完整,WAL 会在下次打开时重放。
|
|
6
|
+
*/
|
|
7
|
+
import type { StorageAdapter } from '../storage/StorageAdapter';
|
|
8
|
+
/**
|
|
9
|
+
* 检查点写入器
|
|
10
|
+
*/
|
|
11
|
+
export declare class CheckpointWriter {
|
|
12
|
+
private readonly adapter;
|
|
13
|
+
private readonly pageSize;
|
|
14
|
+
constructor(adapter: StorageAdapter, pageSize: number);
|
|
15
|
+
/**
|
|
16
|
+
* 写入快照
|
|
17
|
+
* @param records 记录视图
|
|
18
|
+
* @param lsn 快照覆盖到的 LSN
|
|
19
|
+
* @returns 写入字节数
|
|
20
|
+
*/
|
|
21
|
+
write(records: ReadonlyMap<string, Uint8Array>, lsn: bigint): Promise<number>;
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=checkpoint.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"checkpoint.d.ts","sourceRoot":"","sources":["../../src/core/checkpoint.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAEhE;;GAEG;AACH,qBAAa,gBAAgB;IACzB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAiB;IACzC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;gBAEtB,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM;IAKrD;;;;;OAKG;IACU,KAAK,CAAC,OAAO,EAAE,WAAW,CAAC,MAAM,EAAE,UAAU,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;CAuB7F"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 检查点
|
|
3
|
+
*
|
|
4
|
+
* 把内存记录写成一份新快照,再用适配器的 `rename` 原子发布。
|
|
5
|
+
* 崩溃发生在发布前时旧快照仍然完整,WAL 会在下次打开时重放。
|
|
6
|
+
*/
|
|
7
|
+
import { encodeSnapshot } from '../codec';
|
|
8
|
+
import { LightDbError, LightDbErrorCodes } from '../errors';
|
|
9
|
+
/**
|
|
10
|
+
* 检查点写入器
|
|
11
|
+
*/
|
|
12
|
+
export class CheckpointWriter {
|
|
13
|
+
adapter;
|
|
14
|
+
pageSize;
|
|
15
|
+
constructor(adapter, pageSize) {
|
|
16
|
+
this.adapter = adapter;
|
|
17
|
+
this.pageSize = pageSize;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* 写入快照
|
|
21
|
+
* @param records 记录视图
|
|
22
|
+
* @param lsn 快照覆盖到的 LSN
|
|
23
|
+
* @returns 写入字节数
|
|
24
|
+
*/
|
|
25
|
+
async write(records, lsn) {
|
|
26
|
+
let data;
|
|
27
|
+
try {
|
|
28
|
+
data = encodeSnapshot(records, lsn, this.pageSize);
|
|
29
|
+
}
|
|
30
|
+
catch (error) {
|
|
31
|
+
throw new LightDbError(LightDbErrorCodes.unsupported, 'cannot encode database snapshot', {
|
|
32
|
+
operation: 'checkpoint',
|
|
33
|
+
cause: error,
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
const temp = await this.adapter.open('main.tmp', 'readwrite');
|
|
37
|
+
try {
|
|
38
|
+
await temp.truncate(0);
|
|
39
|
+
await temp.write(0, data);
|
|
40
|
+
await temp.sync();
|
|
41
|
+
}
|
|
42
|
+
finally {
|
|
43
|
+
await temp.close();
|
|
44
|
+
}
|
|
45
|
+
await this.adapter.rename('main.tmp', 'main');
|
|
46
|
+
return data.length;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=checkpoint.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"checkpoint.js","sourceRoot":"","sources":["../../src/core/checkpoint.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAC1C,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAG5D;;GAEG;AACH,MAAM,OAAO,gBAAgB;IACR,OAAO,CAAiB;IACxB,QAAQ,CAAS;IAElC,YAAY,OAAuB,EAAE,QAAgB;QACjD,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC7B,CAAC;IAED;;;;;OAKG;IACI,KAAK,CAAC,KAAK,CAAC,OAAwC,EAAE,GAAW;QACpE,IAAI,IAAgB,CAAC;QACrB,IAAI,CAAC;YACD,IAAI,GAAG,cAAc,CAAC,OAAO,EAAE,GAAG,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;QACvD,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACb,MAAM,IAAI,YAAY,CAAC,iBAAiB,CAAC,WAAW,EAAE,iCAAiC,EAAE;gBACrF,SAAS,EAAE,YAAY;gBACvB,KAAK,EAAE,KAAK;aACf,CAAC,CAAC;QACP,CAAC;QAED,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC;QAC9D,IAAI,CAAC;YACD,MAAM,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;YACvB,MAAM,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;YAC1B,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC;QACtB,CAAC;gBAAS,CAAC;YACP,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC;QACvB,CAAC;QAED,MAAM,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;QAC9C,OAAO,IAAI,CAAC,MAAM,CAAC;IACvB,CAAC;CACJ"}
|