working copy: on checkout, move read from store out of write_*() functions

I'd like to read N files ahead from the backend, to avoid serializing
too many server calls on backends that are backed by a server. Moving
the reads a little earlier is a little step towards that.

The `TreeState::write_*()` functions can now be made into free/static
functions if we prefer.
This commit is contained in:
Martin von Zweigbergk 2023-10-29 09:40:54 -07:00 committed by Martin von Zweigbergk
parent 084b99e1e2
commit 65bd5cacba

View file

@ -992,8 +992,7 @@ impl TreeState {
fn write_file( fn write_file(
&self, &self,
disk_path: &Path, disk_path: &Path,
path: &RepoPath, contents: &mut dyn Read,
id: &FileId,
executable: bool, executable: bool,
) -> Result<FileState, CheckoutError> { ) -> Result<FileState, CheckoutError> {
let mut file = OpenOptions::new() let mut file = OpenOptions::new()
@ -1004,8 +1003,7 @@ impl TreeState {
message: format!("Failed to open file {} for writing", disk_path.display()), message: format!("Failed to open file {} for writing", disk_path.display()),
err: err.into(), err: err.into(),
})?; })?;
let mut contents = self.store.read_file(path, id)?; let size = std::io::copy(contents, &mut file).map_err(|err| CheckoutError::Other {
let size = std::io::copy(&mut contents, &mut file).map_err(|err| CheckoutError::Other {
message: format!("Failed to write file {}", disk_path.display()), message: format!("Failed to write file {}", disk_path.display()),
err: err.into(), err: err.into(),
})?; })?;
@ -1021,16 +1019,10 @@ impl TreeState {
} }
#[cfg_attr(windows, allow(unused_variables))] #[cfg_attr(windows, allow(unused_variables))]
fn write_symlink( fn write_symlink(&self, disk_path: &Path, target: String) -> Result<FileState, CheckoutError> {
&self,
disk_path: &Path,
path: &RepoPath,
id: &SymlinkId,
) -> Result<FileState, CheckoutError> {
let target = self.store.read_symlink(path, id)?;
#[cfg(windows)] #[cfg(windows)]
{ {
println!("ignoring symlink at {:?}", path); println!("ignoring symlink at {}", disk_path.display());
} }
#[cfg(unix)] #[cfg(unix)]
{ {
@ -1053,8 +1045,7 @@ impl TreeState {
fn write_conflict( fn write_conflict(
&self, &self,
disk_path: &Path, disk_path: &Path,
path: &RepoPath, conflict_data: Vec<u8>,
conflict: &MergedTreeValue,
) -> Result<FileState, CheckoutError> { ) -> Result<FileState, CheckoutError> {
let mut file = OpenOptions::new() let mut file = OpenOptions::new()
.write(true) .write(true)
@ -1064,10 +1055,6 @@ impl TreeState {
message: format!("Failed to open file {} for writing", disk_path.display()), message: format!("Failed to open file {} for writing", disk_path.display()),
err: err.into(), err: err.into(),
})?; })?;
let mut conflict_data = vec![];
conflicts::materialize(conflict, self.store.as_ref(), path, &mut conflict_data)
.block_on()
.expect("Failed to materialize conflict to in-memory buffer");
file.write_all(&conflict_data) file.write_all(&conflict_data)
.map_err(|err| CheckoutError::Other { .map_err(|err| CheckoutError::Other {
message: format!("Failed to write conflict to file {}", disk_path.display()), message: format!("Failed to write conflict to file {}", disk_path.display()),
@ -1197,9 +1184,13 @@ impl TreeState {
Ok(Some(after)) => { Ok(Some(after)) => {
let file_state = match after { let file_state = match after {
TreeValue::File { id, executable } => { TreeValue::File { id, executable } => {
self.write_file(&disk_path, &path, &id, executable)? let mut contents = self.store.read_file(&path, &id)?;
self.write_file(&disk_path, &mut contents, executable)?
}
TreeValue::Symlink(id) => {
let target = self.store.read_symlink(&path, &id)?;
self.write_symlink(&disk_path, target)?
} }
TreeValue::Symlink(id) => self.write_symlink(&disk_path, &path, &id)?,
TreeValue::Conflict(_) => { TreeValue::Conflict(_) => {
panic!("unexpected conflict entry in diff at {path:?}"); panic!("unexpected conflict entry in diff at {path:?}");
} }
@ -1214,7 +1205,16 @@ impl TreeState {
self.file_states.insert(path, file_state); self.file_states.insert(path, file_state);
} }
Err(after_conflict) => { Err(after_conflict) => {
let file_state = self.write_conflict(&disk_path, &path, &after_conflict)?; let mut conflict_data = vec![];
conflicts::materialize(
&after_conflict,
self.store.as_ref(),
&path,
&mut conflict_data,
)
.block_on()
.expect("Failed to materialize conflict to in-memory buffer");
let file_state = self.write_conflict(&disk_path, conflict_data)?;
self.file_states.insert(path, file_state); self.file_states.insert(path, file_state);
} }
} }