Commit

A last-commits walk answers within 2.5 s with what it has, and keeps only finished answers

syntaqxcommitted Parent763ad40Browse files
2 files+25−70/2 viewed
+15−6
8888 }
8989
9090 /// The last commit of each entry of `path` at `git_ref`, and whether every
91−/// entry was given one.
92−pub async fn last_commits<R: GitRepo>(repo: &R, git_ref: &str, path: &str) -> Result<(Vec<LastCommit>, bool)> {
91+/// entry was given one. `out_of_time` is asked between batches; once it
92+/// says so the walk stops with what it has, incomplete.
93+pub async fn last_commits<R: GitRepo>(
94+ repo: &R,
95+ git_ref: &str,
96+ path: &str,
97+ out_of_time: &dyn Fn() -> bool,
98+) -> Result<(Vec<LastCommit>, bool)> {
9399 let history = repo.log(git_ref, MAX_COMMITS).await?;
94100 let Some(head) = history.first() else {
95101 return Ok((Vec::new(), true));
105111 break;
106112 }
107113 if index % READ_AHEAD == 0 {
114+ if index > 0 && out_of_time() {
115+ break;
116+ }
108117 let ahead = history.iter().skip(index + 1).take(READ_AHEAD).map(|commit| commit.tree_hash.clone()).collect();
109118 trees.prefetch_dirs(ahead, path).await?;
110119 }
219228
220229 #[test]
221230 fn each_root_entry_gets_the_newest_commit_that_changed_it() {
222− let (found, complete) = run(last_commits(&repo(), "main", "")).unwrap();
231+ let (found, complete) = run(last_commits(&repo(), "main", "", &|| false)).unwrap();
223232 assert!(complete);
224233 let found = by_name(found);
225234 assert_eq!(found["README.md"], "c3");
228237
229238 #[test]
230239 fn a_subdirectory_is_walked_by_its_own_tree() {
231− let (found, complete) = run(last_commits(&repo(), "main", "src")).unwrap();
240+ let (found, complete) = run(last_commits(&repo(), "main", "src", &|| false)).unwrap();
232241 assert!(complete);
233242 assert_eq!(by_name(found)["a.rs"], "c2");
234243 }
238247 let mut fake = repo();
239248 fake.trees.insert("root2".into(), vec![entry("README.md", "r1", EntryKind::Blob), entry("src", "src1", EntryKind::Tree)]);
240249 fake.trees.insert("root3".into(), vec![entry("README.md", "r2", EntryKind::Blob), entry("src", "src1", EntryKind::Tree)]);
241− let (found, complete) = run(last_commits(&fake, "main", "")).unwrap();
250+ let (found, complete) = run(last_commits(&fake, "main", "", &|| false)).unwrap();
242251 assert!(complete);
243252 assert_eq!(by_name(found)["src"], "c1");
244253 }
250259 fake.history[2].parents = vec!["c0".into()];
251260 fake.trees.insert("root2".into(), vec![entry("README.md", "r1", EntryKind::Blob), entry("src", "src1", EntryKind::Tree)]);
252261 fake.trees.insert("root3".into(), vec![entry("README.md", "r2", EntryKind::Blob), entry("src", "src1", EntryKind::Tree)]);
253− let (found, complete) = run(last_commits(&fake, "main", "")).unwrap();
262+ let (found, complete) = run(last_commits(&fake, "main", "", &|| false)).unwrap();
254263 assert!(!complete);
255264 let found = by_name(found);
256265 assert_eq!(found["README.md"], "c3");
+10−1
6060 const MAX_ANCESTRY: u32 = 1000;
6161 /// The most tags a repository's Tags page reads and lists.
6262 const MAX_TAGS_READ: usize = 100;
63+/// How long a last-commits walk may take before it answers with what it has.
64+const LAST_COMMITS_BUDGET_MS: u64 = 2_500;
6365
6466 /// One path segment, percent-encoded for a cache key.
6567 fn urlencoding_segment(segment: &str) -> String {
770772 return Ok(Outcome::Ok(found));
771773 }
772774 }
773− let (entries, complete) = last_commits::last_commits(&git, &head.hash, &a.tree_path).await?;
775+ // A page waits on this: past the budget, what was found so far, not kept.
776+ let started = worker::Date::now().as_millis();
777+ let out_of_time = move || worker::Date::now().as_millis().saturating_sub(started) > LAST_COMMITS_BUDGET_MS;
778+ let (entries, complete) = last_commits::last_commits(&git, &head.hash, &a.tree_path, &out_of_time).await?;
779+ let stopped = out_of_time();
774780 let found = g1t_contracts::repos::LastCommits { entries, complete };
781+ if stopped && !found.complete {
782+ return Ok(Outcome::Ok(found));
783+ }
775784 if let Ok(mut response) = worker::Response::from_json(&found) {
776785 let _ = response.headers_mut().set("cache-control", "max-age=604800");
777786 let _ = cache.put(key.as_str(), response).await;