##// END OF EJS Templates
dirstate-tree: Serialize to disk...
Simon Sapin -
r47872:d6c94ca4 default
parent child Browse files
Show More
@@ -64,9 +64,9 checksum = "08c48aae112d48ed9f069b33538e
64 64
65 65 [[package]]
66 66 name = "bytes-cast"
67 version = "0.1.0"
67 version = "0.2.0"
68 68 source = "registry+https://github.com/rust-lang/crates.io-index"
69 checksum = "3196ba300c7bc9282a4331e878496cb3e9603a898a8f1446601317163e16ca52"
69 checksum = "0d434f9a4ecbe987e7ccfda7274b6f82ea52c9b63742565a65cb5e8ba0f2c452"
70 70 dependencies = [
71 71 "bytes-cast-derive",
72 72 ]
@@ -9,7 +9,7 edition = "2018"
9 9 name = "hg"
10 10
11 11 [dependencies]
12 bytes-cast = "0.1"
12 bytes-cast = "0.2"
13 13 byteorder = "1.3.4"
14 14 derive_more = "0.99"
15 15 home = "0.5"
@@ -4,7 +4,7
4 4 // GNU General Public License version 2 or any later version.
5 5
6 6 use crate::errors::HgError;
7 use crate::utils::hg_path::HgPath;
7 use crate::utils::hg_path::{HgPath, HgPathBuf};
8 8 use crate::{
9 9 dirstate::{CopyMap, EntryState, RawEntry, StateMap},
10 10 DirstateEntry, DirstateParents,
@@ -82,9 +82,71 pub fn parse_dirstate_entries<'a>(
82 82 Ok(parents)
83 83 }
84 84
85 fn packed_filename_and_copy_source_size(
86 filename: &HgPathBuf,
87 copy_source: Option<&HgPathBuf>,
88 ) -> usize {
89 filename.len()
90 + if let Some(source) = copy_source {
91 b"\0".len() + source.len()
92 } else {
93 0
94 }
95 }
96
97 pub fn packed_entry_size(
98 filename: &HgPathBuf,
99 copy_source: Option<&HgPathBuf>,
100 ) -> usize {
101 MIN_ENTRY_SIZE
102 + packed_filename_and_copy_source_size(filename, copy_source)
103 }
104
105 pub fn pack_entry(
106 filename: &HgPathBuf,
107 entry: &DirstateEntry,
108 copy_source: Option<&HgPathBuf>,
109 packed: &mut Vec<u8>,
110 ) {
111 let length = packed_filename_and_copy_source_size(filename, copy_source);
112
113 // Unwrapping because `impl std::io::Write for Vec<u8>` never errors
114 packed.write_u8(entry.state.into()).unwrap();
115 packed.write_i32::<BigEndian>(entry.mode).unwrap();
116 packed.write_i32::<BigEndian>(entry.size).unwrap();
117 packed.write_i32::<BigEndian>(entry.mtime).unwrap();
118 packed.write_i32::<BigEndian>(length as i32).unwrap();
119 packed.extend(filename.as_bytes());
120 if let Some(source) = copy_source {
121 packed.push(b'\0');
122 packed.extend(source.as_bytes());
123 }
124 }
125
85 126 /// Seconds since the Unix epoch
86 127 pub struct Timestamp(pub u64);
87 128
129 pub fn clear_ambiguous_mtime(
130 entry: &mut DirstateEntry,
131 mtime_now: i32,
132 ) -> bool {
133 let ambiguous =
134 entry.state == EntryState::Normal && entry.mtime == mtime_now;
135 if ambiguous {
136 // The file was last modified "simultaneously" with the current
137 // write to dirstate (i.e. within the same second for file-
138 // systems with a granularity of 1 sec). This commonly happens
139 // for at least a couple of files on 'update'.
140 // The user could change the file without changing its size
141 // within the same second. Invalidate the file's mtime in
142 // dirstate, forcing future 'status' calls to compare the
143 // contents of the file if the size is the same. This prevents
144 // mistakenly treating such files as clean.
145 entry.mtime = -1;
146 }
147 ambiguous
148 }
149
88 150 pub fn pack_dirstate(
89 151 state_map: &mut StateMap,
90 152 copy_map: &CopyMap,
@@ -97,11 +159,7 pub fn pack_dirstate(
97 159 let expected_size: usize = state_map
98 160 .iter()
99 161 .map(|(filename, _)| {
100 let mut length = MIN_ENTRY_SIZE + filename.len();
101 if let Some(copy) = copy_map.get(filename) {
102 length += copy.len() + 1;
103 }
104 length
162 packed_entry_size(filename, copy_map.get(filename))
105 163 })
106 164 .sum();
107 165 let expected_size = expected_size + PARENT_SIZE * 2;
@@ -112,39 +170,8 pub fn pack_dirstate(
112 170 packed.extend(parents.p2.as_bytes());
113 171
114 172 for (filename, entry) in state_map.iter_mut() {
115 let new_filename = filename.to_owned();
116 let mut new_mtime: i32 = entry.mtime;
117 if entry.state == EntryState::Normal && entry.mtime == now {
118 // The file was last modified "simultaneously" with the current
119 // write to dirstate (i.e. within the same second for file-
120 // systems with a granularity of 1 sec). This commonly happens
121 // for at least a couple of files on 'update'.
122 // The user could change the file without changing its size
123 // within the same second. Invalidate the file's mtime in
124 // dirstate, forcing future 'status' calls to compare the
125 // contents of the file if the size is the same. This prevents
126 // mistakenly treating such files as clean.
127 new_mtime = -1;
128 *entry = DirstateEntry {
129 mtime: new_mtime,
130 ..*entry
131 };
132 }
133 let mut new_filename = new_filename.into_vec();
134 if let Some(copy) = copy_map.get(filename) {
135 new_filename.push(b'\0');
136 new_filename.extend(copy.bytes());
137 }
138
139 // Unwrapping because `impl std::io::Write for Vec<u8>` never errors
140 packed.write_u8(entry.state.into()).unwrap();
141 packed.write_i32::<BigEndian>(entry.mode).unwrap();
142 packed.write_i32::<BigEndian>(entry.size).unwrap();
143 packed.write_i32::<BigEndian>(new_mtime).unwrap();
144 packed
145 .write_i32::<BigEndian>(new_filename.len() as i32)
146 .unwrap();
147 packed.extend(new_filename)
173 clear_ambiguous_mtime(entry, now);
174 pack_entry(filename, entry, copy_map.get(filename), &mut packed)
148 175 }
149 176
150 177 if packed.len() != expected_size {
@@ -1,11 +1,14
1 use std::collections::BTreeMap;
1 use bytes_cast::BytesCast;
2 2 use std::path::PathBuf;
3 use std::{collections::BTreeMap, convert::TryInto};
3 4
4 5 use super::path_with_basename::WithBasename;
6 use crate::dirstate::parsers::clear_ambiguous_mtime;
7 use crate::dirstate::parsers::pack_entry;
8 use crate::dirstate::parsers::packed_entry_size;
5 9 use crate::dirstate::parsers::parse_dirstate_entries;
6 10 use crate::dirstate::parsers::parse_dirstate_parents;
7 11 use crate::dirstate::parsers::Timestamp;
8
9 12 use crate::matchers::Matcher;
10 13 use crate::revlog::node::NULL_NODE;
11 14 use crate::utils::hg_path::{HgPath, HgPathBuf};
@@ -327,11 +330,38 impl super::dispatch::DirstateMapMethods
327 330
328 331 fn pack(
329 332 &mut self,
330 _parents: DirstateParents,
331 _now: Timestamp,
333 parents: DirstateParents,
334 now: Timestamp,
332 335 ) -> Result<Vec<u8>, DirstateError> {
333 let _ = self.iter_node_data_mut();
334 todo!()
336 // Optizimation (to be measured?): pre-compute size to avoid `Vec`
337 // reallocations
338 let mut size = parents.as_bytes().len();
339 for (path, node) in self.iter_nodes() {
340 if node.entry.is_some() {
341 size += packed_entry_size(
342 path.full_path(),
343 node.copy_source.as_ref(),
344 )
345 }
346 }
347
348 let mut packed = Vec::with_capacity(size);
349 packed.extend(parents.as_bytes());
350
351 let now: i32 = now.0.try_into().expect("time overflow");
352 for (path, opt_entry, copy_source) in self.iter_node_data_mut() {
353 if let Some(entry) = opt_entry {
354 clear_ambiguous_mtime(entry, now);
355 pack_entry(
356 path.full_path(),
357 entry,
358 copy_source.as_ref(),
359 &mut packed,
360 );
361 }
362 }
363 self.dirty_parents = false;
364 Ok(packed)
335 365 }
336 366
337 367 fn build_file_fold_map(&mut self) -> &FastHashMap<HgPathBuf, HgPathBuf> {
General Comments 0
You need to be logged in to leave comments. Login now