Skip to main content

omnigraph/
failpoints.rs

1use crate::error::Result;
2
3pub(crate) fn maybe_fail(_name: &str) -> Result<()> {
4    #[cfg(feature = "failpoints")]
5    {
6        let name = _name;
7        fail::fail_point!(name, |_| {
8            return Err(crate::error::OmniError::manifest(format!(
9                "injected failpoint triggered: {}",
10                name
11            )));
12        });
13    }
14    Ok(())
15}
16
17/// Compile-checked catalog of every failpoint name in this crate. Call sites
18/// (`maybe_fail`) and tests (`ScopedFailPoint` / the test rendezvous helper)
19/// reference these constants instead of bare string literals, so a typo is a
20/// compile error rather than a silently-never-firing failpoint.
21pub mod names {
22    pub const BRANCH_CREATE_AFTER_MANIFEST_BRANCH_CREATE: &str = "branch_create.after_manifest_branch_create";
23    pub const BRANCH_DELETE_BEFORE_COMMIT_GRAPH_RECLAIM: &str = "branch_delete.before_commit_graph_reclaim";
24    pub const BRANCH_DELETE_BEFORE_TABLE_CLEANUP: &str = "branch_delete.before_table_cleanup";
25    pub const BRANCH_MERGE_ADOPT_AFTER_APPEND_PRE_UPSERT: &str = "branch_merge.adopt_after_append_pre_upsert";
26    pub const BRANCH_MERGE_ADOPT_AFTER_UPSERT_PRE_DELETE: &str = "branch_merge.adopt_after_upsert_pre_delete";
27    pub const BRANCH_MERGE_POST_PHASE_B_PRE_MANIFEST_COMMIT: &str = "branch_merge.post_phase_b_pre_manifest_commit";
28    pub const BRANCH_MERGE_REWRITE_AFTER_DELETE_PRE_INDEX: &str = "branch_merge.rewrite_after_delete_pre_index";
29    pub const BRANCH_MERGE_REWRITE_AFTER_MERGE_PRE_DELETE: &str = "branch_merge.rewrite_after_merge_pre_delete";
30    pub const CLASSIFY_FRESH_READ: &str = "classify.fresh_read";
31    pub const CLEANUP_RECONCILE_FORK: &str = "cleanup.reconcile_fork";
32    pub const CLEANUP_RESOLVE_BRANCH_SNAPSHOT: &str = "cleanup.resolve_branch_snapshot";
33    pub const CLEANUP_TABLE_GC: &str = "cleanup.table_gc";
34    pub const ENSURE_INDICES_POST_PHASE_B_PRE_MANIFEST_COMMIT: &str = "ensure_indices.post_phase_b_pre_manifest_commit";
35    pub const ENSURE_INDICES_POST_STAGE_PRE_COMMIT_BTREE: &str = "ensure_indices.post_stage_pre_commit_btree";
36    pub const FORK_BEFORE_CLASSIFY: &str = "fork.before_classify";
37    pub const FORK_BEFORE_RECLAIM: &str = "fork.before_reclaim";
38    pub const GRAPH_PUBLISH_AFTER_MANIFEST_COMMIT: &str = "graph_publish.after_manifest_commit";
39    pub const GRAPH_PUBLISH_BEFORE_COMMIT_APPEND: &str = "graph_publish.before_commit_append";
40    pub const INIT_AFTER_COORDINATOR_INIT: &str = "init.after_coordinator_init";
41    pub const INIT_AFTER_SCHEMA_CONTRACT_WRITTEN: &str = "init.after_schema_contract_written";
42    pub const INIT_AFTER_SCHEMA_PG_WRITTEN: &str = "init.after_schema_pg_written";
43    pub const MUTATION_DELETE_NODE_PRE_PRIMARY_DELETE: &str = "mutation.delete_node_pre_primary_delete";
44    pub const MUTATION_POST_FINALIZE_PRE_PUBLISHER: &str = "mutation.post_finalize_pre_publisher";
45    pub const OPTIMIZE_BEFORE_COMPACT: &str = "optimize.before_compact";
46    pub const OPTIMIZE_INJECT_REINDEX_CONFLICT: &str = "optimize.inject_reindex_conflict";
47    pub const OPTIMIZE_POST_PHASE_B_PRE_MANIFEST_COMMIT: &str = "optimize.post_phase_b_pre_manifest_commit";
48    pub const RECOVERY_BEFORE_ROLL_FORWARD_PUBLISH: &str = "recovery.before_roll_forward_publish";
49    pub const RECOVERY_ORPHAN_DISCARD_AUDIT_APPEND: &str = "recovery.orphan_discard_audit_append";
50    pub const RECOVERY_RECORD_AUDIT: &str = "recovery.record_audit";
51    pub const RECOVERY_SIDECAR_CONFIRM: &str = "recovery.sidecar_confirm";
52    pub const RECOVERY_SIDECAR_DELETE: &str = "recovery.sidecar_delete";
53    pub const RECOVERY_SIDECAR_LIST: &str = "recovery.sidecar_list";
54    pub const RECOVERY_SIDECAR_WRITE: &str = "recovery.sidecar_write";
55    pub const SCHEMA_APPLY_AFTER_MANIFEST_COMMIT: &str = "schema_apply.after_manifest_commit";
56    pub const SCHEMA_APPLY_AFTER_STAGING_WRITE: &str = "schema_apply.after_staging_write";
57    pub const SCHEMA_APPLY_BEFORE_STAGING_WRITE: &str = "schema_apply.before_staging_write";
58}
59
60#[cfg(feature = "failpoints")]
61pub struct ScopedFailPoint {
62    name: String,
63}
64
65#[cfg(feature = "failpoints")]
66impl ScopedFailPoint {
67    pub fn new(name: &str, action: &str) -> Self {
68        fail::cfg(name, action).expect("configure failpoint");
69        Self {
70            name: name.to_string(),
71        }
72    }
73
74    /// Register a callback failpoint with the same Drop-based cleanup as
75    /// `new`. Without the guard, a panic while the point is active would
76    /// leak the callback into the process-global registry and fire it under
77    /// later tests in the same binary.
78    pub fn with_callback<F>(name: &str, callback: F) -> Self
79    where
80        F: Fn() + Send + Sync + 'static,
81    {
82        fail::cfg_callback(name, callback).expect("configure callback failpoint");
83        Self {
84            name: name.to_string(),
85        }
86    }
87}
88
89#[cfg(feature = "failpoints")]
90impl Drop for ScopedFailPoint {
91    fn drop(&mut self) {
92        fail::remove(&self.name);
93    }
94}