@@ -287,92 +287,90 @@ impl FilesystemStoreInner {
287
287
return Ok ( ( ) ) ;
288
288
}
289
289
290
- {
291
- let inner_lock_ref = {
292
- let mut outer_lock = self . locks . lock ( ) . unwrap ( ) ;
293
- Arc :: clone ( & outer_lock. entry ( dest_file_path. clone ( ) ) . or_default ( ) )
294
- } ;
295
- let mut last_written_version = inner_lock_ref. write ( ) . unwrap ( ) ;
296
-
297
- // If a version is provided, we check if we already have a newer version written/removed. This is used in
298
- // async contexts to realize eventual consistency.
299
- if let Some ( version) = version {
300
- if version <= * last_written_version {
301
- // If the version is not greater, we don't touch the file.
302
- return Ok ( ( ) ) ;
303
- }
304
-
305
- * last_written_version = version;
290
+ let inner_lock_ref = {
291
+ let mut outer_lock = self . locks . lock ( ) . unwrap ( ) ;
292
+ Arc :: clone ( & outer_lock. entry ( dest_file_path. clone ( ) ) . or_default ( ) )
293
+ } ;
294
+ let mut last_written_version = inner_lock_ref. write ( ) . unwrap ( ) ;
295
+
296
+ // If a version is provided, we check if we already have a newer version written/removed. This is used in
297
+ // async contexts to realize eventual consistency.
298
+ if let Some ( version) = version {
299
+ if version <= * last_written_version {
300
+ // If the version is not greater, we don't touch the file.
301
+ return Ok ( ( ) ) ;
306
302
}
307
303
308
- if lazy {
309
- // If we're lazy we just call remove and be done with it.
310
- fs:: remove_file ( & dest_file_path) ?;
311
- } else {
312
- // If we're not lazy we try our best to persist the updated metadata to ensure
313
- // atomicity of this call.
314
- #[ cfg( not( target_os = "windows" ) ) ]
315
- {
316
- fs:: remove_file ( & dest_file_path) ?;
304
+ * last_written_version = version;
305
+ }
317
306
318
- let parent_directory = dest_file_path. parent ( ) . ok_or_else ( || {
319
- let msg = format ! (
320
- "Could not retrieve parent directory of {}." ,
321
- dest_file_path. display( )
322
- ) ;
323
- std:: io:: Error :: new ( std:: io:: ErrorKind :: InvalidInput , msg)
324
- } ) ?;
325
- let dir_file = fs:: OpenOptions :: new ( ) . read ( true ) . open ( parent_directory) ?;
326
- // The above call to `fs::remove_file` corresponds to POSIX `unlink`, whose changes
327
- // to the inode might get cached (and hence possibly lost on crash), depending on
328
- // the target platform and file system.
329
- //
330
- // In order to assert we permanently removed the file in question we therefore
331
- // call `fsync` on the parent directory on platforms that support it.
332
- dir_file. sync_all ( ) ?;
333
- }
307
+ if lazy {
308
+ // If we're lazy we just call remove and be done with it.
309
+ fs:: remove_file ( & dest_file_path) ?;
310
+ } else {
311
+ // If we're not lazy we try our best to persist the updated metadata to ensure
312
+ // atomicity of this call.
313
+ #[ cfg( not( target_os = "windows" ) ) ]
314
+ {
315
+ fs:: remove_file ( & dest_file_path) ?;
334
316
335
- #[ cfg( target_os = "windows" ) ]
336
- {
337
- // Since Windows `DeleteFile` API is not persisted until the last open file handle
338
- // is dropped, and there seemingly is no reliable way to flush the directory
339
- // metadata, we here fall back to use a 'recycling bin' model, i.e., first move the
340
- // file to be deleted to a temporary trash file and remove the latter file
341
- // afterwards.
342
- //
343
- // This should be marginally better, as, according to the documentation,
344
- // `MoveFileExW` APIs should offer stronger persistence guarantees,
345
- // at least if `MOVEFILE_WRITE_THROUGH`/`MOVEFILE_REPLACE_EXISTING` is set.
346
- // However, all this is partially based on assumptions and local experiments, as
347
- // Windows API is horribly underdocumented.
348
- let mut trash_file_path = dest_file_path. clone ( ) ;
349
- let trash_file_ext =
350
- format ! ( "{}.trash" , self . tmp_file_counter. fetch_add( 1 , Ordering :: AcqRel ) ) ;
351
- trash_file_path. set_extension ( trash_file_ext) ;
317
+ let parent_directory = dest_file_path. parent ( ) . ok_or_else ( || {
318
+ let msg = format ! (
319
+ "Could not retrieve parent directory of {}." ,
320
+ dest_file_path. display( )
321
+ ) ;
322
+ std:: io:: Error :: new ( std:: io:: ErrorKind :: InvalidInput , msg)
323
+ } ) ?;
324
+ let dir_file = fs:: OpenOptions :: new ( ) . read ( true ) . open ( parent_directory) ?;
325
+ // The above call to `fs::remove_file` corresponds to POSIX `unlink`, whose changes
326
+ // to the inode might get cached (and hence possibly lost on crash), depending on
327
+ // the target platform and file system.
328
+ //
329
+ // In order to assert we permanently removed the file in question we therefore
330
+ // call `fsync` on the parent directory on platforms that support it.
331
+ dir_file. sync_all ( ) ?;
332
+ }
352
333
353
- call ! ( unsafe {
354
- windows_sys:: Win32 :: Storage :: FileSystem :: MoveFileExW (
355
- path_to_windows_str( & dest_file_path) . as_ptr( ) ,
356
- path_to_windows_str( & trash_file_path) . as_ptr( ) ,
357
- windows_sys:: Win32 :: Storage :: FileSystem :: MOVEFILE_WRITE_THROUGH
334
+ #[ cfg( target_os = "windows" ) ]
335
+ {
336
+ // Since Windows `DeleteFile` API is not persisted until the last open file handle
337
+ // is dropped, and there seemingly is no reliable way to flush the directory
338
+ // metadata, we here fall back to use a 'recycling bin' model, i.e., first move the
339
+ // file to be deleted to a temporary trash file and remove the latter file
340
+ // afterwards.
341
+ //
342
+ // This should be marginally better, as, according to the documentation,
343
+ // `MoveFileExW` APIs should offer stronger persistence guarantees,
344
+ // at least if `MOVEFILE_WRITE_THROUGH`/`MOVEFILE_REPLACE_EXISTING` is set.
345
+ // However, all this is partially based on assumptions and local experiments, as
346
+ // Windows API is horribly underdocumented.
347
+ let mut trash_file_path = dest_file_path. clone ( ) ;
348
+ let trash_file_ext =
349
+ format ! ( "{}.trash" , self . tmp_file_counter. fetch_add( 1 , Ordering :: AcqRel ) ) ;
350
+ trash_file_path. set_extension ( trash_file_ext) ;
351
+
352
+ call ! ( unsafe {
353
+ windows_sys:: Win32 :: Storage :: FileSystem :: MoveFileExW (
354
+ path_to_windows_str( & dest_file_path) . as_ptr( ) ,
355
+ path_to_windows_str( & trash_file_path) . as_ptr( ) ,
356
+ windows_sys:: Win32 :: Storage :: FileSystem :: MOVEFILE_WRITE_THROUGH
358
357
| windows_sys:: Win32 :: Storage :: FileSystem :: MOVEFILE_REPLACE_EXISTING ,
359
- )
360
- } ) ?;
361
-
362
- {
363
- // We fsync the trash file in hopes this will also flush the original's file
364
- // metadata to disk.
365
- let trash_file = fs:: OpenOptions :: new ( )
366
- . read ( true )
367
- . write ( true )
368
- . open ( & trash_file_path. clone ( ) ) ?;
369
- trash_file. sync_all ( ) ?;
370
- }
358
+ )
359
+ } ) ?;
371
360
372
- // We're fine if this remove would fail as the trash file will be cleaned up in
373
- // list eventually.
374
- fs:: remove_file ( trash_file_path) . ok ( ) ;
361
+ {
362
+ // We fsync the trash file in hopes this will also flush the original's file
363
+ // metadata to disk.
364
+ let trash_file = fs:: OpenOptions :: new ( )
365
+ . read ( true )
366
+ . write ( true )
367
+ . open ( & trash_file_path. clone ( ) ) ?;
368
+ trash_file. sync_all ( ) ?;
375
369
}
370
+
371
+ // We're fine if this remove would fail as the trash file will be cleaned up in
372
+ // list eventually.
373
+ fs:: remove_file ( trash_file_path) . ok ( ) ;
376
374
}
377
375
}
378
376
0 commit comments