Skip to content

Commit 3081f3f

Browse files
authored
Merge pull request #18 from shogun444/add-purge-api
feat: add purge API support for TidesDB v8.7.0
2 parents b523c2c + fdea8f5 commit 3081f3f

4 files changed

Lines changed: 751 additions & 427 deletions

File tree

src/column-family.ts

Lines changed: 94 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -23,16 +23,25 @@ import {
2323
tidesdb_flush_memtable,
2424
tidesdb_is_flushing,
2525
tidesdb_is_compacting,
26+
tidesdb_purge_cf,
2627
tidesdb_cf_update_runtime_config,
2728
tidesdb_range_cost,
2829
tidesdb_cf_set_commit_hook,
2930
CommitOpStruct,
3031
commitHookPtrType,
3132
StatsStruct,
3233
ColumnFamilyConfigStruct,
33-
} from './ffi';
34-
import { checkResult } from './error';
35-
import { Stats, ColumnFamilyConfig, CompressionAlgorithm, SyncMode, IsolationLevel, CommitOp, CommitHookCallback } from './types';
34+
} from "./ffi";
35+
import { checkResult } from "./error";
36+
import {
37+
Stats,
38+
ColumnFamilyConfig,
39+
CompressionAlgorithm,
40+
SyncMode,
41+
IsolationLevel,
42+
CommitOp,
43+
CommitHookCallback,
44+
} from "./types";
3645

3746
// Opaque pointer type for column family
3847
type CFPtr = unknown;
@@ -71,15 +80,18 @@ export class ColumnFamily {
7180
const statsPtrOut: unknown[] = [null];
7281

7382
const result = tidesdb_get_stats(this._cf, statsPtrOut);
74-
checkResult(result, 'failed to get stats');
83+
checkResult(result, "failed to get stats");
7584

7685
const statsPtr = statsPtrOut[0];
7786
if (!statsPtr) {
78-
throw new Error('failed to get stats: null pointer returned');
87+
throw new Error("failed to get stats: null pointer returned");
7988
}
8089

8190
// Decode the stats struct from the pointer
82-
const decoded = koffi.decode(statsPtr, StatsStruct) as Record<string, unknown>;
91+
const decoded = koffi.decode(statsPtr, StatsStruct) as Record<
92+
string,
93+
unknown
94+
>;
8395

8496
const numLevels = (decoded.num_levels ?? 0) as number;
8597
const memtableSize = (decoded.memtable_size ?? 0) as number;
@@ -102,15 +114,27 @@ export class ColumnFamily {
102114
if (numLevels > 0) {
103115
try {
104116
if (decoded.level_sizes) {
105-
const sizes = koffi.decode(decoded.level_sizes, 'size_t', numLevels) as number[];
117+
const sizes = koffi.decode(
118+
decoded.level_sizes,
119+
"size_t",
120+
numLevels,
121+
) as number[];
106122
levelSizes.push(...sizes);
107123
}
108124
if (decoded.level_num_sstables) {
109-
const counts = koffi.decode(decoded.level_num_sstables, 'int', numLevels) as number[];
125+
const counts = koffi.decode(
126+
decoded.level_num_sstables,
127+
"int",
128+
numLevels,
129+
) as number[];
110130
levelNumSSTables.push(...counts);
111131
}
112132
if (decoded.level_key_counts) {
113-
const keyCounts = koffi.decode(decoded.level_key_counts, 'uint64_t', numLevels) as number[];
133+
const keyCounts = koffi.decode(
134+
decoded.level_key_counts,
135+
"uint64_t",
136+
numLevels,
137+
) as number[];
114138
levelKeyCounts.push(...keyCounts);
115139
}
116140
} catch {
@@ -122,14 +146,18 @@ export class ColumnFamily {
122146
let config: ColumnFamilyConfig | undefined;
123147
if (decoded.config) {
124148
try {
125-
const cfgDecoded = koffi.decode(decoded.config, ColumnFamilyConfigStruct) as Record<string, unknown>;
149+
const cfgDecoded = koffi.decode(
150+
decoded.config,
151+
ColumnFamilyConfigStruct,
152+
) as Record<string, unknown>;
126153
config = {
127154
writeBufferSize: cfgDecoded.write_buffer_size as number,
128155
levelSizeRatio: cfgDecoded.level_size_ratio as number,
129156
minLevels: cfgDecoded.min_levels as number,
130157
dividingLevelOffset: cfgDecoded.dividing_level_offset as number,
131158
klogValueThreshold: cfgDecoded.klog_value_threshold as number,
132-
compressionAlgorithm: cfgDecoded.compression_algorithm as CompressionAlgorithm,
159+
compressionAlgorithm:
160+
cfgDecoded.compression_algorithm as CompressionAlgorithm,
133161
enableBloomFilter: (cfgDecoded.enable_bloom_filter as number) !== 0,
134162
bloomFpr: cfgDecoded.bloom_fpr as number,
135163
enableBlockIndexes: (cfgDecoded.enable_block_indexes as number) !== 0,
@@ -139,7 +167,8 @@ export class ColumnFamily {
139167
syncIntervalUs: cfgDecoded.sync_interval_us as number,
140168
skipListMaxLevel: cfgDecoded.skip_list_max_level as number,
141169
skipListProbability: cfgDecoded.skip_list_probability as number,
142-
defaultIsolationLevel: cfgDecoded.default_isolation_level as IsolationLevel,
170+
defaultIsolationLevel:
171+
cfgDecoded.default_isolation_level as IsolationLevel,
143172
minDiskSpace: cfgDecoded.min_disk_space as number,
144173
l1FileCountTrigger: cfgDecoded.l1_file_count_trigger as number,
145174
l0QueueStallThreshold: cfgDecoded.l0_queue_stall_threshold as number,
@@ -177,15 +206,15 @@ export class ColumnFamily {
177206
*/
178207
compact(): void {
179208
const result = tidesdb_compact(this._cf);
180-
checkResult(result, 'failed to compact column family');
209+
checkResult(result, "failed to compact column family");
181210
}
182211

183212
/**
184213
* Manually trigger memtable flush for the column family.
185214
*/
186215
flushMemtable(): void {
187216
const result = tidesdb_flush_memtable(this._cf);
188-
checkResult(result, 'failed to flush memtable');
217+
checkResult(result, "failed to flush memtable");
189218
}
190219

191220
/**
@@ -204,17 +233,28 @@ export class ColumnFamily {
204233
return tidesdb_is_compacting(this._cf) !== 0;
205234
}
206235

236+
/**
237+
* Purge this column family by flushing and synchronously compacting.
238+
*/
239+
purgeColumnFamily(): void {
240+
const result = tidesdb_purge_cf(this._cf);
241+
checkResult(result, "failed to purge column family");
242+
}
243+
207244
/**
208245
* Update runtime-safe configuration settings.
209246
* Changes apply to new operations only.
210247
* @param config New configuration values.
211248
* @param persistToDisk If true, save changes to config.ini.
212249
*/
213-
updateRuntimeConfig(config: ColumnFamilyConfig, persistToDisk: boolean = false): void {
250+
updateRuntimeConfig(
251+
config: ColumnFamilyConfig,
252+
persistToDisk: boolean = false,
253+
): void {
214254
// Build the comparator_name as an array of char codes
215255
const comparatorNameArr = new Array(64).fill(0);
216256
if (config.comparatorName) {
217-
const nameBytes = Buffer.from(config.comparatorName, 'utf8');
257+
const nameBytes = Buffer.from(config.comparatorName, "utf8");
218258
for (let i = 0; i < Math.min(nameBytes.length, 63); i++) {
219259
comparatorNameArr[i] = nameBytes[i];
220260
}
@@ -228,7 +268,8 @@ export class ColumnFamily {
228268
min_levels: config.minLevels ?? 0,
229269
dividing_level_offset: config.dividingLevelOffset ?? 0,
230270
klog_value_threshold: config.klogValueThreshold ?? 0,
231-
compression_algorithm: config.compressionAlgorithm ?? CompressionAlgorithm.Lz4Compression,
271+
compression_algorithm:
272+
config.compressionAlgorithm ?? CompressionAlgorithm.Lz4Compression,
232273
enable_bloom_filter: config.enableBloomFilter ? 1 : 0,
233274
bloom_fpr: config.bloomFpr ?? 0.01,
234275
enable_block_indexes: config.enableBlockIndexes ? 1 : 0,
@@ -242,7 +283,8 @@ export class ColumnFamily {
242283
comparator_ctx_cached: null,
243284
skip_list_max_level: config.skipListMaxLevel ?? 12,
244285
skip_list_probability: config.skipListProbability ?? 0.25,
245-
default_isolation_level: config.defaultIsolationLevel ?? IsolationLevel.ReadCommitted,
286+
default_isolation_level:
287+
config.defaultIsolationLevel ?? IsolationLevel.ReadCommitted,
246288
min_disk_space: config.minDiskSpace ?? 100 * 1024 * 1024,
247289
l1_file_count_trigger: config.l1FileCountTrigger ?? 4,
248290
l0_queue_stall_threshold: config.l0QueueStallThreshold ?? 20,
@@ -251,8 +293,12 @@ export class ColumnFamily {
251293
commit_hook_ctx: null,
252294
};
253295

254-
const result = tidesdb_cf_update_runtime_config(this._cf, cConfig, persistToDisk ? 1 : 0);
255-
checkResult(result, 'failed to update runtime config');
296+
const result = tidesdb_cf_update_runtime_config(
297+
this._cf,
298+
cConfig,
299+
persistToDisk ? 1 : 0,
300+
);
301+
checkResult(result, "failed to update runtime config");
256302
}
257303

258304
/**
@@ -268,12 +314,19 @@ export class ColumnFamily {
268314
}
269315

270316
// Create wrapper that decodes C data to TypeScript types
271-
const wrapper = (opsPtr: unknown, numOps: number, commitSeq: number, _ctx: unknown): number => {
317+
const wrapper = (
318+
opsPtr: unknown,
319+
numOps: number,
320+
commitSeq: number,
321+
_ctx: unknown,
322+
): number => {
272323
try {
273324
const ops: CommitOp[] = [];
274325

275326
if (numOps > 0 && opsPtr) {
276-
const rawOps = koffi.decode(opsPtr, CommitOpStruct, numOps) as Array<Record<string, unknown>>;
327+
const rawOps = koffi.decode(opsPtr, CommitOpStruct, numOps) as Array<
328+
Record<string, unknown>
329+
>;
277330

278331
for (const rawOp of rawOps) {
279332
const keySize = rawOp.key_size as number;
@@ -282,13 +335,21 @@ export class ColumnFamily {
282335

283336
let key = Buffer.alloc(0);
284337
if (rawOp.key && keySize > 0) {
285-
const keyBytes = koffi.decode(rawOp.key, 'uint8_t', keySize) as number[];
338+
const keyBytes = koffi.decode(
339+
rawOp.key,
340+
"uint8_t",
341+
keySize,
342+
) as number[];
286343
key = Buffer.from(keyBytes);
287344
}
288345

289346
let value: Buffer | null = null;
290347
if (!isDelete && rawOp.value && valueSize > 0) {
291-
const valueBytes = koffi.decode(rawOp.value, 'uint8_t', valueSize) as number[];
348+
const valueBytes = koffi.decode(
349+
rawOp.value,
350+
"uint8_t",
351+
valueSize,
352+
) as number[];
292353
value = Buffer.from(valueBytes);
293354
}
294355

@@ -309,8 +370,12 @@ export class ColumnFamily {
309370

310371
this._commitHookCb = koffi.register(wrapper, commitHookPtrType);
311372

312-
const result = tidesdb_cf_set_commit_hook(this._cf, this._commitHookCb, null);
313-
checkResult(result, 'failed to set commit hook');
373+
const result = tidesdb_cf_set_commit_hook(
374+
this._cf,
375+
this._commitHookCb,
376+
null,
377+
);
378+
checkResult(result, "failed to set commit hook");
314379
}
315380

316381
/**
@@ -319,7 +384,7 @@ export class ColumnFamily {
319384
*/
320385
clearCommitHook(): void {
321386
const result = tidesdb_cf_set_commit_hook(this._cf, null, null);
322-
checkResult(result, 'failed to clear commit hook');
387+
checkResult(result, "failed to clear commit hook");
323388

324389
if (this._commitHookCb) {
325390
koffi.unregister(this._commitHookCb as never);
@@ -336,9 +401,9 @@ export class ColumnFamily {
336401
keyA.length,
337402
keyB,
338403
keyB.length,
339-
costOut
404+
costOut,
340405
);
341-
checkResult(result, 'failed to estimate range cost');
406+
checkResult(result, "failed to estimate range cost");
342407

343408
return costOut[0];
344409
}

0 commit comments

Comments
 (0)