chadtmiller.com/knotless
git that lives in your Atmosphere account
1
10
Diffs are read four at a time, highlighted off the async threads
crates/knotless-serve/src/web.rs+21−8
| @@ -3134,10 +3134,16 @@ fn row(r: diff::Row) -> DiffRowView { | ||
} | ||
} | ||
| ||
/// How many diffs are read at once, git's patch and blobs and the | ||
/// highlighting of their rows: the rest wait their turn. A crawler walking | ||
/// commit and pull pages asks for dozens together, which, run at once, | ||
/// held every other request's answer up for tens of seconds. | ||
static DIFFING: tokio::sync::Semaphore = tokio::sync::Semaphore::const_new(4); | ||
| ||
/// What `git <verb> <rev>` prints as a patch of `paths` (all, if none), | ||
/// read into files in the order an editor's file tree lists them, with | ||
/// their rows as `rows` says: a file without is neither highlighted nor | ||
/// has its blobs read. | ||
/// has its blobs read. At most [`DIFFING`] are read at once. | ||
async fn files( | ||
git: &Git, | ||
verb: &[&str], | ||
| @@ -3145,6 +3151,7 @@ async fn files( | ||
paths: &[&str], | ||
rows: Rows, | ||
) -> Result<Vec<FileDiffView>> { | ||
let _turn = DIFFING.acquire().await.expect("never closed"); | ||
let mut args = vec!["-c", "core.quotePath=false"]; | ||
args.extend(verb); | ||
args.extend([ | ||
| @@ -3172,13 +3179,19 @@ async fn files( | ||
.filter_map(|oid| oid.as_deref()) | ||
.collect(); | ||
let texts = texts(git, &shown).await; | ||
// Each listed, and those with their rows drawn in its place. | ||
let mut out: Vec<FileDiffView> = parsed.iter().map(listed).collect(); | ||
let picked = parsed.into_iter().zip(with).enumerate(); | ||
for (i, (f, _)) in picked.filter(|(_, (_, with))| *with) { | ||
out[i] = file_diff(f, &texts); | ||
} | ||
Ok(out) | ||
// Each listed, and those with their rows drawn in its place, off the | ||
// async threads: highlighting parses the whole of each side, a good | ||
// part of a second for a long file, and on them it would hold up every | ||
// other request, and the reading of git's output, until it was done. | ||
let drawn = tokio::task::spawn_blocking(move || { | ||
let mut out: Vec<FileDiffView> = parsed.iter().map(listed).collect(); | ||
let picked = parsed.into_iter().zip(with).enumerate(); | ||
for (i, (f, _)) in picked.filter(|(_, (_, with))| *with) { | ||
out[i] = file_diff(f, &texts); | ||
} | ||
out | ||
}); | ||
Ok(drawn.await.expect("drawing a diff does not panic")) | ||
} | ||
| ||
/// Which of `files` a pull's files page draws with their rows at once: | ||
docs/design/serve.md+14−1
| @@ -807,7 +807,10 @@ Discord's, is not held to it, as someone shared that link. | ||
| ||
A crawler that calls itself a browser is not caught, and each request's | ||
log line names its client (`user_agent.original`), so they can be told | ||
apart. | ||
apart. What its pages cost is bounded instead: the diffs of commit and | ||
pull pages, the dearest it can ask for, are read a few at a time (see | ||
[Highlighting and diffs](#highlighting-and-diffs)), as blames and | ||
archives are ([Git and the object API](#git-and-the-object-api)). | ||
| ||
Crawlers and old browsers ask for `/favicon.ico` whatever a page names | ||
as its icon. Handed to the pages, it would be drawn as the profile of a | ||
| @@ -1621,6 +1624,16 @@ browser fetches the rest from `getCommit` with `paths`, ten at a time, as | ||
each nears the screen. A commit that touches hundreds of files is otherwise | ||
an answer of megabytes, read, highlighted and drawn before any of it shows. | ||
| ||
At most four diffs are read at once, of commits, pulls and compares | ||
together: git's patch, the blobs of the files drawn with their rows, and | ||
their highlighting, which runs off the server's async threads. The rest | ||
wait their turn. A crawler posing as browsers once asked for about a | ||
hundred commit and pull diffs in a minute: sixty git processes ran at | ||
once on the server's two cores, and highlighting on the async threads | ||
held every other answer up behind them, a profile or a tree as much as a | ||
commit, for seconds and up to half a minute. Now such a burst waits on | ||
itself, and the rest of the site answers as before. | ||
| ||
A diff shows each hunk with three lines around it; the rest of a file | ||
changed in place is left out. A pull's, a commit's and a compare's files can | ||
show more: the arrows in a hunk's header put back 20 lines at a time from | ||