@@ -4,10 +4,10 @@ use std::pin::Pin;
4
4
use std:: sync:: atomic:: { AtomicBool , AtomicU32 , Ordering } ;
5
5
use std:: sync:: Arc ;
6
6
use std:: task:: { Context , Poll } ;
7
+ use std:: time:: Duration ;
7
8
use tempfile:: tempdir;
8
9
use tokio:: io:: { duplex, AsyncRead , AsyncWrite , DuplexStream } ;
9
10
use tower:: Service ;
10
- use std:: time:: Duration ;
11
11
12
12
#[ tokio:: test]
13
13
async fn test_sync_context_push_frame ( ) {
@@ -30,10 +30,10 @@ async fn test_sync_context_push_frame() {
30
30
// Push a frame and verify the response
31
31
let durable_frame = sync_ctx. push_one_frame ( frame, 1 , 0 ) . await . unwrap ( ) ;
32
32
sync_ctx. write_metadata ( ) . await . unwrap ( ) ;
33
- assert_eq ! ( durable_frame, 1 ) ; // First frame should return max_frame_no = 1
33
+ assert_eq ! ( durable_frame, 0 ) ; // First frame should return max_frame_no = 0
34
34
35
35
// Verify internal state was updated
36
- assert_eq ! ( sync_ctx. durable_frame_num( ) , 1 ) ;
36
+ assert_eq ! ( sync_ctx. durable_frame_num( ) , 0 ) ;
37
37
assert_eq ! ( sync_ctx. generation( ) , 1 ) ;
38
38
assert_eq ! ( server. frame_count( ) , 1 ) ;
39
39
}
@@ -58,7 +58,7 @@ async fn test_sync_context_with_auth() {
58
58
59
59
let durable_frame = sync_ctx. push_one_frame ( frame, 1 , 0 ) . await . unwrap ( ) ;
60
60
sync_ctx. write_metadata ( ) . await . unwrap ( ) ;
61
- assert_eq ! ( durable_frame, 1 ) ;
61
+ assert_eq ! ( durable_frame, 0 ) ;
62
62
assert_eq ! ( server. frame_count( ) , 1 ) ;
63
63
}
64
64
@@ -84,8 +84,8 @@ async fn test_sync_context_multiple_frames() {
84
84
let frame = Bytes :: from ( format ! ( "frame data {}" , i) ) ;
85
85
let durable_frame = sync_ctx. push_one_frame ( frame, 1 , i) . await . unwrap ( ) ;
86
86
sync_ctx. write_metadata ( ) . await . unwrap ( ) ;
87
- assert_eq ! ( durable_frame, i + 1 ) ;
88
- assert_eq ! ( sync_ctx. durable_frame_num( ) , i + 1 ) ;
87
+ assert_eq ! ( durable_frame, i) ;
88
+ assert_eq ! ( sync_ctx. durable_frame_num( ) , i) ;
89
89
assert_eq ! ( server. frame_count( ) , i + 1 ) ;
90
90
}
91
91
}
@@ -110,7 +110,7 @@ async fn test_sync_context_corrupted_metadata() {
110
110
let frame = Bytes :: from ( "test frame data" ) ;
111
111
let durable_frame = sync_ctx. push_one_frame ( frame, 1 , 0 ) . await . unwrap ( ) ;
112
112
sync_ctx. write_metadata ( ) . await . unwrap ( ) ;
113
- assert_eq ! ( durable_frame, 1 ) ;
113
+ assert_eq ! ( durable_frame, 0 ) ;
114
114
assert_eq ! ( server. frame_count( ) , 1 ) ;
115
115
116
116
// Update metadata path to use -info instead of .meta
@@ -132,11 +132,69 @@ async fn test_sync_context_corrupted_metadata() {
132
132
assert_eq ! ( sync_ctx. generation( ) , 1 ) ;
133
133
}
134
134
135
+ #[ tokio:: test]
136
+ async fn test_sync_restarts_with_lower_max_frame_no ( ) {
137
+ let _ = tracing_subscriber:: fmt:: try_init ( ) ;
138
+
139
+ let server = MockServer :: start ( ) ;
140
+ let temp_dir = tempdir ( ) . unwrap ( ) ;
141
+ let db_path = temp_dir. path ( ) . join ( "test.db" ) ;
142
+
143
+ // Create initial sync context and push a frame
144
+ let sync_ctx = SyncContext :: new (
145
+ server. connector ( ) ,
146
+ db_path. to_str ( ) . unwrap ( ) . to_string ( ) ,
147
+ server. url ( ) ,
148
+ None ,
149
+ )
150
+ . await
151
+ . unwrap ( ) ;
152
+
153
+ let mut sync_ctx = sync_ctx;
154
+ let frame = Bytes :: from ( "test frame data" ) ;
155
+ let durable_frame = sync_ctx. push_one_frame ( frame. clone ( ) , 1 , 0 ) . await . unwrap ( ) ;
156
+ sync_ctx. write_metadata ( ) . await . unwrap ( ) ;
157
+ assert_eq ! ( durable_frame, 0 ) ;
158
+ assert_eq ! ( server. frame_count( ) , 1 ) ;
159
+
160
+ // Bump the durable frame num so that the next time we call the
161
+ // server we think we are further ahead than the database we are talking to is.
162
+ sync_ctx. durable_frame_num += 3 ;
163
+ sync_ctx. write_metadata ( ) . await . unwrap ( ) ;
164
+
165
+ // Create new sync context with corrupted metadata
166
+ let mut sync_ctx = SyncContext :: new (
167
+ server. connector ( ) ,
168
+ db_path. to_str ( ) . unwrap ( ) . to_string ( ) ,
169
+ server. url ( ) ,
170
+ None ,
171
+ )
172
+ . await
173
+ . unwrap ( ) ;
174
+
175
+ // Verify that the context was set to new fake values.
176
+ assert_eq ! ( sync_ctx. durable_frame_num( ) , 3 ) ;
177
+ assert_eq ! ( sync_ctx. generation( ) , 1 ) ;
178
+
179
+ let frame_no = sync_ctx. durable_frame_num ( ) + 1 ;
180
+ // This push should fail because we are ahead of the server and thus should get an invalid
181
+ // frame no error.
182
+ sync_ctx
183
+ . push_one_frame ( frame. clone ( ) , 1 , frame_no)
184
+ . await
185
+ . unwrap_err ( ) ;
186
+
187
+ let frame_no = sync_ctx. durable_frame_num ( ) + 1 ;
188
+ // This then should work because when the last one failed it updated our state of the server
189
+ // durable_frame_num and we should then start writing from there.
190
+ sync_ctx. push_one_frame ( frame, 1 , frame_no) . await . unwrap ( ) ;
191
+ }
192
+
135
193
#[ tokio:: test]
136
194
async fn test_sync_context_retry_on_error ( ) {
137
195
// Pause time to control it manually
138
196
tokio:: time:: pause ( ) ;
139
-
197
+
140
198
let server = MockServer :: start ( ) ;
141
199
let temp_dir = tempdir ( ) . unwrap ( ) ;
142
200
let db_path = temp_dir. path ( ) . join ( "test.db" ) ;
@@ -172,7 +230,7 @@ async fn test_sync_context_retry_on_error() {
172
230
// Next attempt should succeed
173
231
let durable_frame = sync_ctx. push_one_frame ( frame, 1 , 0 ) . await . unwrap ( ) ;
174
232
sync_ctx. write_metadata ( ) . await . unwrap ( ) ;
175
- assert_eq ! ( durable_frame, 1 ) ;
233
+ assert_eq ! ( durable_frame, 0 ) ;
176
234
assert_eq ! ( server. frame_count( ) , 1 ) ;
177
235
}
178
236
@@ -316,8 +374,9 @@ impl MockServer {
316
374
let current_count = frame_count. fetch_add ( 1 , Ordering :: SeqCst ) ;
317
375
318
376
if req. uri ( ) . path ( ) . contains ( "/sync/" ) {
377
+ // Return the max_frame_no that has been accepted
319
378
let response = serde_json:: json!( {
320
- "max_frame_no" : current_count + 1
379
+ "max_frame_no" : current_count
321
380
} ) ;
322
381
323
382
Ok :: < _ , hyper:: Error > (
0 commit comments