mirror of
https://github.com/facebook/sapling.git
synced 2024-10-10 08:47:12 +03:00
vfs: move conflict handling from pyworker to vfs write
Summary: Previously, `write` can fail because the destination file exists as a directory, or the parent directory is missing. pyworker handles those cases by calling `clear_conflicts` to remove conflicted directories and create missing parent directories and retry `write`. Practically, for all `write` usecases (including checkout) we always want the `clear_conflicts` behavior. Therefore, move `clear_conflicts` to vfs `write` and make it private. Reviewed By: quark-zju Differential Revision: D26257829 fbshipit-source-id: 03d1da0767202edba61c47ae5654847c0ea3b33e
This commit is contained in:
parent
d9232f1db3
commit
14064f8582
@ -151,25 +151,7 @@ fn update(state: &WriterState, key: Key, flag: Option<UpdateFlag>) -> Result<usi
|
||||
|
||||
let content = redact_if_needed(content);
|
||||
|
||||
// Fast path: let's try to open the file directly, we'll handle the failure only if this fails.
|
||||
match state.working_copy.write(&key.path, &content, flag) {
|
||||
Ok(size) => Ok(size),
|
||||
Err(e) => {
|
||||
// Ideally, we shouldn't need to retry for some failures, but this is the slow path, any
|
||||
// failures not due to a conflicting file would show up here again, so let's not worry
|
||||
// about it.
|
||||
state
|
||||
.working_copy
|
||||
.clear_conflicts(&key.path)
|
||||
.with_context(|| {
|
||||
format!("Can't clear conflicts after handling error \"{:?}\"", e)
|
||||
})?;
|
||||
state
|
||||
.working_copy
|
||||
.write(&key.path, &content, flag)
|
||||
.with_context(|| format!("Can't write after handling error \"{:?}\"", e))
|
||||
}
|
||||
}
|
||||
state.working_copy.write(&key.path, &content, flag)
|
||||
}
|
||||
|
||||
fn threaded_writer(
|
||||
|
@ -166,8 +166,6 @@ impl CheckoutPlan {
|
||||
// As of today tokio::fs operations do the same.
|
||||
// Since we do multiple fs calls inside, it is beneficial to 'pack'
|
||||
// all of them into single spawn_blocking.
|
||||
|
||||
// todo - create directories if needed
|
||||
async fn write_file(
|
||||
vfs: &VFS,
|
||||
path: RepoPathBuf,
|
||||
|
@ -181,7 +181,12 @@ impl VFS {
|
||||
|
||||
/// Overwrite the content of the file at `path` with `data`. The number of bytes written on
|
||||
/// disk will be returned.
|
||||
pub fn write(&self, path: &RepoPath, data: &Bytes, flags: Option<UpdateFlag>) -> Result<usize> {
|
||||
fn write_inner(
|
||||
&self,
|
||||
path: &RepoPath,
|
||||
data: &Bytes,
|
||||
flags: Option<UpdateFlag>,
|
||||
) -> Result<usize> {
|
||||
let filepath = self
|
||||
.inner
|
||||
.auditor
|
||||
@ -195,6 +200,26 @@ impl VFS {
|
||||
}
|
||||
}
|
||||
|
||||
/// Overwrite content of the file, try to clear conflicts if attempt fails
|
||||
///
|
||||
/// Return an error if fails to overwrite after clearing conflicts, or if clear conflicts fail
|
||||
pub fn write(&self, path: &RepoPath, data: &Bytes, flag: Option<UpdateFlag>) -> Result<usize> {
|
||||
// Fast path: let's try to open the file directly, we'll handle the failure only if this fails.
|
||||
match self.write_inner(path, data, flag) {
|
||||
Ok(size) => Ok(size),
|
||||
Err(e) => {
|
||||
// Ideally, we shouldn't need to retry for some failures, but this is the slow path, any
|
||||
// failures not due to a conflicting file would show up here again, so let's not worry
|
||||
// about it.
|
||||
self.clear_conflicts(path).with_context(|| {
|
||||
format!("Can't clear conflicts after handling error \"{:?}\"", e)
|
||||
})?;
|
||||
self.write_inner(path, data, flag)
|
||||
.with_context(|| format!("Can't write after handling error \"{:?}\"", e))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_executable(&self, path: &RepoPath, flag: bool) -> Result<()> {
|
||||
let filepath = self
|
||||
.inner
|
||||
|
Loading…
Reference in New Issue
Block a user