@@ -246,8 +246,10 @@ impl Tracker {
246
246
enum CurrentManifest {
247
247
// Don't generate a new snapshot at all.
248
248
UpToDate ,
249
- // Snapshot from scratch.
250
- Desync ,
249
+ FromScratch ,
250
+ // Snapshot from scratch, but the previous manifest
251
+ // had some chunk fingerprints that could still match.
252
+ Desync ( Manifest , Option < Arc < Chunk > > ) ,
251
253
// Use the previous manifest as an initial snapshot.
252
254
Initial ( Manifest , Option < Arc < Chunk > > ) ,
253
255
}
@@ -262,12 +264,14 @@ enum CurrentManifest {
262
264
impl Tracker {
263
265
/// Loads the current manifest and figures out what to do with it.
264
266
fn judge_current_manifest ( & self , version_id : & [ u8 ] ) -> CurrentManifest {
265
- let mut current_manifest: Option < ( Manifest , Option < Arc < Chunk > > ) > = self
267
+ let current_manifest: Option < ( Manifest , Option < Arc < Chunk > > ) > = self
266
268
. read_current_manifest ( )
267
269
. map_err ( |e| chain_info ! ( e, "failed to read staged manifest file" ) )
268
270
. ok ( )
269
271
. flatten ( ) ;
270
272
273
+ let desync: bool ;
274
+
271
275
// If we're snapshotting after a write, we always want to go
272
276
// through the whole process. We made some changes, let's
273
277
// guarantee we try and publish them. That's important because,
@@ -326,10 +330,8 @@ impl Tracker {
326
330
up_to_date = false ;
327
331
}
328
332
329
- // If the manifest isn't up to date, we can't use it.
330
- if !up_to_date {
331
- current_manifest = None ;
332
- }
333
+ // If the manifest isn't up to date, remember that.
334
+ desync = !up_to_date;
333
335
} else {
334
336
// If we're doing this opportunistically (not after a write)
335
337
// and the staging manifest seems up to date, there's nothing
@@ -344,14 +346,20 @@ impl Tracker {
344
346
}
345
347
346
348
// If we think there's work to do after a read
347
- // transaction, assume the worst, and rebuild
348
- // the snapshot from scratch.
349
- current_manifest = None ;
349
+ // transaction, assume the worst, and rescan
350
+ // the whole file
351
+ desync = true ;
350
352
}
351
353
352
354
match current_manifest {
353
- None => CurrentManifest :: Desync ,
354
- Some ( ( manifest, base) ) => CurrentManifest :: Initial ( manifest, base) ,
355
+ None => CurrentManifest :: FromScratch ,
356
+ Some ( ( manifest, base) ) => {
357
+ if desync {
358
+ CurrentManifest :: Desync ( manifest, base)
359
+ } else {
360
+ CurrentManifest :: Initial ( manifest, base)
361
+ }
362
+ }
355
363
}
356
364
}
357
365
@@ -363,6 +371,7 @@ impl Tracker {
363
371
fn snapshot_chunks (
364
372
& self ,
365
373
base : Option < Vec < Fingerprint > > ,
374
+ force_refresh : bool ,
366
375
) -> Result < ( u64 , Vec < Fingerprint > , Vec < BundledChunk > , usize ) > {
367
376
use rand:: Rng ;
368
377
let mut rng = rand:: thread_rng ( ) ;
@@ -402,12 +411,18 @@ impl Tracker {
402
411
. is_some ( ) ;
403
412
let delta = ( grown || wrote_past_end) as u64 ;
404
413
405
- // We definitely don't know anything about what's at or
406
- // after chunk index `fprints.len()`. We also don't
407
- // want to go out of bounds if the new file shrunk.
408
- backfill_begin = ( fprints. len ( ) as u64 )
409
- . clamp ( 0 , num_chunks)
410
- . saturating_sub ( delta) ;
414
+ if force_refresh {
415
+ // Assume all the chunks in the manifests exist, but confirm
416
+ // that they match what we want.
417
+ backfill_begin = 0 ;
418
+ } else {
419
+ // We definitely don't know anything about what's at or
420
+ // after chunk index `fprints.len()`. We also don't
421
+ // want to go out of bounds if the new file shrunk.
422
+ backfill_begin = ( fprints. len ( ) as u64 )
423
+ . clamp ( 0 , num_chunks)
424
+ . saturating_sub ( delta) ;
425
+ }
411
426
fprints
412
427
} else {
413
428
backfill_begin = 0 ;
@@ -551,6 +566,7 @@ impl Tracker {
551
566
header_fprint : Fingerprint ,
552
567
version_id : Vec < u8 > ,
553
568
current_manifest : Option < ( Manifest , Option < Arc < Chunk > > ) > ,
569
+ force_refresh : bool ,
554
570
) -> Result < ( usize , Vec < Fingerprint > , Option < Fingerprint > ) > {
555
571
use std:: os:: unix:: fs:: MetadataExt ;
556
572
@@ -585,7 +601,8 @@ impl Tracker {
585
601
// Try to get an initial list of chunks to work off.
586
602
let base_fprints = Self :: base_chunk_fprints ( current_manifest. as_ref ( ) . map ( |x| & x. 0 ) ) ;
587
603
588
- let ( len, mut chunks, bundled_chunks, mut copied) = self . snapshot_chunks ( base_fprints) ?;
604
+ let ( len, mut chunks, bundled_chunks, mut copied) =
605
+ self . snapshot_chunks ( base_fprints, force_refresh) ?;
589
606
590
607
let ( ctime, ctime_ns) = match self . file . metadata ( ) {
591
608
Ok ( meta) => ( meta. ctime ( ) , meta. ctime_nsec ( ) as i32 ) ,
@@ -724,11 +741,12 @@ impl Tracker {
724
741
e => chain_warn!( e, "failed to force populate version xattr" , path=?self . path) ) ;
725
742
}
726
743
727
- let current_manifest: Option < ( Manifest , Option < Arc < Chunk > > ) > =
744
+ let ( current_manifest, force_refresh ) : ( Option < ( Manifest , Option < Arc < Chunk > > ) > , bool ) =
728
745
match self . judge_current_manifest ( & version_id) {
729
746
CurrentManifest :: UpToDate => return Ok ( ( ) ) ,
730
- CurrentManifest :: Desync => None ,
731
- CurrentManifest :: Initial ( manifest, base) => Some ( ( manifest, base) ) ,
747
+ CurrentManifest :: FromScratch => ( None , true ) ,
748
+ CurrentManifest :: Desync ( manifest, base) => ( Some ( ( manifest, base) ) , true ) ,
749
+ CurrentManifest :: Initial ( manifest, base) => ( Some ( ( manifest, base) ) , false ) ,
732
750
} ;
733
751
734
752
// We don't *have* to overwrite the .metadata file, but we
@@ -740,7 +758,7 @@ impl Tracker {
740
758
// Publish an updated snapshot, and remember the chunks we
741
759
// care about.
742
760
let ( copied, chunks, base_chunk) =
743
- self . stage_new_snapshot ( header_fprint, version_id, current_manifest) ?;
761
+ self . stage_new_snapshot ( header_fprint, version_id, current_manifest, force_refresh ) ?;
744
762
745
763
let published = self . maybe_update_ready_buffer ( & chunks) ?;
746
764
0 commit comments