comparison rust/hg-core/src/repo.rs @ 49200:10b9f11daf15

branching: merge stable into default This also added the small fix need in Rust tests for the new `DirstateMap::pack_v2` API change in stable.
author Rapha?l Gom?s <rgomes@octobus.net>
date Mon, 25 Apr 2022 11:09:33 +0200
parents 3f5e207f78be 802e2c25dab8
children a932cad26d37
comparison
equal deleted inserted replaced
49199:f45e1618cbf6 49200:10b9f11daf15
421 pub fn write_dirstate(&self) -> Result<(), DirstateError> { 421 pub fn write_dirstate(&self) -> Result<(), DirstateError> {
422 let map = self.dirstate_map()?; 422 let map = self.dirstate_map()?;
423 // TODO: Maintain a `DirstateMap::dirty` flag, and return early here if 423 // TODO: Maintain a `DirstateMap::dirty` flag, and return early here if
424 // it’s unset 424 // it’s unset
425 let parents = self.dirstate_parents()?; 425 let parents = self.dirstate_parents()?;
426 let packed_dirstate = if self.has_dirstate_v2() { 426 let (packed_dirstate, old_uuid_to_remove) = if self.has_dirstate_v2() {
427 let uuid = self.dirstate_data_file_uuid.get_or_init(self)?; 427 let uuid = self.dirstate_data_file_uuid.get_or_init(self)?;
428 let mut uuid = uuid.as_ref(); 428 let mut uuid = uuid.as_ref();
429 let can_append = uuid.is_some(); 429 let can_append = uuid.is_some();
430 let (data, tree_metadata, append) = map.pack_v2(can_append)?; 430 let (data, tree_metadata, append, old_data_size) =
431 map.pack_v2(can_append)?;
431 if !append { 432 if !append {
432 uuid = None 433 uuid = None
433 } 434 }
434 let uuid = if let Some(uuid) = uuid { 435 let (uuid, old_uuid) = if let Some(uuid) = uuid {
435 std::str::from_utf8(uuid) 436 let as_str = std::str::from_utf8(uuid)
436 .map_err(|_| { 437 .map_err(|_| {
437 HgError::corrupted("non-UTF-8 dirstate data file ID") 438 HgError::corrupted("non-UTF-8 dirstate data file ID")
438 })? 439 })?
439 .to_owned() 440 .to_owned();
441 let old_uuid_to_remove = Some(as_str.to_owned());
442 (as_str, old_uuid_to_remove)
440 } else { 443 } else {
441 DirstateDocket::new_uid() 444 (DirstateDocket::new_uid(), None)
442 }; 445 };
443 let data_filename = format!("dirstate.{}", uuid); 446 let data_filename = format!("dirstate.{}", uuid);
444 let data_filename = self.hg_vfs().join(data_filename); 447 let data_filename = self.hg_vfs().join(data_filename);
445 let mut options = std::fs::OpenOptions::new(); 448 let mut options = std::fs::OpenOptions::new();
446 if append { 449 if append {
451 let data_size = (|| { 454 let data_size = (|| {
452 // TODO: loop and try another random ID if !append and this 455 // TODO: loop and try another random ID if !append and this
453 // returns `ErrorKind::AlreadyExists`? Collision chance of two 456 // returns `ErrorKind::AlreadyExists`? Collision chance of two
454 // random IDs is one in 2**32 457 // random IDs is one in 2**32
455 let mut file = options.open(&data_filename)?; 458 let mut file = options.open(&data_filename)?;
456 file.write_all(&data)?; 459 if data.is_empty() {
457 file.flush()?; 460 // If we're not appending anything, the data size is the
458 // TODO: use https://doc.rust-lang.org/std/io/trait.Seek.html#method.stream_position when we require Rust 1.51+ 461 // same as in the previous docket. It is *not* the file
459 file.seek(SeekFrom::Current(0)) 462 // length, since it could have garbage at the end.
463 // We don't have to worry about it when we do have data
464 // to append since we rewrite the root node in this case.
465 Ok(old_data_size as u64)
466 } else {
467 file.write_all(&data)?;
468 file.flush()?;
469 // TODO: use https://doc.rust-lang.org/std/io/trait.Seek.html#method.stream_position when we require Rust 1.51+
470 file.seek(SeekFrom::Current(0))
471 }
460 })() 472 })()
461 .when_writing_file(&data_filename)?; 473 .when_writing_file(&data_filename)?;
462 DirstateDocket::serialize( 474
475 let packed_dirstate = DirstateDocket::serialize(
463 parents, 476 parents,
464 tree_metadata, 477 tree_metadata,
465 data_size, 478 data_size,
466 uuid.as_bytes(), 479 uuid.as_bytes(),
467 ) 480 )
468 .map_err(|_: std::num::TryFromIntError| { 481 .map_err(|_: std::num::TryFromIntError| {
469 HgError::corrupted("overflow in dirstate docket serialization") 482 HgError::corrupted("overflow in dirstate docket serialization")
470 })? 483 })?;
471 } else { 484
472 map.pack_v1(parents)? 485 (packed_dirstate, old_uuid)
486 } else {
487 (map.pack_v1(parents)?, None)
473 }; 488 };
474 self.hg_vfs().atomic_write("dirstate", &packed_dirstate)?; 489
490 let vfs = self.hg_vfs();
491 vfs.atomic_write("dirstate", &packed_dirstate)?;
492 if let Some(uuid) = old_uuid_to_remove {
493 // Remove the old data file after the new docket pointing to the
494 // new data file was written.
495 vfs.remove_file(format!("dirstate.{}", uuid))?;
496 }
475 Ok(()) 497 Ok(())
476 } 498 }
477 } 499 }
478 500
479 /// Lazily-initialized component of `Repo` with interior mutability 501 /// Lazily-initialized component of `Repo` with interior mutability