##// END OF EJS Templates
branching: merge stable into default...
Raphaël Gomès -
r50039:10b9f11d merge default
parent child Browse files
Show More
@@ -50,6 +50,10 b" pub struct DirstateMap<'on_disk> {"
50
50
51 /// How many bytes of `on_disk` are not used anymore
51 /// How many bytes of `on_disk` are not used anymore
52 pub(super) unreachable_bytes: u32,
52 pub(super) unreachable_bytes: u32,
53
54 /// Size of the data used to first load this `DirstateMap`. Used in case
55 /// we need to write some new metadata, but no new data on disk.
56 pub(super) old_data_size: usize,
53 }
57 }
54
58
55 /// Using a plain `HgPathBuf` of the full path from the repository root as a
59 /// Using a plain `HgPathBuf` of the full path from the repository root as a
@@ -436,6 +440,7 b" impl<'on_disk> DirstateMap<'on_disk> {"
436 nodes_with_copy_source_count: 0,
440 nodes_with_copy_source_count: 0,
437 ignore_patterns_hash: [0; on_disk::IGNORE_PATTERNS_HASH_LEN],
441 ignore_patterns_hash: [0; on_disk::IGNORE_PATTERNS_HASH_LEN],
438 unreachable_bytes: 0,
442 unreachable_bytes: 0,
443 old_data_size: 0,
439 }
444 }
440 }
445 }
441
446
@@ -1232,12 +1237,13 b' impl OwningDirstateMap {'
1232 /// Returns new data and metadata together with whether that data should be
1237 /// Returns new data and metadata together with whether that data should be
1233 /// appended to the existing data file whose content is at
1238 /// appended to the existing data file whose content is at
1234 /// `map.on_disk` (true), instead of written to a new data file
1239 /// `map.on_disk` (true), instead of written to a new data file
1235 /// (false).
1240 /// (false), and the previous size of data on disk.
1236 #[timed]
1241 #[timed]
1237 pub fn pack_v2(
1242 pub fn pack_v2(
1238 &self,
1243 &self,
1239 can_append: bool,
1244 can_append: bool,
1240 ) -> Result<(Vec<u8>, on_disk::TreeMetadata, bool), DirstateError> {
1245 ) -> Result<(Vec<u8>, on_disk::TreeMetadata, bool, usize), DirstateError>
1246 {
1241 let map = self.get_map();
1247 let map = self.get_map();
1242 on_disk::write(map, can_append)
1248 on_disk::write(map, can_append)
1243 }
1249 }
@@ -1795,7 +1801,8 b' mod tests {'
1795 None,
1801 None,
1796 )?;
1802 )?;
1797
1803
1798 let (packed, metadata, _should_append) = map.pack_v2(false)?;
1804 let (packed, metadata, _should_append, _old_data_size) =
1805 map.pack_v2(false)?;
1799 let packed_len = packed.len();
1806 let packed_len = packed.len();
1800 assert!(packed_len > 0);
1807 assert!(packed_len > 0);
1801
1808
@@ -290,6 +290,7 b" pub(super) fn read<'on_disk>("
290 nodes_with_copy_source_count: meta.nodes_with_copy_source_count.get(),
290 nodes_with_copy_source_count: meta.nodes_with_copy_source_count.get(),
291 ignore_patterns_hash: meta.ignore_patterns_hash,
291 ignore_patterns_hash: meta.ignore_patterns_hash,
292 unreachable_bytes: meta.unreachable_bytes.get(),
292 unreachable_bytes: meta.unreachable_bytes.get(),
293 old_data_size: on_disk.len(),
293 };
294 };
294 Ok(dirstate_map)
295 Ok(dirstate_map)
295 }
296 }
@@ -601,11 +602,11 b" pub(crate) fn for_each_tracked_path<'on_"
601 /// Returns new data and metadata, together with whether that data should be
602 /// Returns new data and metadata, together with whether that data should be
602 /// appended to the existing data file whose content is at
603 /// appended to the existing data file whose content is at
603 /// `dirstate_map.on_disk` (true), instead of written to a new data file
604 /// `dirstate_map.on_disk` (true), instead of written to a new data file
604 /// (false).
605 /// (false), and the previous size of data on disk.
605 pub(super) fn write(
606 pub(super) fn write(
606 dirstate_map: &DirstateMap,
607 dirstate_map: &DirstateMap,
607 can_append: bool,
608 can_append: bool,
608 ) -> Result<(Vec<u8>, TreeMetadata, bool), DirstateError> {
609 ) -> Result<(Vec<u8>, TreeMetadata, bool, usize), DirstateError> {
609 let append = can_append && dirstate_map.write_should_append();
610 let append = can_append && dirstate_map.write_should_append();
610
611
611 // This ignores the space for paths, and for nodes without an entry.
612 // This ignores the space for paths, and for nodes without an entry.
@@ -631,7 +632,7 b' pub(super) fn write('
631 unused: [0; 4],
632 unused: [0; 4],
632 ignore_patterns_hash: dirstate_map.ignore_patterns_hash,
633 ignore_patterns_hash: dirstate_map.ignore_patterns_hash,
633 };
634 };
634 Ok((writer.out, meta, append))
635 Ok((writer.out, meta, append, dirstate_map.old_data_size))
635 }
636 }
636
637
637 struct Writer<'dmap, 'on_disk> {
638 struct Writer<'dmap, 'on_disk> {
@@ -423,22 +423,25 b' impl Repo {'
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);
@@ -453,13 +456,23 b' impl Repo {'
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,
@@ -467,11 +480,20 b' impl Repo {'
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 })?;
484
485 (packed_dirstate, old_uuid)
471 } else {
486 } else {
472 map.pack_v1(parents)?
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 }
@@ -252,7 +252,7 b' py_class!(pub class DirstateMap |py| {'
252 let inner = self.inner(py).borrow();
252 let inner = self.inner(py).borrow();
253 let result = inner.pack_v2(can_append);
253 let result = inner.pack_v2(can_append);
254 match result {
254 match result {
255 Ok((packed, tree_metadata, append)) => {
255 Ok((packed, tree_metadata, append, _old_data_size)) => {
256 let packed = PyBytes::new(py, &packed);
256 let packed = PyBytes::new(py, &packed);
257 let tree_metadata = PyBytes::new(py, tree_metadata.as_bytes());
257 let tree_metadata = PyBytes::new(py, tree_metadata.as_bytes());
258 let tuple = (packed, tree_metadata, append);
258 let tuple = (packed, tree_metadata, append);
General Comments 0
You need to be logged in to leave comments. Login now