fix: 修复 CI 卡死 + LZ4/SSTable/Checkpoint 多项 bug — 526 测试全通过
CI / test (18.x) (push) Successful in 10m1s
CI / test (20.x) (push) Successful in 10m6s
CI / test (22.x) (push) Successful in 10m2s
CI / test (24.x) (push) Successful in 10m6s

This commit is contained in:
thzxx
2026-07-27 20:28:23 +08:00
parent bc69d8f500
commit 620cd11521
16 changed files with 175 additions and 157 deletions
+21 -36
View File
@@ -71,7 +71,7 @@ export function compressLZ4(input: Uint8Array): Uint8Array {
output[dstIdx++] = (bestMatchOffset >> 8) & 0xFF;
srcIdx += matchLen + MIN_MATCH;
} else {
// 写入字面量
// 写入字面量:收集连续无匹配的字节,直到遇到可匹配序列或末尾
let litStart = srcIdx;
while (srcIdx < input.byteLength) {
const remaining = input.byteLength - srcIdx;
@@ -79,11 +79,9 @@ export function compressLZ4(input: Uint8Array): Uint8Array {
srcIdx += remaining;
break;
}
srcIdx++;
// 检查下一个位置是否有匹配
// 检查当前位置开始是否有 >= MIN_MATCH 长度的匹配
let hasMatch = false;
const nextEnd = Math.min(srcIdx, input.byteLength);
for (let i = Math.max(0, srcIdx - 65535); i < srcIdx && !hasMatch; i++) {
let ml = 0;
while (srcIdx + ml < input.byteLength && i + ml < srcIdx && input[i + ml] === input[srcIdx + ml] && ml < MIN_MATCH) {
@@ -93,9 +91,12 @@ export function compressLZ4(input: Uint8Array): Uint8Array {
}
if (hasMatch) {
srcIdx--;
// 当前位置开始可匹配,停止字面量收集(不输出当前字节,交给下一轮匹配处理)
break;
}
// 无匹配,将此字节纳入字面量
srcIdx++;
}
let litLen = srcIdx - litStart;
@@ -125,6 +126,11 @@ export function compressLZ4(input: Uint8Array): Uint8Array {
/**
* 解压 LZ4 数据。
*
* 与 compressLZ4 配套的简化格式:
* 每个 token 要么是字面量(低 4 位 = 0),要么是匹配(高 4 位 = 0)。
* 字面量 token: [hi4 = litLen] | 0x00 后跟 [litLen bytes]
* 匹配 token: 0x00 | [lo4 = matchLen] 后跟 [offset: 2B LE]
*/
export function decompressLZ4(
input: Uint8Array,
@@ -136,46 +142,25 @@ export function decompressLZ4(
while (srcIdx < input.byteLength && dstIdx < originalSize) {
const token = input[srcIdx++];
let literalLen = (token >> 4) & 0x0F;
// 扩展字面量长度
if (literalLen === 15) {
while (srcIdx < input.byteLength && input[srcIdx] === 255) {
literalLen += 255;
srcIdx++;
}
if (srcIdx < input.byteLength) {
literalLen += input[srcIdx++];
}
}
const litLen = (token >> 4) & 0x0F;
const matchLenField = token & 0x0F;
// 复制字面量
for (let i = 0; i < literalLen && srcIdx < input.byteLength && dstIdx < originalSize; i++) {
for (let i = 0; i < litLen && srcIdx < input.byteLength && dstIdx < originalSize; i++) {
output[dstIdx++] = input[srcIdx++];
}
if (srcIdx >= input.byteLength || dstIdx >= originalSize) break;
// 偏移量
const offset = input[srcIdx++] | (input[srcIdx++] << 8);
if (matchLenField > 0) {
// 读取偏移量并复制匹配
const offset = input[srcIdx++] | (input[srcIdx++] << 8);
const matchLen = matchLenField + MIN_MATCH;
let matchLen = (token & 0x0F) + MIN_MATCH;
// 扩展匹配长度
if ((token & 0x0F) === 15) {
while (srcIdx < input.byteLength && input[srcIdx] === 255) {
matchLen += 255;
srcIdx++;
for (let i = 0; i < matchLen && dstIdx < originalSize; i++) {
output[dstIdx] = output[dstIdx - offset];
dstIdx++;
}
if (srcIdx < input.byteLength) {
matchLen += input[srcIdx++];
}
}
// 复制匹配
for (let i = 0; i < matchLen && dstIdx < originalSize; i++) {
output[dstIdx] = output[dstIdx - offset];
dstIdx++;
}
}
+2 -2
View File
@@ -330,8 +330,8 @@ export class LSM {
this.freezeMemtable();
this.flushImmutableSync();
}
// 等待存储完成
await new Promise((r) => setTimeout(r, 10));
// 确保所有微任务完成(不使用 setTimeout,避免额外 timer 阻止进程退出)
await Promise.resolve();
}
async clear(): Promise<void> {
+9 -6
View File
@@ -30,8 +30,8 @@ export class SSTableReader {
// -----------------------------------------------------------------------
/** 精确查找 key */
get(key: string): Record<string, unknown> | null {
const blockIdx = this.locateBlock(key);
get(targetKey: string): Record<string, unknown> | null {
const blockIdx = this.locateBlock(targetKey);
if (blockIdx < 0) return null;
const entry = this.indexEntries[blockIdx];
@@ -45,8 +45,7 @@ export class SSTableReader {
const entryCount = blockView.getUint32(0, false);
let offset = 4;
// 二分查找 block 内的 key
// 为简单起见,这里使用顺序扫描(生产中应二分查找)
// 顺序扫描 block 内的条目(生产中应二分查找)
for (let i = 0; i < entryCount; i++) {
const keyLen = blockView.getUint16(offset, false);
offset += 2;
@@ -57,8 +56,12 @@ export class SSTableReader {
const valBytes = blockData.slice(offset, offset + valLen);
offset += valLen;
if (key === key) {
return JSON.parse(new TextDecoder().decode(valBytes));
if (key === targetKey) {
try {
return JSON.parse(new TextDecoder().decode(valBytes));
} catch {
return null;
}
}
}