Mercurial > public > mercurial-scm > hg-stable
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 |