mirror of
https://github.com/gitbutlerapp/gitbutler.git
synced 2024-08-17 08:10:52 +03:00
enforce filesystem-synchronization during worktree updates and prolonged reads
That way it's assured that reads and writes don't intersect, but assure we only hold such lock for the shortest amount of time for reads and and for the full duration of writes.
This commit is contained in:
parent
b3b87b34a5
commit
d7948db628
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -2175,6 +2175,7 @@ name = "gitbutler-project"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"fslock",
|
||||
"git2",
|
||||
"gitbutler-error",
|
||||
"gitbutler-id",
|
||||
|
@ -43,6 +43,7 @@ serde = { version = "1.0", features = ["derive"] }
|
||||
thiserror = "1.0.61"
|
||||
tokio = { version = "1.38.0", default-features = false }
|
||||
keyring = "2.3.3"
|
||||
fslock = "0.2.1"
|
||||
anyhow = "1.0.86"
|
||||
|
||||
gitbutler-id = { path = "crates/gitbutler-id" }
|
||||
|
@ -5,8 +5,7 @@ use gitbutler_branch::{
|
||||
use gitbutler_command_context::ProjectRepository;
|
||||
use gitbutler_oplog::{
|
||||
entry::{OperationKind, SnapshotDetails},
|
||||
oplog::OplogExt,
|
||||
snapshot::SnapshotExt,
|
||||
OplogExt, SnapshotExt,
|
||||
};
|
||||
use gitbutler_project::{FetchResult, Project};
|
||||
use gitbutler_reference::ReferenceName;
|
||||
|
@ -11,7 +11,7 @@ use gitbutler_branch::{
|
||||
};
|
||||
use gitbutler_commit::commit_headers::HasCommitHeaders;
|
||||
use gitbutler_error::error::Marker;
|
||||
use gitbutler_oplog::snapshot::SnapshotExt;
|
||||
use gitbutler_oplog::SnapshotExt;
|
||||
use gitbutler_reference::Refname;
|
||||
use gitbutler_repo::{rebase::cherry_rebase, RepoActionsExt, RepositoryExt};
|
||||
use gitbutler_time::time::now_since_unix_epoch_ms;
|
||||
|
@ -8,7 +8,7 @@ use anyhow::{anyhow, Context, Result};
|
||||
use git2::build::TreeUpdateBuilder;
|
||||
use gitbutler_branch::{Branch, BranchExt, BranchId};
|
||||
use gitbutler_commit::commit_headers::CommitHeadersV2;
|
||||
use gitbutler_oplog::snapshot::SnapshotExt;
|
||||
use gitbutler_oplog::SnapshotExt;
|
||||
use gitbutler_reference::ReferenceName;
|
||||
use gitbutler_reference::{normalize_branch_name, Refname};
|
||||
use gitbutler_repo::{RepoActionsExt, RepositoryExt};
|
||||
|
@ -1,6 +1,6 @@
|
||||
use super::*;
|
||||
use gitbutler_branch::{BranchCreateRequest, VirtualBranchesHandle};
|
||||
use gitbutler_oplog::oplog::OplogExt;
|
||||
use gitbutler_oplog::OplogExt;
|
||||
use itertools::Itertools;
|
||||
use std::io::Write;
|
||||
use std::path::Path;
|
||||
|
@ -1,5 +1,5 @@
|
||||
use anyhow::Result;
|
||||
use gitbutler_oplog::oplog::OplogExt;
|
||||
use gitbutler_oplog::OplogExt;
|
||||
|
||||
use clap::{arg, Command};
|
||||
use gitbutler_project::Project;
|
||||
|
@ -1,7 +1,9 @@
|
||||
pub mod entry;
|
||||
pub mod oplog;
|
||||
mod oplog;
|
||||
pub use oplog::OplogExt;
|
||||
mod reflog;
|
||||
pub mod snapshot;
|
||||
mod snapshot;
|
||||
pub use snapshot::SnapshotExt;
|
||||
mod state;
|
||||
|
||||
/// The name of the file holding our state, useful for watching for changes.
|
||||
|
@ -287,6 +287,7 @@ impl OplogExt for Project {
|
||||
|
||||
#[instrument(skip(details), err(Debug))]
|
||||
fn create_snapshot(&self, details: SnapshotDetails) -> Result<Option<git2::Oid>> {
|
||||
let _lock = self.exclusive_worktree_access()?;
|
||||
let tree_id = self.prepare_snapshot()?;
|
||||
self.commit_snapshot(tree_id, details)
|
||||
}
|
||||
@ -399,6 +400,7 @@ impl OplogExt for Project {
|
||||
let worktree_dir = self.path.as_path();
|
||||
let repo = git2::Repository::open(worktree_dir)?;
|
||||
|
||||
let _lock = self.exclusive_worktree_access()?;
|
||||
let before_restore_snapshot_result = self.prepare_snapshot();
|
||||
let snapshot_commit = repo.find_commit(snapshot_commit_id)?;
|
||||
|
||||
|
@ -7,6 +7,7 @@ publish = false
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.86"
|
||||
fslock.workspace = true
|
||||
serde = { workspace = true, features = ["std"]}
|
||||
serde_json = { version = "1.0", features = [ "std", "arbitrary_precision" ] }
|
||||
gitbutler-error.workspace = true
|
||||
|
@ -118,4 +118,21 @@ impl Project {
|
||||
pub fn worktree_path(&self) -> PathBuf {
|
||||
self.path.clone()
|
||||
}
|
||||
|
||||
/// Return a guard for exclusive worktree access, blocking while waiting for someone else,
|
||||
/// in the same or in a difference process, to release it.
|
||||
/// It's undefined how fair the lock is, and it's also undefined in which order locks are acquired.
|
||||
///
|
||||
/// Note that the kind of lock used cannot go stale, at as long as it's not used on a network drive
|
||||
/// where things might stop working correctly.
|
||||
pub fn exclusive_worktree_access(&self) -> anyhow::Result<WorktreeFileLockGuard> {
|
||||
let mut lock_file =
|
||||
fslock::LockFile::open(self.gb_dir().join("worktree.lock").as_os_str())?;
|
||||
lock_file.lock()?;
|
||||
Ok(WorktreeFileLockGuard(lock_file))
|
||||
}
|
||||
}
|
||||
|
||||
/// Note that the contained `LockFile` unlocks on drop automatically.
|
||||
#[allow(dead_code)]
|
||||
pub struct WorktreeFileLockGuard(fslock::LockFile);
|
||||
|
@ -8,7 +8,7 @@ use gitbutler_branch::VirtualBranchesHandle;
|
||||
use gitbutler_command_context::ProjectRepository;
|
||||
use gitbutler_error::error::Code;
|
||||
use gitbutler_id::id::Id;
|
||||
use gitbutler_oplog::oplog::OplogExt;
|
||||
use gitbutler_oplog::OplogExt;
|
||||
use gitbutler_project as projects;
|
||||
use gitbutler_project::{CodePushState, Project};
|
||||
use gitbutler_reference::Refname;
|
||||
|
@ -26,7 +26,7 @@ anyhow = "1.0.86"
|
||||
backtrace = { version = "0.3.72", optional = true }
|
||||
console-subscriber = "0.2.0"
|
||||
dirs = "5.0.1"
|
||||
fslock = "0.2.1"
|
||||
fslock.workspace = true
|
||||
futures = "0.3"
|
||||
git2.workspace = true
|
||||
once_cell = "1.19"
|
||||
|
@ -2,7 +2,7 @@ use crate::error::Error;
|
||||
use anyhow::Context;
|
||||
use gitbutler_branch::diff::FileDiff;
|
||||
use gitbutler_oplog::entry::Snapshot;
|
||||
use gitbutler_oplog::oplog::OplogExt;
|
||||
use gitbutler_oplog::OplogExt;
|
||||
use gitbutler_project as projects;
|
||||
use gitbutler_project::ProjectId;
|
||||
use std::collections::HashMap;
|
||||
|
@ -7,7 +7,7 @@ use gitbutler_command_context::ProjectRepository;
|
||||
use gitbutler_error::error::Marker;
|
||||
use gitbutler_oplog::{
|
||||
entry::{OperationKind, SnapshotDetails},
|
||||
oplog::OplogExt,
|
||||
OplogExt,
|
||||
};
|
||||
use gitbutler_project as projects;
|
||||
use gitbutler_project::ProjectId;
|
||||
|
Loading…
Reference in New Issue
Block a user