mirror of
https://github.com/martinvonz/jj.git
synced 2025-01-06 05:04:18 +00:00
working_copy: Add is_file_states_sorted
to tree state proto
See #2651 and a935a4f70c
for more
background.
This speeds up `jj log` in a large repo with watchman enabled by around
9%:
```
$ hyperfine --sort command --warmup 3 --runs 20 -L bin \
jj-before,jj-after "target/release/{bin} -R ~/chromiumjj/src log"
Benchmark 1: target/release/jj-before -R ~/chromiumjj/src log
Time (mean ± σ): 788.3 ms ± 3.4 ms [User: 618.6 ms, System: 168.8 ms]
Range (min … max): 783.1 ms … 793.3 ms 20 runs
Benchmark 2: target/release/jj-after -R ~/chromiumjj/src log
Time (mean ± σ): 713.4 ms ± 5.2 ms [User: 536.1 ms, System: 176.2 ms]
Range (min … max): 706.6 ms … 724.7 ms 20 runs
Relative speed comparison
1.11 ± 0.01 target/release/jj-before -R ~/chromiumjj/src log
1.00 target/release/jj-after -R ~/chromiumjj/src log
```
This commit is contained in:
parent
404f31cbc1
commit
458580cee2
3 changed files with 19 additions and 9 deletions
|
@ -149,13 +149,17 @@ impl FileStatesMap {
|
|||
FileStatesMap { data: Vec::new() }
|
||||
}
|
||||
|
||||
// TODO: skip sorting if the data is known to be sorted?
|
||||
fn from_proto_unsorted(mut data: Vec<crate::protos::working_copy::FileStateEntry>) -> Self {
|
||||
data.sort_unstable_by(|entry1, entry2| {
|
||||
let path1 = RepoPath::from_internal_string(&entry1.path);
|
||||
let path2 = RepoPath::from_internal_string(&entry2.path);
|
||||
path1.cmp(path2)
|
||||
});
|
||||
fn from_proto(
|
||||
mut data: Vec<crate::protos::working_copy::FileStateEntry>,
|
||||
is_sorted: bool,
|
||||
) -> Self {
|
||||
if !is_sorted {
|
||||
data.sort_unstable_by(|entry1, entry2| {
|
||||
let path1 = RepoPath::from_internal_string(&entry1.path);
|
||||
let path2 = RepoPath::from_internal_string(&entry2.path);
|
||||
path1.cmp(path2)
|
||||
});
|
||||
}
|
||||
debug_assert!(is_file_state_entries_proto_unique_and_sorted(&data));
|
||||
FileStatesMap { data }
|
||||
}
|
||||
|
@ -610,7 +614,8 @@ impl TreeState {
|
|||
.collect();
|
||||
self.tree_id = MergedTreeId::Merge(tree_ids_builder.build());
|
||||
}
|
||||
self.file_states = FileStatesMap::from_proto_unsorted(proto.file_states);
|
||||
self.file_states =
|
||||
FileStatesMap::from_proto(proto.file_states, proto.is_file_states_sorted);
|
||||
self.sparse_patterns = sparse_patterns_from_proto(proto.sparse_patterns.as_ref());
|
||||
self.watchman_clock = proto.watchman_clock;
|
||||
Ok(())
|
||||
|
@ -630,6 +635,8 @@ impl TreeState {
|
|||
}
|
||||
|
||||
proto.file_states = self.file_states.data.clone();
|
||||
// `FileStatesMap` is guaranteed to be sorted.
|
||||
proto.is_file_states_sorted = true;
|
||||
let mut sparse_patterns = crate::protos::working_copy::SparsePatterns::default();
|
||||
for path in &self.sparse_patterns {
|
||||
sparse_patterns
|
||||
|
@ -1899,7 +1906,7 @@ mod tests {
|
|||
new_proto_entry("b/e", 3),
|
||||
new_proto_entry("bc", 5),
|
||||
];
|
||||
let mut file_states = FileStatesMap::from_proto_unsorted(data);
|
||||
let mut file_states = FileStatesMap::from_proto(data, false);
|
||||
|
||||
let changed_file_states = vec![
|
||||
new_owned_entry("aa", 10), // change
|
||||
|
|
|
@ -47,6 +47,7 @@ message TreeState {
|
|||
// single (positive) value
|
||||
repeated bytes tree_ids = 5;
|
||||
repeated FileStateEntry file_states = 2;
|
||||
bool is_file_states_sorted = 6;
|
||||
SparsePatterns sparse_patterns = 3;
|
||||
WatchmanClock watchman_clock = 4;
|
||||
}
|
||||
|
|
|
@ -38,6 +38,8 @@ pub struct TreeState {
|
|||
pub tree_ids: ::prost::alloc::vec::Vec<::prost::alloc::vec::Vec<u8>>,
|
||||
#[prost(message, repeated, tag = "2")]
|
||||
pub file_states: ::prost::alloc::vec::Vec<FileStateEntry>,
|
||||
#[prost(bool, tag = "6")]
|
||||
pub is_file_states_sorted: bool,
|
||||
#[prost(message, optional, tag = "3")]
|
||||
pub sparse_patterns: ::core::option::Option<SparsePatterns>,
|
||||
#[prost(message, optional, tag = "4")]
|
||||
|
|
Loading…
Reference in a new issue