pub trait RegionHook:
Send
+ Sync
+ Debug {
// Provided methods
fn on_sst_files_written<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
region_id: RegionId,
region_metadata: &'life1 RegionMetadataRef,
files: &'life2 [SstFileInfo<'life3>],
) -> Pin<Box<dyn Future<Output = ()> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait { ... }
fn on_manifest_updated<'life0, 'life1, 'async_trait>(
&'life0 self,
region_id: RegionId,
action_list: &'life1 RegionMetaActionList,
manifest_version: ManifestVersion,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait { ... }
fn on_region_opened<'life0, 'life1, 'async_trait>(
&'life0 self,
region_id: RegionId,
region_metadata: &'life1 RegionMetadataRef,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait { ... }
fn on_region_closed<'life0, 'life1, 'async_trait>(
&'life0 self,
region_id: RegionId,
region_metadata: &'life1 RegionMetadataRef,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait { ... }
fn on_region_dropped<'life0, 'life1, 'async_trait>(
&'life0 self,
region_id: RegionId,
region_metadata: &'life1 RegionMetadataRef,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait { ... }
fn on_region_files_removed<'life0, 'life1, 'async_trait>(
&'life0 self,
region_id: RegionId,
region_metadata: &'life1 RegionMetadataRef,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait { ... }
fn on_region_gc<'life0, 'life1, 'life2, 'life3, 'life4, 'async_trait>(
&'life0 self,
region_id: RegionId,
region_metadata: Option<&'life1 RegionMetadataRef>,
access_layer: &'life2 AccessLayerRef,
info: &'life3 RegionGcInfo<'life4>,
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
'life4: 'async_trait { ... }
}Expand description
Hook for observing region mutations in mito2.
Implementations can be registered via the Plugins system:
use std::sync::Arc;
use common_base::Plugins;
use mito2::engine::region_hook::{RegionHook, RegionHookRef};
plugins.insert(Arc::new(MyHook) as RegionHookRef);Provided Methods§
Sourcefn on_sst_files_written<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
region_id: RegionId,
region_metadata: &'life1 RegionMetadataRef,
files: &'life2 [SstFileInfo<'life3>],
) -> Pin<Box<dyn Future<Output = ()> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
fn on_sst_files_written<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
region_id: RegionId,
region_metadata: &'life1 RegionMetadataRef,
files: &'life2 [SstFileInfo<'life3>],
) -> Pin<Box<dyn Future<Output = ()> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
Called after SST data files are physically written, before manifest commit.
This fires only when mito2 itself writes SST files (flush and compaction). It does not fire when SST files are pre-written externally (bulk ingestion, copy region) or when only index files are written (async index build).
§Metadata availability
See SstFileInfo: file_meta is always complete, but the SstInfo footer
and index output are empty on remote compaction. Hooks needing column statistics
(e.g. an Iceberg manifest) must fetch the footer from object storage.
Sourcefn on_manifest_updated<'life0, 'life1, 'async_trait>(
&'life0 self,
region_id: RegionId,
action_list: &'life1 RegionMetaActionList,
manifest_version: ManifestVersion,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn on_manifest_updated<'life0, 'life1, 'async_trait>(
&'life0 self,
region_id: RegionId,
action_list: &'life1 RegionMetaActionList,
manifest_version: ManifestVersion,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Called after the region manifest is successfully committed to the live (normal) manifest directory.
Fires for: flush, compaction, region edit, copy region, alter, truncate, async index build, and apply-staging promote. Does not fire for writes to the staging manifest directory (enter staging, operations during staging, the intermediate apply-staging edit) — those are suppressed because their effects are accumulated and delivered in a single promote notification.
Does not fire for:
- Manifest reads / follower sync (no write)
- GC / checkpoint (internal bookkeeping)
- Failed manifest updates
Sourcefn on_region_opened<'life0, 'life1, 'async_trait>(
&'life0 self,
region_id: RegionId,
region_metadata: &'life1 RegionMetadataRef,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn on_region_opened<'life0, 'life1, 'async_trait>(
&'life0 self,
region_id: RegionId,
region_metadata: &'life1 RegionMetadataRef,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Called once a region open or create succeeds, but before the
region is registered in the engine’s active set (insert_region runs
immediately afterwards).
Fires once when a region becomes active via a create or open request —
the natural counterpart to on_region_closed / on_region_dropped.
It does not fire for the compactor’s transient compaction regions
(open_compaction_region), nor for the internal reopen performed during
follower catch-up / leadership promotion.
On the create path it runs inline in the region worker loop; on the
open path it runs inside the spawned open task
(common_runtime::spawn_global), concurrently with the worker loop
(after WAL replay, before the region is registered/acknowledged).
Implementations must be fast and must not assume worker-loop-thread
affinity or strict ordering against concurrent requests to other regions.
Sourcefn on_region_closed<'life0, 'life1, 'async_trait>(
&'life0 self,
region_id: RegionId,
region_metadata: &'life1 RegionMetadataRef,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn on_region_closed<'life0, 'life1, 'async_trait>(
&'life0 self,
region_id: RegionId,
region_metadata: &'life1 RegionMetadataRef,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Called after a region is closed via a close request.
The region is removed from the engine’s active set, but its data files, manifest, and WAL state are preserved; the region may be reopened later. Fires once per successful close, after the region’s background tasks (flush/compaction) have been stopped.
Fires for a region of any role (leader or follower) that is closed.
Does not fire when a region is dropped (see on_region_dropped).
Runs inline in the region worker loop; implementations should be fast.
Sourcefn on_region_dropped<'life0, 'life1, 'async_trait>(
&'life0 self,
region_id: RegionId,
region_metadata: &'life1 RegionMetadataRef,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn on_region_dropped<'life0, 'life1, 'async_trait>(
&'life0 self,
region_id: RegionId,
region_metadata: &'life1 RegionMetadataRef,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Called after a region is logically dropped (a drop request has been handled).
The region is removed from the active set and its WAL entries are marked
obsolete. Its data files are not yet deleted — they are scheduled for
asynchronous removal by the GC worker. Observe physical deletion via
on_region_files_removed.
Runs inline in the region worker loop; implementations should be fast.
Sourcefn on_region_files_removed<'life0, 'life1, 'async_trait>(
&'life0 self,
region_id: RegionId,
region_metadata: &'life1 RegionMetadataRef,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn on_region_files_removed<'life0, 'life1, 'async_trait>(
&'life0 self,
region_id: RegionId,
region_metadata: &'life1 RegionMetadataRef,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Called after a dropped region’s data files are physically removed by the drop GC worker (the region directory has been deleted).
This is the terminal event in a region’s file lifecycle; no further
callbacks fire for this region id afterwards. Fires only when the drop
worker itself deletes the directory. When global GC is enabled and the
region is a normal table region dropped with partial_drop, the
directory is left for global reclamation and this hook is not fired
by the drop worker.
Runs on a background task, outside the region worker loop.
Sourcefn on_region_gc<'life0, 'life1, 'life2, 'life3, 'life4, 'async_trait>(
&'life0 self,
region_id: RegionId,
region_metadata: Option<&'life1 RegionMetadataRef>,
access_layer: &'life2 AccessLayerRef,
info: &'life3 RegionGcInfo<'life4>,
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
'life4: 'async_trait,
fn on_region_gc<'life0, 'life1, 'life2, 'life3, 'life4, 'async_trait>(
&'life0 self,
region_id: RegionId,
region_metadata: Option<&'life1 RegionMetadataRef>,
access_layer: &'life2 AccessLayerRef,
info: &'life3 RegionGcInfo<'life4>,
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
'life4: 'async_trait,
Called after the datanode’s global GC worker (LocalGcWorker) finishes a
GC pass for a region — live regions (periodic GC) or dropped/repartitioned
regions (the global reclamation path). Also fired by the offline cleanup
path (handle_offline_cleanup_request, i.e. soft-drop PURGE) once the
region directory has been removed. Lets extensions with sidecar files
outside mito2’s region dir clean up residual files.
Always scoped to RegionGcInfo::removed_files: clean only sidecar
artifacts for the files mito deleted this pass. On a
RegionGcInfo::full_file_listing pass you may also reconcile
sidecar-only orphans (e.g. detect a fully-reaped region by cross-checking
the region dir against your own manifest). This callback never authorizes
blind whole-directory removal — derive “fully reaped” from your own state
so a stale mito snapshot can’t cause accidental deletion.
RegionGcInfo::is_region_dropped is context, not authorization.
§Retry
Returning Err keeps the region un-acknowledged (need_retry_regions)
for a future replay. Dropped/repartitioned: guaranteed — metasrv keeps
the table_repart tombstone until Ok, so full-listing passes continue
until cleanup finishes. Live: best-effort — not expedited through
candidate selection, and a later full-listing pass may not reconstruct the
same removed_files; treat live cleanup as opportunistic.
region_metadata is None for dropped regions; use region_id +
access_layer. Idempotent.
§Execution context
On the global-GC path this runs on the background GC task, outside the
region worker loop. The offline cleanup path
(handle_offline_cleanup_request, reached by soft-drop PURGE) instead
runs it inline in the region worker loop and propagates Err so the
caller retries the (idempotent) cleanup. So — like on_region_closed /
on_region_dropped — implementations must be fast and must not block
indefinitely while awaited there: while the callback is pending, every
subsequent DDL request for every region on that worker is blocked.
Extension authors who wrote their hook against the “background GC task”
contract must account for this second, latency-sensitive trigger.
The offline cleanup path fires this callback once the region directory is
confirmed absent — including no-op purges where nothing was actually
removed this call (a retry after the directory was already gone, or a
region that never had files on this datanode, since
remove_region_dir_for_full_drop returns Ok for an absent/empty
prefix). RegionGcInfo::removed_files is empty in that case; do not
interpret the call as “files were deleted in this call”. This is
asymmetric with the GC path, which fires only when files were deleted or
a full listing was performed.