Skip to main content

Update, Delete, Compaction & Autovacuum

Overview

This project implements the full UPDATE / DELETE / COMPACTION pipeline for RookDB, using a soft-delete model with a background autovacuum system.


Sub-pages

PageContents
Data StructuresAll new data structures introduced in this phase
File & Page ChangesNew files, modified files, page layout changes
Backend FunctionsEvery new backend function and its purpose
Frontend CLI StepsInteractive CLI usage for delete, update, and compact
AlgorithmsDELETE, UPDATE, compaction, and autovacuum algorithms
Benchmark ResultsRookDB vs PostgreSQL performance results

Core Design

RookDB follows a PostgreSQL-style deferred-maintenance model:

DELETE / UPDATE (old version)  →  mark slot as deleted  (soft-delete)
SHOW / SCAN → skip slots with SLOT_FLAG_DELETED
COMPACTION → rewrite page, physically reclaim space
AUTOVACUUM → background workers trigger compaction automatically

Soft-delete slot layout

Each slot entry in a page item-id array is 8 bytes:

[ offset: u32 (4 bytes) ][ length: u16 (2 bytes) ][ flags: u16 (2 bytes) ]

The deleted bit:

SLOT_FLAG_DELETED = 0x0001

A slot with this bit set is logically invisible: scans skip it and updates never touch it.

Table header layout (Page 0)

Page 0 of every .dat file is the table header, carrying two u32 counters:

bytes 0..4  →  page_count        (u32, little-endian)
bytes 4..8 → dead_tuple_count (u32, little-endian)
bytes 8.. → reserved / zeroed

dead_tuple_count is incremented by every DELETE and every UPDATE (old-version soft-delete). Autovacuum reads this counter to decide when to schedule compaction.


Intermediate Files Generated

Every mutation operation produces structured log entries. Logs live at:

database/logs/<db_name>/<table_name>/
update.log
delete.log
compaction.log

Each log entry is a JSON object:

{
"timestamp": "2026-04-20T12:34:56.789Z",
"operation": "delete",
"details": { ... },
"status": "success"
}

Core APIs

Update API

pub fn update_tuples(
catalog: &Catalog,
db_name: &str,
table_name: &str,
file: &mut File,
assignments: &[SetAssignment],
condition_groups: &[Vec<Condition>],
returning: bool,
) -> io::Result<UpdateResult>

Return value:

  • UpdateResult.updated_count — number of rows updated
  • UpdateResult.returning_rows — updated rows when RETURNING is enabled

Delete API

pub fn delete_tuples(
catalog: &Catalog,
db_name: &str,
table_name: &str,
file: &mut File,
condition_groups: &[Vec<Condition>],
returning: bool,
) -> io::Result<DeleteResult>

Return value:

  • DeleteResult.deleted_count — number of rows deleted
  • DeleteResult.returning_rows — deleted rows when RETURNING is enabled

Compaction API

pub fn compaction_table(
db_name: &str,
table_name: &str,
) -> io::Result<usize>

Return value: number of data pages that were physically compacted.


Cross-Team Integration Points

This component integrates with the heap/FSM team through src/backend/executor/api.rs.

API / FunctionUsed forProvided by
insert_raw_tuple(db, table, data)Insert re-versioned tuple bytes during UPDATEapi.rs — delegates to HeapManager::insert_tuple
rebuild_table_fsm(db, table)Rebuild FSM after DELETE or compaction changes free-spaceapi.rs — calls FSM::build_from_heap

Autocompaction flow:

autovacuum worker → compaction_table() → rebuild_table_fsm() → FSM::build_from_heap()

Testing & Robustness

Edge cases covered

  • Deleting all rows in a table
  • Deleting rows already soft-deleted
  • UPDATE with no matching rows
  • Nested boolean predicates in WHERE ((a AND b) OR c)
  • LIKE / NOT LIKE applied to INT columns (must not match)
  • Compaction idempotency (running twice produces same result)
  • Preserving live tuples during compaction
  • Concurrent write safety at page level

Test files

FileTestsScope
code/tests/test_update.rs30Condition matching, arithmetic SET, zero-match updates, page-lock during update, RETURNING
code/tests/test_delete.rs57Soft-delete correctness, zero-match, delete-all, page-lock safety, WHERE edge cases
code/tests/test_compaction.rs10Live-tuple preservation, lock held during rewrite, idempotency, post-compaction free space
code/tests/test_page_lock.rsPageWriteLock delays concurrent mutators by ≥ 4 500 ms
code/tests/test_fsm_large.rsFSM correctness at scale after many inserts and compactions

Feature Status

FeatureStatus
Soft-delete via slot flags✅ Done
WHERE parser with DNF (AND / OR / parentheses)✅ Done
UPDATE with arithmetic SET✅ Done
Compaction✅ Done
Autovacuum thresholding✅ Done
Page-level locking✅ Done
Operation logging with ISO timestamps✅ Done
Visibility Map integration✅ Done
Benchmark harness (RookDB vs PostgreSQL)✅ Done

PostgreSQL References


Potential Future Work

AreaDescription
MVCCReplace soft-delete with transaction-ID stamped tuple versions
WAL integrationWrite-ahead log before any mutation for crash recovery
Incremental compactionOnly compact pages above a dead-tuple density threshold
Index integrationInvalidate / update index entries on DELETE and UPDATE
Row-level lockingUpgrade from page-level to tuple-level locks