Mercurial > hg
comparison rust/hg-core/src/repo.rs @ 49146:802e2c25dab8 stable
rust-dirstate-v2: clean up previous data file after the docket is written
This was overlooked before and caused many data files to keep living forever.
We could potentially consider adding a random cleanup of them in case they
slipped through one day.
Differential Revision: https://phab.mercurial-scm.org/D12581
author | Raphaël Gomès <rgomes@octobus.net> |
---|---|
date | Thu, 21 Apr 2022 15:10:57 +0200 |
parents | dd2503a63d33 |
children | 10b9f11daf15 f2ef6a4f918f |
comparison
equal
deleted
inserted
replaced
49145:dd2503a63d33 | 49146:802e2c25dab8 |
---|---|
432 pub fn write_dirstate(&self) -> Result<(), DirstateError> { | 432 pub fn write_dirstate(&self) -> Result<(), DirstateError> { |
433 let map = self.dirstate_map()?; | 433 let map = self.dirstate_map()?; |
434 // TODO: Maintain a `DirstateMap::dirty` flag, and return early here if | 434 // TODO: Maintain a `DirstateMap::dirty` flag, and return early here if |
435 // it’s unset | 435 // it’s unset |
436 let parents = self.dirstate_parents()?; | 436 let parents = self.dirstate_parents()?; |
437 let packed_dirstate = if self.has_dirstate_v2() { | 437 let (packed_dirstate, old_uuid_to_remove) = if self.has_dirstate_v2() { |
438 let uuid = self.dirstate_data_file_uuid.get_or_init(self)?; | 438 let uuid = self.dirstate_data_file_uuid.get_or_init(self)?; |
439 let mut uuid = uuid.as_ref(); | 439 let mut uuid = uuid.as_ref(); |
440 let can_append = uuid.is_some(); | 440 let can_append = uuid.is_some(); |
441 let (data, tree_metadata, append, old_data_size) = | 441 let (data, tree_metadata, append, old_data_size) = |
442 map.pack_v2(can_append)?; | 442 map.pack_v2(can_append)?; |
443 if !append { | 443 if !append { |
444 uuid = None | 444 uuid = None |
445 } | 445 } |
446 let uuid = if let Some(uuid) = uuid { | 446 let (uuid, old_uuid) = if let Some(uuid) = uuid { |
447 std::str::from_utf8(uuid) | 447 let as_str = std::str::from_utf8(uuid) |
448 .map_err(|_| { | 448 .map_err(|_| { |
449 HgError::corrupted("non-UTF-8 dirstate data file ID") | 449 HgError::corrupted("non-UTF-8 dirstate data file ID") |
450 })? | 450 })? |
451 .to_owned() | 451 .to_owned(); |
452 let old_uuid_to_remove = Some(as_str.to_owned()); | |
453 (as_str, old_uuid_to_remove) | |
452 } else { | 454 } else { |
453 DirstateDocket::new_uid() | 455 (DirstateDocket::new_uid(), None) |
454 }; | 456 }; |
455 let data_filename = format!("dirstate.{}", uuid); | 457 let data_filename = format!("dirstate.{}", uuid); |
456 let data_filename = self.hg_vfs().join(data_filename); | 458 let data_filename = self.hg_vfs().join(data_filename); |
457 let mut options = std::fs::OpenOptions::new(); | 459 let mut options = std::fs::OpenOptions::new(); |
458 if append { | 460 if append { |
478 // TODO: use https://doc.rust-lang.org/std/io/trait.Seek.html#method.stream_position when we require Rust 1.51+ | 480 // TODO: use https://doc.rust-lang.org/std/io/trait.Seek.html#method.stream_position when we require Rust 1.51+ |
479 file.seek(SeekFrom::Current(0)) | 481 file.seek(SeekFrom::Current(0)) |
480 } | 482 } |
481 })() | 483 })() |
482 .when_writing_file(&data_filename)?; | 484 .when_writing_file(&data_filename)?; |
483 DirstateDocket::serialize( | 485 |
486 let packed_dirstate = DirstateDocket::serialize( | |
484 parents, | 487 parents, |
485 tree_metadata, | 488 tree_metadata, |
486 data_size, | 489 data_size, |
487 uuid.as_bytes(), | 490 uuid.as_bytes(), |
488 ) | 491 ) |
489 .map_err(|_: std::num::TryFromIntError| { | 492 .map_err(|_: std::num::TryFromIntError| { |
490 HgError::corrupted("overflow in dirstate docket serialization") | 493 HgError::corrupted("overflow in dirstate docket serialization") |
491 })? | 494 })?; |
492 } else { | 495 |
493 map.pack_v1(parents)? | 496 (packed_dirstate, old_uuid) |
497 } else { | |
498 (map.pack_v1(parents)?, None) | |
494 }; | 499 }; |
495 self.hg_vfs().atomic_write("dirstate", &packed_dirstate)?; | 500 |
501 let vfs = self.hg_vfs(); | |
502 vfs.atomic_write("dirstate", &packed_dirstate)?; | |
503 if let Some(uuid) = old_uuid_to_remove { | |
504 // Remove the old data file after the new docket pointing to the | |
505 // new data file was written. | |
506 vfs.remove_file(format!("dirstate.{}", uuid))?; | |
507 } | |
496 Ok(()) | 508 Ok(()) |
497 } | 509 } |
498 } | 510 } |
499 | 511 |
500 /// Lazily-initialized component of `Repo` with interior mutability | 512 /// Lazily-initialized component of `Repo` with interior mutability |