* refactor(mito): retain region compaction and DDL lifecycle state Signed-off-by: Lei, HUANG <ratuthomm@gmail.com> * fix(mito): finalize opening batch in the worker on registration Clean up the `opening_regions` entry and reply to its waiters in the same serialized worker step that registers an opened region, instead of waiting for the background opener to resume after the registration acknowledgement. Previously the entry was only removed by the background opener, so a close followed by a reopen could join the stale opening batch and receive a false success after the region no longer existed. Replying from the worker closes that window because registration and waiter cleanup are now atomic with respect to the worker loop. Add a test-only `EventListener::on_region_open_registered` hook and a regression test that holds the first background opener to verify a reopen does not wait for the previous open task. On failure the region is still stopped and waiters receive `RegionClosed`. Signed-off-by: Lei, HUANG <ratuthomm@gmail.com> * fix(mito): unregister drop runtime state before WAL cleanup The region leaves the region map before its WAL entries are obsoleted. A failure in `wal.obsolete(...).await?` returned early and skipped `cleanup_dropped_region_runtime_state`, so the resident compaction, flush, and index scheduler entries were never unregistered. Since the region is no longer in the map, a later close cannot clean them up either, leaking the entries for the rest of the worker's lifetime. Move the runtime-state cleanup to immediately after the region leaves the map, before the fallible WAL cleanup. The schedulers only touch their own state and do not depend on the region map or WAL, so the reordering is safe and leaves the success path unchanged. Signed-off-by: Lei, HUANG <ratuthomm@gmail.com> * refactor(mito): tighten visibility of new compaction state items Keep `ActiveCompaction::idle` private (it is only used inside `state.rs`) and expose the other items added by the resident-region refactor as `pub(crate)` instead of `pub(super)`, per the style guide. Also drop a stale comment in `on_compaction_finished`: DDL handoff now happens in `take_ready_ddls` before this block, which only runs when no DDL is queued. Signed-off-by: Lei, HUANG <ratuthomm@gmail.com> * fix(mito): skip compaction scheduling while a region is truncating `handle_flush_finished` dispatches queued DDLs before scheduling compaction. A truncate queued behind a committing flush marks the region as `Truncating` synchronously, but `schedule_compaction` only skipped staging states, so it could schedule a new automatic compaction while the truncate was still running. Add `MitoRegion::is_truncating` and skip compaction scheduling for a truncating region. Add a regression test that queues a full truncate behind a committing flush and asserts no compaction is scheduled. Signed-off-by: Lei, HUANG <ratuthomm@gmail.com> * fix(mito): log DDL-fenced compaction rejection The refactor dropped the log emitted when a region was skipped because of pending DDL requests. Automatic triggers carry no waiter, so the rejection became silent and could not be told apart from a scheduling interval that had not elapsed. Log the queued and executing DDL state before cancelling. Signed-off-by: Lei, HUANG <ratuthomm@gmail.com> * docs(mito): document DDL reply fence invariants Explain why fence_ddl_replies installs executing_ddl before handing off the batch and why CompactionDdlComplete carries both a scheduler-wide generation and a per-slot request_id. The generation fences replies from superseded batches or region incarnations, while request_id makes completion idempotent so only the last distinct reply releases the fence. Signed-off-by: Lei, HUANG <ratuthomm@gmail.com> * refactor(mito): rename DDL completion request_id to request_index The value is the DDL's index within the handed-off batch, not a globally stable request identifier; request_id suggested otherwise. Rename it to request_index across the scheduler, worker dispatch, and tests. Signed-off-by: Lei, HUANG <ratuthomm@gmail.com> --------- Signed-off-by: Lei, HUANG <ratuthomm@gmail.com>
5.5 KiB
mito2 — Agent & Contributor Guide
Navigation aid for src/mito2. Keep it short and point to code; do not duplicate
the code here. Paths are relative to the repo root.
Repo-wide rules that apply here: .agents/architecture-invariants.md.
What this crate does
Mito2 is GreptimeDB's primary time-series region storage engine. It owns the
write path (memtable + WAL), flushing memtables to Parquet SST files,
TWCS/windowed compaction, and the read path (multi-level merge + dedup with
snapshot isolation). It implements the RegionEngine trait from store-api.
Module map
| Module | Path | Purpose |
|---|---|---|
engine |
src/mito2/src/engine.rs |
MitoEngine (the RegionEngine impl) and request dispatch |
worker |
src/mito2/src/worker.rs, src/mito2/src/worker/ |
Per-region worker loop; write/alter/flush handlers |
region |
src/mito2/src/region.rs, src/mito2/src/region/version.rs |
MitoRegion state and copy-on-write VersionControl snapshots |
request |
src/mito2/src/request.rs |
WriteRequest/RegionRequest types and result channels |
wal |
src/mito2/src/wal.rs |
Write-ahead log wrapper over log-store |
memtable |
src/mito2/src/memtable/ |
In-memory write buffers (time-series / bulk / partition) |
flush |
src/mito2/src/flush.rs |
FlushScheduler, WriteBufferManager, memtable → SST |
compaction |
src/mito2/src/compaction/ |
Compaction scheduler (scheduler.rs + scheduler/), TWCS picker, strict-window manual picker, compactor, memory control |
access_layer |
src/mito2/src/access_layer.rs |
SST read/write over the object store |
sst |
src/mito2/src/sst/ |
Parquet format, file metadata, index layout |
series_index |
src/mito2/src/series_index/ |
Series index writer/searcher, bucket planning, catalogs, worker-owned reconciliation (maintenance.rs), shared approximate usage (task.rs), catalogs, and index lifecycle |
read |
src/mito2/src/read/ |
ScanRegion, merge, dedup, projection, streaming |
manifest |
src/mito2/src/manifest/ |
RegionManifestManager, manifest actions/edits |
cache |
src/mito2/src/cache.rs |
Write/file/page caches |
gc |
src/mito2/src/gc.rs, src/mito2/src/gc/ |
Dropped-file cleanup worker |
schedule |
src/mito2/src/schedule/ |
Local/remote background job scheduling |
remap_manifest |
src/mito2/src/remap_manifest.rs |
Manifest path remapping for region copy/migration |
config |
src/mito2/src/config.rs |
MitoConfig tuning knobs |
test_util |
src/mito2/src/test_util.rs |
TestEnv and builders (under the test feature) |
Write path
MitoEngine::handle_request (engine.rs) → worker loop
(worker/handle_write.rs) → sequence + WAL assembly (region_write_ctx.rs) →
wal.rs → memtable (memtable/) → when buffer pressure trips, flush.rs
writes SSTs via access_layer.rs and appends a RegionEdit to the manifest
(manifest/manager.rs).
Read path
MitoEngine::handle_query (engine.rs) → read/scan_region.rs takes an
immutable Version (region/version.rs) → scans memtables and Parquet SSTs
(sst/parquet.rs) → merges (read/) and dedups by sequence → projected,
filtered RecordBatch stream.
Public surface
- Entry:
MitoEngineinsrc/mito2/src/engine.rs, built viaMitoEngineBuilder. - Trait:
impl RegionEngine for MitoEngine(store-api's region engine contract). - Consumed by
datanode(sendsRegionRequests) and the query layer (scans).
When you change X, also touch Y
- Manifest format (
manifest/action.rs): affects crash recovery and follower replay. Keep it backward compatible. - SST/Parquet layout (
sst/): readers must stay compatible with existing files. - Series-index disk limit: tasks estimate usage from entry sizes in open-region snapshots and defer new builds when the shared estimate is full. Cleanup still prunes obsolete range entries and expires series indexes to reclaim published usage. Concurrent builds may overshoot; closed-region files are not counted. Series handles and the SST purger own file deletion.
- Series-index coverage (
series_index/catalog.rs):SeriesIndexEntrystores compaction-window width and SST summaries keyed by aligned start in both catalogs and Parquet footers. - Request types (
request.rs): usually tied to proto definitions consumed bydatanode. - WAL/memtable encoding (
wal/,memtable/): breaks replay if changed incompatibly.
Testing
cargo nextest run -p mito2
Tests live next to the code as *_test.rs (e.g. src/mito2/src/engine/flush_test.rs).
TestEnv in test_util.rs spins up an engine over an in-process object store.
Gotchas
- Sequence numbers are strictly increasing per region; dedup and snapshot reads depend on this. Do not change assignment lightly.
- Manifest version is monotonic — never reset or skip it.
- Lock ordering: take the manifest lock before updating
version_control; the reverse deadlocks against concurrent flush/compaction. - All region I/O runs on tokio workers; never
block_oninside a worker. - Loaded regions have resident compaction state, including
Idleand handed-off DDLs. Publish create/open/catchup results through the worker'sregister_region; only close/drop unregisters them. Seecompaction/scheduler/state.rs.
Maintenance contract
Update this file when you add/rename a top-level module, change the write/read path entry points, or alter a persisted format (manifest, SST, WAL).