Show More
@@ -64,9 +64,9 checksum = "08c48aae112d48ed9f069b33538e | |||||
64 |
|
64 | |||
65 | [[package]] |
|
65 | [[package]] | |
66 | name = "bytes-cast" |
|
66 | name = "bytes-cast" | |
67 |
version = "0. |
|
67 | version = "0.2.0" | |
68 | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
68 | source = "registry+https://github.com/rust-lang/crates.io-index" | |
69 | checksum = "3196ba300c7bc9282a4331e878496cb3e9603a898a8f1446601317163e16ca52" |
|
69 | checksum = "0d434f9a4ecbe987e7ccfda7274b6f82ea52c9b63742565a65cb5e8ba0f2c452" | |
70 | dependencies = [ |
|
70 | dependencies = [ | |
71 | "bytes-cast-derive", |
|
71 | "bytes-cast-derive", | |
72 | ] |
|
72 | ] |
@@ -9,7 +9,7 edition = "2018" | |||||
9 | name = "hg" |
|
9 | name = "hg" | |
10 |
|
10 | |||
11 | [dependencies] |
|
11 | [dependencies] | |
12 |
bytes-cast = "0. |
|
12 | bytes-cast = "0.2" | |
13 | byteorder = "1.3.4" |
|
13 | byteorder = "1.3.4" | |
14 | derive_more = "0.99" |
|
14 | derive_more = "0.99" | |
15 | home = "0.5" |
|
15 | home = "0.5" |
@@ -4,7 +4,7 | |||||
4 | // GNU General Public License version 2 or any later version. |
|
4 | // GNU General Public License version 2 or any later version. | |
5 |
|
5 | |||
6 | use crate::errors::HgError; |
|
6 | use crate::errors::HgError; | |
7 | use crate::utils::hg_path::HgPath; |
|
7 | use crate::utils::hg_path::{HgPath, HgPathBuf}; | |
8 | use crate::{ |
|
8 | use crate::{ | |
9 | dirstate::{CopyMap, EntryState, RawEntry, StateMap}, |
|
9 | dirstate::{CopyMap, EntryState, RawEntry, StateMap}, | |
10 | DirstateEntry, DirstateParents, |
|
10 | DirstateEntry, DirstateParents, | |
@@ -82,9 +82,71 pub fn parse_dirstate_entries<'a>( | |||||
82 | Ok(parents) |
|
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 | /// Seconds since the Unix epoch |
|
126 | /// Seconds since the Unix epoch | |
86 | pub struct Timestamp(pub u64); |
|
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 | pub fn pack_dirstate( |
|
150 | pub fn pack_dirstate( | |
89 | state_map: &mut StateMap, |
|
151 | state_map: &mut StateMap, | |
90 | copy_map: &CopyMap, |
|
152 | copy_map: &CopyMap, | |
@@ -97,11 +159,7 pub fn pack_dirstate( | |||||
97 | let expected_size: usize = state_map |
|
159 | let expected_size: usize = state_map | |
98 | .iter() |
|
160 | .iter() | |
99 | .map(|(filename, _)| { |
|
161 | .map(|(filename, _)| { | |
100 | let mut length = MIN_ENTRY_SIZE + filename.len(); |
|
162 | packed_entry_size(filename, copy_map.get(filename)) | |
101 | if let Some(copy) = copy_map.get(filename) { |
|
|||
102 | length += copy.len() + 1; |
|
|||
103 | } |
|
|||
104 | length |
|
|||
105 | }) |
|
163 | }) | |
106 | .sum(); |
|
164 | .sum(); | |
107 | let expected_size = expected_size + PARENT_SIZE * 2; |
|
165 | let expected_size = expected_size + PARENT_SIZE * 2; | |
@@ -112,39 +170,8 pub fn pack_dirstate( | |||||
112 | packed.extend(parents.p2.as_bytes()); |
|
170 | packed.extend(parents.p2.as_bytes()); | |
113 |
|
171 | |||
114 | for (filename, entry) in state_map.iter_mut() { |
|
172 | for (filename, entry) in state_map.iter_mut() { | |
115 | let new_filename = filename.to_owned(); |
|
173 | clear_ambiguous_mtime(entry, now); | |
116 | let mut new_mtime: i32 = entry.mtime; |
|
174 | pack_entry(filename, entry, copy_map.get(filename), &mut packed) | |
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) |
|
|||
148 | } |
|
175 | } | |
149 |
|
176 | |||
150 | if packed.len() != expected_size { |
|
177 | if packed.len() != expected_size { |
@@ -1,11 +1,14 | |||||
1 | use std::collections::BTreeMap; |
|
1 | use bytes_cast::BytesCast; | |
2 | use std::path::PathBuf; |
|
2 | use std::path::PathBuf; | |
|
3 | use std::{collections::BTreeMap, convert::TryInto}; | |||
3 |
|
4 | |||
4 | use super::path_with_basename::WithBasename; |
|
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 | use crate::dirstate::parsers::parse_dirstate_entries; |
|
9 | use crate::dirstate::parsers::parse_dirstate_entries; | |
6 | use crate::dirstate::parsers::parse_dirstate_parents; |
|
10 | use crate::dirstate::parsers::parse_dirstate_parents; | |
7 | use crate::dirstate::parsers::Timestamp; |
|
11 | use crate::dirstate::parsers::Timestamp; | |
8 |
|
||||
9 | use crate::matchers::Matcher; |
|
12 | use crate::matchers::Matcher; | |
10 | use crate::revlog::node::NULL_NODE; |
|
13 | use crate::revlog::node::NULL_NODE; | |
11 | use crate::utils::hg_path::{HgPath, HgPathBuf}; |
|
14 | use crate::utils::hg_path::{HgPath, HgPathBuf}; | |
@@ -327,11 +330,38 impl super::dispatch::DirstateMapMethods | |||||
327 |
|
330 | |||
328 | fn pack( |
|
331 | fn pack( | |
329 | &mut self, |
|
332 | &mut self, | |
330 |
|
|
333 | parents: DirstateParents, | |
331 |
|
|
334 | now: Timestamp, | |
332 | ) -> Result<Vec<u8>, DirstateError> { |
|
335 | ) -> Result<Vec<u8>, DirstateError> { | |
333 | let _ = self.iter_node_data_mut(); |
|
336 | // Optizimation (to be measured?): pre-compute size to avoid `Vec` | |
334 | todo!() |
|
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 | fn build_file_fold_map(&mut self) -> &FastHashMap<HgPathBuf, HgPathBuf> { |
|
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