Skip to content

Commit 79aeb3b

Browse files
committed
perf: Reduce allocations in file hash computation
Deduplicate range-bound string allocations in get_package_hashes — compute format!("{}/", prefix) and format!("{}0", prefix) once instead of twice per call (once for ls_tree, once for status). Also compare using str slices instead of constructing RelativeUnixPathBuf wrappers for the range bounds. Use HashMap::entry API in calculate_file_hashes dedup loop to avoid cloning the HashKey on cache hits. Previously, the key was constructed, looked up with get(), and on miss cloned again for insert + push. Now the entry API does one lookup and only clones into unique_keys on miss.
1 parent fecc400 commit 79aeb3b

File tree

2 files changed

+24
-13
lines changed

2 files changed

+24
-13
lines changed

crates/turborepo-scm/src/repo_index.rs

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -190,19 +190,30 @@ impl RepoGitIndex {
190190
let prefix_str = pkg_prefix.as_str();
191191
let prefix_is_empty = prefix_str.is_empty();
192192

193+
// Compute range bounds once for both ls_tree and status lookups
194+
let range_start;
195+
let range_end;
196+
if !prefix_is_empty {
197+
range_start = format!("{}/", prefix_str);
198+
range_end = format!("{}0", prefix_str);
199+
} else {
200+
range_start = String::new();
201+
range_end = String::new();
202+
}
203+
193204
let mut hashes = if prefix_is_empty {
194205
let mut h = GitHashes::with_capacity(self.ls_tree_hashes.len());
195206
for (path, hash) in &self.ls_tree_hashes {
196207
h.insert(path.clone(), *hash);
197208
}
198209
h
199210
} else {
200-
let range_start = RelativeUnixPathBuf::new(format!("{}/", prefix_str)).unwrap();
201-
let range_end = RelativeUnixPathBuf::new(format!("{}0", prefix_str)).unwrap();
202211
let lo = self
203212
.ls_tree_hashes
204-
.partition_point(|(k, _)| *k < range_start);
205-
let hi = self.ls_tree_hashes.partition_point(|(k, _)| *k < range_end);
213+
.partition_point(|(k, _)| k.as_str() < range_start.as_str());
214+
let hi = self
215+
.ls_tree_hashes
216+
.partition_point(|(k, _)| k.as_str() < range_end.as_str());
206217
let mut h = GitHashes::with_capacity(hi - lo);
207218
for (path, hash) in &self.ls_tree_hashes[lo..hi] {
208219
if let Ok(stripped) = path.strip_prefix(pkg_prefix) {
@@ -216,12 +227,12 @@ impl RepoGitIndex {
216227
let status_entries = if prefix_is_empty {
217228
&self.status_entries[..]
218229
} else {
219-
let range_start = RelativeUnixPathBuf::new(format!("{}/", prefix_str)).unwrap();
220-
let range_end = RelativeUnixPathBuf::new(format!("{}0", prefix_str)).unwrap();
221230
let lo = self
222231
.status_entries
223-
.partition_point(|e| e.path < range_start);
224-
let hi = self.status_entries.partition_point(|e| e.path < range_end);
232+
.partition_point(|e| e.path.as_str() < range_start.as_str());
233+
let hi = self
234+
.status_entries
235+
.partition_point(|e| e.path.as_str() < range_end.as_str());
225236
&self.status_entries[lo..hi]
226237
};
227238
for entry in status_entries {

crates/turborepo-task-hash/src/lib.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -155,12 +155,12 @@ impl PackageInputsHashes {
155155
info.inputs.globs.clone(),
156156
info.inputs.default,
157157
);
158-
let idx = match key_indices.get(&key) {
159-
Some(&idx) => idx,
160-
None => {
158+
let idx = match key_indices.entry(key) {
159+
std::collections::hash_map::Entry::Occupied(e) => *e.get(),
160+
std::collections::hash_map::Entry::Vacant(e) => {
161161
let idx = unique_keys.len();
162-
key_indices.insert(key.clone(), idx);
163-
unique_keys.push(key);
162+
unique_keys.push(e.key().clone());
163+
e.insert(idx);
164164
idx
165165
}
166166
};

0 commit comments

Comments
 (0)