flow/batching_mode/checkpoint.rs
1// Copyright 2023 Greptime Team
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use crate::batching_mode::state::CheckpointMode;
16
17pub(super) const CHECKPOINT_DECISION_ADVANCE: &str = "advance";
18pub(super) const CHECKPOINT_DECISION_FALLBACK: &str = "fallback";
19pub(super) const CHECKPOINT_REASON_NONE: &str = "none";
20
21/// Why the task fell back to full snapshot mode.
22#[derive(Debug, Clone, Copy, PartialEq, Eq)]
23pub(super) enum FlowQueryFallbackReason {
24 /// The query result did not include a region-watermark map at all.
25 MissingRegionWatermark,
26 /// Some participating regions could not prove safe advancement against
27 /// both the returned watermarks and the checkpoint map.
28 IncompleteRegionWatermark,
29 /// The query only covered part of the dirty backlog, so global checkpoints
30 /// cannot advance yet. Incremental SQL drains all dirty windows before
31 /// checkpoint advancement; this primarily protects scoped full-snapshot
32 /// runs capped by the per-query dirty-window limit.
33 DirtyBacklogPending,
34 /// The datanode detected a stale incremental cursor and the Flow
35 /// must recompute from scratch.
36 StaleCursor,
37 /// A non-stale-cursor query failure; the Flow resets to full snapshot
38 /// to avoid cascading errors.
39 IncrementalQueryFailure,
40 /// Incremental mode has been permanently disabled for this Flow
41 /// (e.g. because the query shape is not incrementally safe).
42 IncrementalDisabled,
43}
44
45impl FlowQueryFallbackReason {
46 pub(super) fn as_label(self) -> &'static str {
47 match self {
48 Self::MissingRegionWatermark => "missing_region_watermark",
49 Self::IncompleteRegionWatermark => "incomplete_region_watermark",
50 Self::DirtyBacklogPending => "dirty_backlog_pending",
51 Self::StaleCursor => "stale_cursor",
52 Self::IncrementalQueryFailure => "incremental_query_failure",
53 Self::IncrementalDisabled => "incremental_disabled",
54 }
55 }
56}
57
58/// Decision produced by `BatchingTask::apply_query_result_to_state` after
59/// each Flow query execution. Describes whether the task advanced its
60/// checkpoint state or fell back to full snapshot, and why.
61#[derive(Debug, Clone, Copy, PartialEq, Eq)]
62pub(super) enum FlowCheckpointDecision {
63 /// FullSnapshot → Incremental transition.
64 ///
65 /// The query exercised every participating region, all returned valid
66 /// watermarks, and the checkpoint map was populated from scratch.
67 /// Subsequent executions will use incremental after-seqs.
68 AdvancedFromFullSnapshot {
69 participating_regions: usize,
70 watermarks: usize,
71 },
72 /// Existing Incremental → Incremental (in-place advancement).
73 ///
74 /// A subset of participating regions advanced their watermarks. The
75 /// task stays in incremental mode with an updated checkpoint map.
76 AdvancedIncremental {
77 participating_regions: usize,
78 watermarks: usize,
79 },
80 /// Any mode → FullSnapshot.
81 ///
82 /// Watermark information was incomplete, a participating region was
83 /// absent from the existing checkpoint map, the task has permanently
84 /// disabled incremental mode, or the query itself failed. The task
85 /// resets to full snapshot semantics for the next execution.
86 FallbackToFullSnapshot {
87 previous_mode: CheckpointMode,
88 reason: FlowQueryFallbackReason,
89 },
90}
91
92impl FlowCheckpointDecision {
93 pub(super) fn mode_label(self) -> &'static str {
94 match self {
95 Self::AdvancedFromFullSnapshot { .. } => {
96 checkpoint_mode_label(CheckpointMode::FullSnapshot)
97 }
98 Self::AdvancedIncremental { .. } => checkpoint_mode_label(CheckpointMode::Incremental),
99 Self::FallbackToFullSnapshot { previous_mode, .. } => {
100 checkpoint_mode_label(previous_mode)
101 }
102 }
103 }
104
105 pub(super) fn decision_label(self) -> &'static str {
106 match self {
107 Self::AdvancedFromFullSnapshot { .. } | Self::AdvancedIncremental { .. } => {
108 CHECKPOINT_DECISION_ADVANCE
109 }
110 Self::FallbackToFullSnapshot { .. } => CHECKPOINT_DECISION_FALLBACK,
111 }
112 }
113
114 pub(super) fn reason_label(self) -> &'static str {
115 match self {
116 Self::FallbackToFullSnapshot { reason, .. } => reason.as_label(),
117 _ => CHECKPOINT_REASON_NONE,
118 }
119 }
120}
121
122pub(super) fn checkpoint_mode_label(mode: CheckpointMode) -> &'static str {
123 match mode {
124 CheckpointMode::FullSnapshot => "full_snapshot",
125 CheckpointMode::Incremental => "incremental",
126 }
127}