ok/jj
1
0
Fork 0
forked from mirrors/jj

cli: read files concurrently when diffing

Same reasoning as in the previous patch - this should help
high-latency backends.
This commit is contained in:
Martin von Zweigbergk 2023-11-09 16:57:14 -08:00 committed by Martin von Zweigbergk
parent 90744fb770
commit 0d02724341

View file

@ -17,9 +17,9 @@ use std::collections::VecDeque;
use std::io; use std::io;
use std::ops::Range; use std::ops::Range;
use futures::StreamExt; use futures::{try_join, Stream, StreamExt};
use itertools::Itertools; use itertools::Itertools;
use jj_lib::backend::{ObjectId, TreeValue}; use jj_lib::backend::{BackendResult, ObjectId, TreeValue};
use jj_lib::commit::Commit; use jj_lib::commit::Commit;
use jj_lib::conflicts::{materialize_tree_value, MaterializedTreeValue}; use jj_lib::conflicts::{materialize_tree_value, MaterializedTreeValue};
use jj_lib::diff::{Diff, DiffHunk}; use jj_lib::diff::{Diff, DiffHunk};
@ -28,8 +28,9 @@ use jj_lib::matchers::Matcher;
use jj_lib::merge::MergedTreeValue; use jj_lib::merge::MergedTreeValue;
use jj_lib::merged_tree::{MergedTree, TreeDiffStream}; use jj_lib::merged_tree::{MergedTree, TreeDiffStream};
use jj_lib::repo::Repo; use jj_lib::repo::Repo;
use jj_lib::repo_path::RepoPath; use jj_lib::repo_path::{RepoPath, RepoPathBuf};
use jj_lib::settings::{ConfigResultExt as _, UserSettings}; use jj_lib::settings::{ConfigResultExt as _, UserSettings};
use jj_lib::store::Store;
use jj_lib::{diff, files, rewrite}; use jj_lib::{diff, files, rewrite};
use pollster::FutureExt; use pollster::FutureExt;
use tracing::instrument; use tracing::instrument;
@ -384,16 +385,14 @@ fn basic_diff_file_type(value: &MaterializedTreeValue) -> &'static str {
pub fn show_color_words_diff( pub fn show_color_words_diff(
formatter: &mut dyn Formatter, formatter: &mut dyn Formatter,
workspace_command: &WorkspaceCommandHelper, workspace_command: &WorkspaceCommandHelper,
mut tree_diff: TreeDiffStream, tree_diff: TreeDiffStream,
) -> Result<(), CommandError> { ) -> Result<(), CommandError> {
let store = workspace_command.repo().store();
formatter.push_label("diff")?; formatter.push_label("diff")?;
let mut diff_stream = materialized_diff_stream(workspace_command.repo().store(), tree_diff);
async { async {
while let Some((path, diff)) = tree_diff.next().await { while let Some((path, diff)) = diff_stream.next().await {
let ui_path = workspace_command.format_file_path(&path); let ui_path = workspace_command.format_file_path(&path);
let (left_value, right_value) = diff?; let (left_value, right_value) = diff?;
let left_value = materialize_tree_value(store, &path, left_value).block_on()?;
let right_value = materialize_tree_value(store, &path, right_value).block_on()?;
if left_value.is_absent() { if left_value.is_absent() {
let description = basic_diff_file_type(&right_value); let description = basic_diff_file_type(&right_value);
writeln!( writeln!(
@ -677,19 +676,42 @@ fn show_unified_diff_hunks(
Ok(()) Ok(())
} }
fn materialized_diff_stream<'a>(
store: &'a Store,
tree_diff: TreeDiffStream<'a>,
) -> impl Stream<
Item = (
RepoPathBuf,
BackendResult<(MaterializedTreeValue, MaterializedTreeValue)>,
),
> + 'a {
tree_diff
.map(|(path, diff)| async {
match diff {
Err(err) => (path, Err(err)),
Ok((before, after)) => {
let before_future = materialize_tree_value(store, &path, before);
let after_future = materialize_tree_value(store, &path, after);
let values = try_join!(before_future, after_future);
(path, values)
}
}
})
.buffered((store.concurrency() / 2).max(1))
}
pub fn show_git_diff( pub fn show_git_diff(
formatter: &mut dyn Formatter, formatter: &mut dyn Formatter,
workspace_command: &WorkspaceCommandHelper, workspace_command: &WorkspaceCommandHelper,
mut tree_diff: TreeDiffStream, tree_diff: TreeDiffStream,
) -> Result<(), CommandError> { ) -> Result<(), CommandError> {
let store = workspace_command.repo().store();
formatter.push_label("diff")?; formatter.push_label("diff")?;
let mut diff_stream = materialized_diff_stream(workspace_command.repo().store(), tree_diff);
async { async {
while let Some((path, diff)) = tree_diff.next().await { while let Some((path, diff)) = diff_stream.next().await {
let path_string = path.as_internal_file_string(); let path_string = path.as_internal_file_string();
let (left_value, right_value) = diff?; let (left_value, right_value) = diff?;
let left_value = materialize_tree_value(store, &path, left_value).block_on()?;
let right_value = materialize_tree_value(store, &path, right_value).block_on()?;
if left_value.is_absent() { if left_value.is_absent() {
let right_part = git_diff_part(&path, right_value)?; let right_part = git_diff_part(&path, right_value)?;
formatter.with_label("file_header", |formatter| { formatter.with_label("file_header", |formatter| {
@ -810,18 +832,16 @@ pub fn show_diff_stat(
ui: &Ui, ui: &Ui,
formatter: &mut dyn Formatter, formatter: &mut dyn Formatter,
workspace_command: &WorkspaceCommandHelper, workspace_command: &WorkspaceCommandHelper,
mut tree_diff: TreeDiffStream, tree_diff: TreeDiffStream,
) -> Result<(), CommandError> { ) -> Result<(), CommandError> {
let mut stats: Vec<DiffStat> = vec![]; let mut stats: Vec<DiffStat> = vec![];
let mut max_path_width = 0; let mut max_path_width = 0;
let mut max_diffs = 0; let mut max_diffs = 0;
let store = workspace_command.repo().store(); let mut diff_stream = materialized_diff_stream(workspace_command.repo().store(), tree_diff);
async { async {
while let Some((repo_path, diff)) = tree_diff.next().await { while let Some((repo_path, diff)) = diff_stream.next().await {
let (left, right) = diff?; let (left, right) = diff?;
let left = materialize_tree_value(store, &repo_path, left).block_on()?;
let right = materialize_tree_value(store, &repo_path, right).block_on()?;
let path = workspace_command.format_file_path(&repo_path); let path = workspace_command.format_file_path(&repo_path);
let left_content = diff_content(&repo_path, left)?; let left_content = diff_content(&repo_path, left)?;
let right_content = diff_content(&repo_path, right)?; let right_content = diff_content(&repo_path, right)?;