@@ -5,7 +5,19 @@ use crate::{
5
5
fatal,
6
6
} ;
7
7
8
+ #[ derive( PartialEq ) ]
9
+ pub enum SnapshotDeducedType {
10
+ Uncertain ,
11
+ Regular ,
12
+ Fap ,
13
+ }
14
+
8
15
impl < T : Transport + ' static , ER : RaftEngine > ProxyForwarder < T , ER > {
16
+ pub fn deduce_snapshot_type ( _peer_id : u64 , _snap : & store:: Snapshot ) -> SnapshotDeducedType {
17
+ // TODO(fap) implement in seperated modes(serverless or op).
18
+ SnapshotDeducedType :: Uncertain
19
+ }
20
+
9
21
pub fn pre_apply_snapshot_for_fap_snapshot (
10
22
& self ,
11
23
ob_region : & Region ,
@@ -21,7 +33,7 @@ impl<T: Transport + 'static, ER: RaftEngine> ProxyForwarder<T, ER> {
21
33
|info : MapEntry < u64 , Arc < CachedRegionInfo > > | match info {
22
34
MapEntry :: Occupied ( _) => {
23
35
if !self . engine_store_server_helper . kvstore_region_exist ( region_id) {
24
- if self . engine_store_server_helper . query_fap_snapshot_state ( region_id, peer_id) == proxy_ffi:: interfaces_ffi:: FapSnapshotState :: Persisted {
36
+ if self . engine_store_server_helper . query_fap_snapshot_state ( region_id, peer_id, snap_key . idx , snap_key . term ) == proxy_ffi:: interfaces_ffi:: FapSnapshotState :: Persisted {
25
37
info ! ( "fast path: prehandle first snapshot skipped {}:{} {}" , self . store_id, region_id, peer_id;
26
38
"snap_key" => ?snap_key,
27
39
"region_id" => region_id,
@@ -32,7 +44,7 @@ impl<T: Transport + 'static, ER: RaftEngine> ProxyForwarder<T, ER> {
32
44
}
33
45
MapEntry :: Vacant ( _) => {
34
46
// It won't go here because cached region info is inited after restart and on the first fap message.
35
- let pstate = self . engine_store_server_helper . query_fap_snapshot_state ( region_id, peer_id) ;
47
+ let pstate = self . engine_store_server_helper . query_fap_snapshot_state ( region_id, peer_id, snap_key . idx , snap_key . term ) ;
36
48
if pstate == proxy_ffi:: interfaces_ffi:: FapSnapshotState :: Persisted {
37
49
// We have a fap snapshot now. skip
38
50
info ! ( "fast path: prehandle first snapshot skipped after restart {}:{} {}" , self . store_id, region_id, peer_id;
@@ -63,10 +75,21 @@ impl<T: Transport + 'static, ER: RaftEngine> ProxyForwarder<T, ER> {
63
75
ob_region : & Region ,
64
76
peer_id : u64 ,
65
77
snap_key : & store:: SnapKey ,
78
+ maybe_snap : Option < & store:: Snapshot > ,
66
79
) -> bool {
67
80
let region_id = ob_region. get_id ( ) ;
68
- let try_apply_fap_snapshot = |c : Arc < CachedRegionInfo > , restarted : bool | {
69
- info ! ( "fast path: start applying first snapshot {}:{} {}" , self . store_id, region_id, peer_id;
81
+ let try_apply_fap_snapshot = |c : Arc < CachedRegionInfo > | {
82
+ let already_existed = self
83
+ . engine_store_server_helper
84
+ . kvstore_region_exist ( region_id) ;
85
+ if already_existed {
86
+ debug ! ( "fast path: skip apply snapshot because not first {}:{} {}" , self . store_id, region_id, peer_id;
87
+ "snap_key" => ?snap_key,
88
+ "region_id" => region_id,
89
+ ) ;
90
+ return false ;
91
+ }
92
+ info ! ( "fast path: start applying first fap snapshot {}:{} {}" , self . store_id, region_id, peer_id;
70
93
"snap_key" => ?snap_key,
71
94
"region_id" => region_id,
72
95
) ;
@@ -80,36 +103,78 @@ impl<T: Transport + 'static, ER: RaftEngine> ProxyForwarder<T, ER> {
80
103
. duration_since ( SystemTime :: UNIX_EPOCH )
81
104
. unwrap ( ) ;
82
105
83
- let assert_exist = if !restarted {
84
- snapshot_sent_time != 0
85
- } else {
86
- false
106
+ let snap = match maybe_snap {
107
+ Some ( s) => s,
108
+ None => {
109
+ return false ;
110
+ }
87
111
} ;
88
- if !self
89
- . engine_store_server_helper
90
- . apply_fap_snapshot ( region_id, peer_id, assert_exist)
91
- {
92
- // This is not a fap snapshot.
93
- info ! ( "fast path: this is not fap snapshot {}:{} {}, goto tikv snapshot" , self . store_id, region_id, peer_id;
112
+
113
+ // We can't rely on `snapshot_inflight`, because it will be undetermined ZERO
114
+ // after restart.
115
+ let expected_snapshot_type = Self :: deduce_snapshot_type ( peer_id, snap) ;
116
+
117
+ let quit_apply_fap = |tag : & str | {
118
+ info ! ( "fast path: fap snapshot mismatch/nonexist {}:{} {}" , self . store_id, region_id, peer_id;
94
119
"snap_key" => ?snap_key,
95
120
"region_id" => region_id,
96
121
"cost_snapshot" => current. as_millis( ) - snapshot_sent_time,
97
122
"cost_total" => current. as_millis( ) - fap_start_time,
98
123
"current_enabled" => current_enabled,
99
- "from_restart " => restarted ,
124
+ "tag " => tag
100
125
) ;
126
+ if expected_snapshot_type == SnapshotDeducedType :: Fap {
127
+ // It won't actually happen because TiFlash will panic since `assert_exist` is
128
+ // true in this case.
129
+ fatal ! (
130
+ "fast path: fap snapshot apply failed {}:{} {}, which is assert to be fap snapshot" ,
131
+ self . store_id,
132
+ region_id,
133
+ peer_id
134
+ ) ;
135
+ }
101
136
c. snapshot_inflight . store ( 0 , Ordering :: SeqCst ) ;
102
137
c. fast_add_peer_start . store ( 0 , Ordering :: SeqCst ) ;
103
138
c. inited_or_fallback . store ( true , Ordering :: SeqCst ) ;
104
- return false ;
139
+ false
140
+ } ;
141
+
142
+ // If there is no fap snapshot with given (index, term) we shall quit.
143
+ if self . engine_store_server_helper . query_fap_snapshot_state (
144
+ region_id,
145
+ peer_id,
146
+ snap_key. idx ,
147
+ snap_key. term ,
148
+ ) != proxy_ffi:: interfaces_ffi:: FapSnapshotState :: Persisted
149
+ {
150
+ return quit_apply_fap ( "pre check" ) ;
105
151
}
106
- info ! ( "fast path: finished applied first snapshot {}:{} {}, recover MsgAppend" , self . store_id, region_id, peer_id;
152
+
153
+ // Only succeeds if (index, term) matches.
154
+ // Returns false if `assert_exist` is false,
155
+ // Panics if `assert_exist` is true.
156
+ // The logic is kind of redundant, but we want to make it complete on both
157
+ // sides.
158
+ if !self . engine_store_server_helper . apply_fap_snapshot (
159
+ region_id,
160
+ peer_id,
161
+ true ,
162
+ snap_key. idx ,
163
+ snap_key. term ,
164
+ ) {
165
+ return quit_apply_fap ( "apply" ) ;
166
+ }
167
+ // If it's a reguar snapshot have the same (index, term) as the fap snapshot,
168
+ // it make no difference which snapshot we actually applied.
169
+ // So we always choose to apply a fap snapshot, since it saves as from
170
+ // prehandling work.
171
+ info ! ( "fast path: finished applied first fap snapshot {}:{} {}, recover MsgAppend" , self . store_id, region_id, peer_id;
107
172
"snap_key" => ?snap_key,
108
173
"region_id" => region_id,
109
174
"cost_snapshot" => current. as_millis( ) - snapshot_sent_time,
110
175
"cost_total" => current. as_millis( ) - fap_start_time,
111
176
"current_enabled" => current_enabled,
112
- "from_restart " => restarted ,
177
+ "replacement_of_regular " => expected_snapshot_type == SnapshotDeducedType :: Regular
113
178
) ;
114
179
c. snapshot_inflight . store ( 0 , Ordering :: SeqCst ) ;
115
180
c. fast_add_peer_start . store ( 0 , Ordering :: SeqCst ) ;
@@ -132,26 +197,13 @@ impl<T: Transport + 'static, ER: RaftEngine> ProxyForwarder<T, ER> {
132
197
let mut applied_fap = false ;
133
198
#[ allow( clippy:: collapsible_if) ]
134
199
if should_check_fap_snapshot {
135
- let mut maybe_cached_info: Option < Arc < CachedRegionInfo > > = None ;
136
200
if self
137
201
. get_cached_manager ( )
138
202
. access_cached_region_info_mut (
139
203
region_id,
140
204
|info : MapEntry < u64 , Arc < CachedRegionInfo > > | match info {
141
205
MapEntry :: Occupied ( o) => {
142
- maybe_cached_info = Some ( o. get ( ) . clone ( ) ) ;
143
- let already_existed = self . engine_store_server_helper . kvstore_region_exist ( region_id) ;
144
- debug ! ( "fast path: check should apply fap snapshot {}:{} {}" , self . store_id, region_id, peer_id;
145
- "snap_key" => ?snap_key,
146
- "region_id" => region_id,
147
- "inited_or_fallback" => o. get( ) . inited_or_fallback. load( Ordering :: SeqCst ) ,
148
- "snapshot_inflight" => o. get( ) . snapshot_inflight. load( Ordering :: SeqCst ) ,
149
- "already_existed" => already_existed,
150
- ) ;
151
- if !already_existed {
152
- // May be a fap snapshot, try to apply.
153
- applied_fap = try_apply_fap_snapshot ( o. get ( ) . clone ( ) , false ) ;
154
- }
206
+ applied_fap = try_apply_fap_snapshot ( o. get ( ) . clone ( ) ) ;
155
207
}
156
208
MapEntry :: Vacant ( _) => {
157
209
// It won't go here because cached region info is inited after restart and on the first fap message.
@@ -161,7 +213,7 @@ impl<T: Transport + 'static, ER: RaftEngine> ProxyForwarder<T, ER> {
161
213
) ;
162
214
assert ! ( self . is_initialized( region_id) ) ;
163
215
let o = Arc :: new ( CachedRegionInfo :: default ( ) ) ;
164
- applied_fap = try_apply_fap_snapshot ( o, true ) ;
216
+ applied_fap = try_apply_fap_snapshot ( o) ;
165
217
}
166
218
} ,
167
219
)
0 commit comments