feat: v0.6.1 — AriaEngine 可选自研 KVStore 后端(storageBackend: 'kv')+ KVStore APPEND 日志类型 + 10 个 aria+kv 集成测试 + 文档全量同步
This commit is contained in:
@@ -223,6 +223,18 @@ export class KVStore {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* v0.6.1: 追加写入(value 拼接语义)— aria WAL 分片等追加型数据用。
|
||||
* 日志记录 APPEND 类型(O(chunk) 高效),恢复时按 seq 顺序拼接,
|
||||
* checkpoint 后快照含最终值。崩溃时该次追加全有或全无(单记录原子)。
|
||||
*/
|
||||
async appendValue(key: string, chunk: ArrayBuffer): Promise<void> {
|
||||
if (chunk.byteLength === 0) return;
|
||||
await this.enqueue(async () => {
|
||||
await this.appendRecord({}, [], { [key]: chunk });
|
||||
});
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
// 维护
|
||||
// =======================================================================
|
||||
@@ -301,9 +313,13 @@ export class KVStore {
|
||||
}
|
||||
|
||||
/** 追加一条日志记录并更新内存索引(队列内调用,无并发) */
|
||||
private async appendRecord(puts: Record<string, ArrayBuffer>, deletes: string[]): Promise<void> {
|
||||
private async appendRecord(
|
||||
puts: Record<string, ArrayBuffer>,
|
||||
deletes: string[],
|
||||
appends: Record<string, ArrayBuffer> = {},
|
||||
): Promise<void> {
|
||||
this.seq++;
|
||||
const record = encodeLogRecord(this.seq, puts, deletes);
|
||||
const record = encodeLogRecord(this.seq, puts, deletes, appends);
|
||||
try {
|
||||
// 日志追加:介质 append(真追加)或回退读+拼+写
|
||||
const data = record.buffer.slice(record.byteOffset, record.byteOffset + record.byteLength) as ArrayBuffer;
|
||||
@@ -334,6 +350,17 @@ export class KVStore {
|
||||
for (const key of deletes) {
|
||||
this.index.delete(key);
|
||||
}
|
||||
for (const [key, chunk] of Object.entries(appends)) {
|
||||
const existing = this.index.get(key);
|
||||
if (existing) {
|
||||
const combined = new Uint8Array(existing.byteLength + chunk.byteLength);
|
||||
combined.set(new Uint8Array(existing), 0);
|
||||
combined.set(new Uint8Array(chunk), existing.byteLength);
|
||||
this.index.set(key, combined.buffer as ArrayBuffer);
|
||||
} else {
|
||||
this.index.set(key, chunk);
|
||||
}
|
||||
}
|
||||
this.logBytes += record.byteLength;
|
||||
|
||||
// 自动 checkpoint(日志超阈值)
|
||||
@@ -358,6 +385,16 @@ export class KVStore {
|
||||
for (const e of entries) {
|
||||
if (e.op === KVLogOp.PUT) {
|
||||
this.index.set(e.key, e.value);
|
||||
} else if (e.op === KVLogOp.APPEND) {
|
||||
const existing = this.index.get(e.key);
|
||||
if (existing) {
|
||||
const combined = new Uint8Array(existing.byteLength + e.value.byteLength);
|
||||
combined.set(new Uint8Array(existing), 0);
|
||||
combined.set(new Uint8Array(e.value), existing.byteLength);
|
||||
this.index.set(e.key, combined.buffer as ArrayBuffer);
|
||||
} else {
|
||||
this.index.set(e.key, e.value);
|
||||
}
|
||||
} else {
|
||||
this.index.delete(e.key);
|
||||
}
|
||||
|
||||
@@ -23,6 +23,8 @@ import { crc32 } from '../aria/crc32';
|
||||
export const enum KVLogOp {
|
||||
PUT = 1,
|
||||
DELETE = 2,
|
||||
/** v0.6.1: 追加写入(value 拼接语义,恢复时按序 concat;aria WAL 分片用) */
|
||||
APPEND = 3,
|
||||
}
|
||||
|
||||
/** 解析后的日志记录 */
|
||||
@@ -40,11 +42,13 @@ export interface KVLogRecord {
|
||||
* @param seq 日志序号
|
||||
* @param puts key → value 写入条目
|
||||
* @param deletes 删除 key 列表
|
||||
* @param appends key → 追加块列表(APPEND 语义,恢复时拼接)
|
||||
*/
|
||||
export function encodeLogRecord(
|
||||
seq: number,
|
||||
puts: Record<string, ArrayBuffer>,
|
||||
deletes: string[] = [],
|
||||
appends: Record<string, ArrayBuffer> = {},
|
||||
): Uint8Array {
|
||||
const encoder = new TextEncoder();
|
||||
const entries: { op: KVLogOp; key: string; value: ArrayBuffer }[] = [];
|
||||
@@ -54,6 +58,9 @@ export function encodeLogRecord(
|
||||
for (const key of deletes) {
|
||||
entries.push({ op: KVLogOp.DELETE, key, value: new ArrayBuffer(0) });
|
||||
}
|
||||
for (const [key, value] of Object.entries(appends)) {
|
||||
entries.push({ op: KVLogOp.APPEND, key, value });
|
||||
}
|
||||
|
||||
// 预编码 key 字节,计算总长度
|
||||
const entryBytes: { op: KVLogOp; key: Uint8Array; value: Uint8Array }[] = [];
|
||||
|
||||
Reference in New Issue
Block a user