@@ -124,8 +124,7 @@ fn test_file_write_error() {
124124 assert_eq ! ( engine. last_index( 2 ) . unwrap( ) , 1 ) ;
125125}
126126
127- #[ test]
128- fn test_file_rotate_error ( ) {
127+ fn test_file_rotate_error ( restart_after_failure : bool ) {
129128 let dir = tempfile:: Builder :: new ( )
130129 . prefix ( "test_file_rotate_error" )
131130 . tempdir ( )
@@ -138,7 +137,7 @@ fn test_file_rotate_error() {
138137 let fs = Arc :: new ( ObfuscatedFileSystem :: default ( ) ) ;
139138 let entry = vec ! [ b'x' ; 1024 ] ;
140139
141- let engine = Engine :: open_with_file_system ( cfg. clone ( ) , fs. clone ( ) ) . unwrap ( ) ;
140+ let mut engine = Engine :: open_with_file_system ( cfg. clone ( ) , fs. clone ( ) ) . unwrap ( ) ;
142141 engine
143142 . write ( & mut generate_batch ( 1 , 1 , 2 , Some ( & entry) ) , false )
144143 . unwrap ( ) ;
@@ -160,27 +159,46 @@ fn test_file_rotate_error() {
160159 let _ = engine. write( & mut generate_batch( 1 , 4 , 5 , Some ( & entry) ) , false ) ;
161160 } )
162161 . is_err( ) ) ;
163- assert_eq ! ( engine. file_span( LogQueue :: Append ) . 1 , 1 ) ;
164162 }
163+ if restart_after_failure {
164+ drop ( engine) ;
165+ engine = Engine :: open_with_file_system ( cfg. clone ( ) , fs. clone ( ) ) . unwrap ( ) ;
166+ }
167+ assert_eq ! ( engine. file_span( LogQueue :: Append ) . 1 , 1 ) ;
165168 {
166169 // Fail to create new log file.
167170 let _f = FailGuard :: new ( "default_fs::create::err" , "return" ) ;
168- assert ! ( catch_unwind_silent( || {
169- let _ = engine. write( & mut generate_batch( 1 , 4 , 5 , Some ( & entry) ) , false ) ;
170- } )
171- . is_err( ) ) ;
172- assert_eq ! ( engine. file_span( LogQueue :: Append ) . 1 , 1 ) ;
171+ assert ! ( engine
172+ . write( & mut generate_batch( 1 , 4 , 5 , Some ( & entry) ) , false )
173+ . is_err( ) ) ;
173174 }
175+ if restart_after_failure {
176+ drop ( engine) ;
177+ engine = Engine :: open_with_file_system ( cfg. clone ( ) , fs. clone ( ) ) . unwrap ( ) ;
178+ }
179+ let num_files_before = std:: fs:: read_dir ( & dir) . unwrap ( ) . count ( ) ;
174180 {
175181 // Fail to write header of new log file.
176182 let _f = FailGuard :: new ( "log_file::write::err" , "1*off->return" ) ;
177- assert ! ( catch_unwind_silent( || {
178- let _ = engine. write( & mut generate_batch( 1 , 4 , 5 , Some ( & entry) ) , false ) ;
179- } )
180- . is_err( ) ) ;
183+ assert ! ( engine
184+ . write( & mut generate_batch( 1 , 4 , 5 , Some ( & entry) ) , false )
185+ . is_err( ) ) ;
186+ }
187+ if restart_after_failure {
188+ drop ( engine) ;
189+ engine = Engine :: open_with_file_system ( cfg. clone ( ) , fs. clone ( ) ) . unwrap ( ) ;
190+ // The new log file is added during recovery phase of restart.
191+ assert_eq ! ( engine. file_span( LogQueue :: Append ) . 1 , 2 ) ;
192+ } else {
181193 assert_eq ! ( engine. file_span( LogQueue :: Append ) . 1 , 1 ) ;
182194 }
183- {
195+ // Although the header is not written, the file is still created.
196+ assert_eq ! (
197+ std:: fs:: read_dir( & dir) . unwrap( ) . count( ) - num_files_before,
198+ 1
199+ ) ;
200+ if !restart_after_failure {
201+ // If the engine restarted, the write does not require sync will succeed.
184202 // Fail to sync new log file. The old log file is already sync-ed at this point.
185203 let _f = FailGuard :: new ( "log_fd::sync::err" , "return" ) ;
186204 assert ! ( catch_unwind_silent( || {
@@ -190,18 +208,39 @@ fn test_file_rotate_error() {
190208 assert_eq ! ( engine. file_span( LogQueue :: Append ) . 1 , 1 ) ;
191209 }
192210
211+ // Only one log file should be created after all the incidents.
212+ assert_eq ! (
213+ std:: fs:: read_dir( & dir) . unwrap( ) . count( ) - num_files_before,
214+ 1
215+ ) ;
193216 // We can continue writing after the incidents.
194217 engine
195218 . write ( & mut generate_batch ( 2 , 1 , 2 , Some ( & entry) ) , true )
196219 . unwrap ( ) ;
197- drop ( engine) ;
198- let engine = Engine :: open_with_file_system ( cfg, fs) . unwrap ( ) ;
220+ if restart_after_failure {
221+ drop ( engine) ;
222+ engine = Engine :: open_with_file_system ( cfg, fs) . unwrap ( ) ;
223+ }
224+ assert_eq ! (
225+ std:: fs:: read_dir( & dir) . unwrap( ) . count( ) - num_files_before,
226+ 1
227+ ) ;
199228 assert_eq ! ( engine. first_index( 1 ) . unwrap( ) , 1 ) ;
200229 assert_eq ! ( engine. last_index( 1 ) . unwrap( ) , 4 ) ;
201230 assert_eq ! ( engine. first_index( 2 ) . unwrap( ) , 1 ) ;
202231 assert_eq ! ( engine. last_index( 2 ) . unwrap( ) , 1 ) ;
203232}
204233
234+ #[ test]
235+ fn test_file_rotate_error_without_restart ( ) {
236+ test_file_rotate_error ( false ) ;
237+ }
238+
239+ #[ test]
240+ fn test_file_rotate_error_with_restart ( ) {
241+ test_file_rotate_error ( true ) ;
242+ }
243+
205244#[ test]
206245fn test_concurrent_write_error ( ) {
207246 let dir = tempfile:: Builder :: new ( )
@@ -262,10 +301,8 @@ fn test_concurrent_write_error() {
262301 let _f2 = FailGuard :: new ( "log_file::truncate::err" , "return" ) ;
263302 let entry_clone = entry. clone ( ) ;
264303 ctx. write_ext ( move |e| {
265- catch_unwind_silent ( || {
266- e. write ( & mut generate_batch ( 1 , 11 , 21 , Some ( & entry_clone) ) , false )
267- } )
268- . unwrap_err ( ) ;
304+ e. write ( & mut generate_batch ( 1 , 11 , 21 , Some ( & entry_clone) ) , false )
305+ . unwrap_err ( ) ;
269306 } ) ;
270307 // We don't test followers, their panics are hard to catch.
271308 ctx. join ( ) ;
@@ -527,20 +564,17 @@ fn test_no_space_write_error() {
527564 cfg. dir = dir. path ( ) . to_str ( ) . unwrap ( ) . to_owned ( ) ;
528565 cfg. spill_dir = Some ( spill_dir. path ( ) . to_str ( ) . unwrap ( ) . to_owned ( ) ) ;
529566 {
530- // Case 1: `Write` is abnormal for no space left, Engine should panic at
567+ // Case 1: `Write` is abnormal for no space left, Engine should fail at
531568 // `rotate`.
532569 let cfg_err = Config {
533570 target_file_size : ReadableSize ( 1 ) ,
534571 ..cfg. clone ( )
535572 } ;
536573 let engine = Engine :: open ( cfg_err) . unwrap ( ) ;
537574 let _f = FailGuard :: new ( "log_fd::write::no_space_err" , "return" ) ;
538- assert ! ( catch_unwind_silent( || {
539- engine
540- . write( & mut generate_batch( 2 , 11 , 21 , Some ( & entry) ) , true )
541- . unwrap_err( ) ;
542- } )
543- . is_err( ) ) ;
575+ assert ! ( engine
576+ . write( & mut generate_batch( 2 , 11 , 21 , Some ( & entry) ) , true )
577+ . is_err( ) ) ;
544578 assert_eq ! (
545579 0 ,
546580 engine
@@ -554,12 +588,9 @@ fn test_no_space_write_error() {
554588 let _f1 = FailGuard :: new ( "log_fd::write::no_space_err" , "2*return->off" ) ;
555589 let _f2 = FailGuard :: new ( "file_pipe_log::force_choose_dir" , "return" ) ;
556590 // The first write should fail, because all dirs run out of space for writing.
557- assert ! ( catch_unwind_silent( || {
558- engine
559- . write( & mut generate_batch( 2 , 11 , 21 , Some ( & entry) ) , true )
560- . unwrap_err( ) ;
561- } )
562- . is_err( ) ) ;
591+ assert ! ( engine
592+ . write( & mut generate_batch( 2 , 11 , 21 , Some ( & entry) ) , true )
593+ . is_err( ) ) ;
563594 assert_eq ! (
564595 0 ,
565596 engine
0 commit comments