mirror of
https://github.com/martinvonz/jj.git
synced 2024-12-24 12:48:55 +00:00
working_copy: enable storing multiple tree ids in state file
This commit is contained in:
parent
49e32aa532
commit
88e9933462
7 changed files with 64 additions and 36 deletions
|
@ -878,7 +878,7 @@ impl WorkspaceCommandHelper {
|
|||
&mut self,
|
||||
) -> Result<(LockedWorkingCopy, Commit), CommandError> {
|
||||
let (locked_working_copy, wc_commit) = self.unchecked_start_working_copy_mutation()?;
|
||||
if wc_commit.tree_id() != locked_working_copy.old_tree_id() {
|
||||
if wc_commit.merged_tree_id() != locked_working_copy.old_tree_id() {
|
||||
return Err(user_error("Concurrent working copy operation. Try again."));
|
||||
}
|
||||
Ok((locked_working_copy, wc_commit))
|
||||
|
@ -1661,8 +1661,8 @@ pub fn check_stale_working_copy(
|
|||
repo: &ReadonlyRepo,
|
||||
) -> Result<Option<Operation>, StaleWorkingCopyError> {
|
||||
// Check if the working copy's tree matches the repo's view
|
||||
let wc_tree_id = locked_wc.old_tree_id().clone();
|
||||
if *wc_commit.tree_id() == wc_tree_id {
|
||||
let wc_tree_id = locked_wc.old_tree_id();
|
||||
if wc_commit.merged_tree_id() == wc_tree_id {
|
||||
// The working copy isn't stale, and no need to reload the repo.
|
||||
Ok(None)
|
||||
} else {
|
||||
|
|
|
@ -3603,7 +3603,7 @@ fn cmd_workspace_update_stale(
|
|||
Err(_) => {
|
||||
// The same check as start_working_copy_mutation(), but with the stale
|
||||
// working-copy commit.
|
||||
if known_wc_commit.tree_id() != locked_wc.old_tree_id() {
|
||||
if known_wc_commit.merged_tree_id() != locked_wc.old_tree_id() {
|
||||
return Err(user_error("Concurrent working copy operation. Try again."));
|
||||
}
|
||||
let desired_tree = desired_wc_commit.merged_tree()?;
|
||||
|
|
|
@ -524,7 +524,7 @@ diff editing in mind and be a little inaccurate.
|
|||
progress: None,
|
||||
max_new_file_size: settings.max_new_file_size()?,
|
||||
})?;
|
||||
Ok(output_tree_state.current_tree_id().clone())
|
||||
Ok(output_tree_state.current_tree_id().to_legacy_tree_id())
|
||||
}
|
||||
|
||||
/// Generates textual diff by the specified `tool`, and writes into `writer`.
|
||||
|
|
|
@ -37,7 +37,10 @@ message SparsePatterns {
|
|||
}
|
||||
|
||||
message TreeState {
|
||||
bytes tree_id = 1;
|
||||
bytes legacy_tree_id = 1;
|
||||
// Alternating positive and negative terms if there's a conflict, otherwise a
|
||||
// single (positive) value
|
||||
repeated bytes tree_ids = 5;
|
||||
map<string, FileState> file_states = 2;
|
||||
SparsePatterns sparse_patterns = 3;
|
||||
WatchmanClock watchman_clock = 4;
|
||||
|
|
|
@ -22,7 +22,11 @@ pub struct SparsePatterns {
|
|||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct TreeState {
|
||||
#[prost(bytes = "vec", tag = "1")]
|
||||
pub tree_id: ::prost::alloc::vec::Vec<u8>,
|
||||
pub legacy_tree_id: ::prost::alloc::vec::Vec<u8>,
|
||||
/// Alternating positive and negative terms if there's a conflict, otherwise a
|
||||
/// single (positive) value
|
||||
#[prost(bytes = "vec", repeated, tag = "5")]
|
||||
pub tree_ids: ::prost::alloc::vec::Vec<::prost::alloc::vec::Vec<u8>>,
|
||||
#[prost(map = "string, message", tag = "2")]
|
||||
pub file_states: ::std::collections::HashMap<
|
||||
::prost::alloc::string::String,
|
||||
|
|
|
@ -51,7 +51,7 @@ use crate::lock::FileLock;
|
|||
use crate::matchers::{
|
||||
DifferenceMatcher, EverythingMatcher, IntersectionMatcher, Matcher, PrefixMatcher,
|
||||
};
|
||||
use crate::merge::Merge;
|
||||
use crate::merge::{Merge, MergeBuilder};
|
||||
use crate::merged_tree::{MergedTree, MergedTreeBuilder};
|
||||
use crate::op_store::{OperationId, WorkspaceId};
|
||||
use crate::repo_path::{FsPathParseError, RepoPath, RepoPathComponent, RepoPathJoin};
|
||||
|
@ -120,7 +120,7 @@ pub struct TreeState {
|
|||
store: Arc<Store>,
|
||||
working_copy_path: PathBuf,
|
||||
state_path: PathBuf,
|
||||
tree_id: TreeId,
|
||||
tree_id: MergedTreeId,
|
||||
file_states: BTreeMap<RepoPath, FileState>,
|
||||
// Currently only path prefixes
|
||||
sparse_patterns: Vec<RepoPath>,
|
||||
|
@ -428,7 +428,7 @@ impl TreeState {
|
|||
&self.working_copy_path
|
||||
}
|
||||
|
||||
pub fn current_tree_id(&self) -> &TreeId {
|
||||
pub fn current_tree_id(&self) -> &MergedTreeId {
|
||||
&self.tree_id
|
||||
}
|
||||
|
||||
|
@ -462,7 +462,7 @@ impl TreeState {
|
|||
store,
|
||||
working_copy_path: working_copy_path.canonicalize().unwrap(),
|
||||
state_path,
|
||||
tree_id,
|
||||
tree_id: MergedTreeId::Legacy(tree_id.clone()),
|
||||
file_states: BTreeMap::new(),
|
||||
sparse_patterns: vec![RepoPath::root()],
|
||||
own_mtime: MillisSinceEpoch(0),
|
||||
|
@ -516,7 +516,16 @@ impl TreeState {
|
|||
source: err,
|
||||
}
|
||||
})?;
|
||||
self.tree_id = TreeId::new(proto.tree_id.clone());
|
||||
if proto.tree_ids.is_empty() {
|
||||
self.tree_id = MergedTreeId::Legacy(TreeId::new(proto.legacy_tree_id.clone()));
|
||||
} else {
|
||||
let tree_ids_builder: MergeBuilder<TreeId> = proto
|
||||
.tree_ids
|
||||
.iter()
|
||||
.map(|id| TreeId::new(id.clone()))
|
||||
.collect();
|
||||
self.tree_id = MergedTreeId::Merge(tree_ids_builder.build());
|
||||
}
|
||||
self.file_states = file_states_from_proto(&proto);
|
||||
self.sparse_patterns = sparse_patterns_from_proto(&proto);
|
||||
self.watchman_clock = proto.watchman_clock;
|
||||
|
@ -524,10 +533,16 @@ impl TreeState {
|
|||
}
|
||||
|
||||
fn save(&mut self) -> Result<(), TreeStateError> {
|
||||
let mut proto = crate::protos::working_copy::TreeState {
|
||||
tree_id: self.tree_id.to_bytes(),
|
||||
..Default::default()
|
||||
};
|
||||
let mut proto: crate::protos::working_copy::TreeState = Default::default();
|
||||
match &self.tree_id {
|
||||
MergedTreeId::Legacy(tree_id) => {
|
||||
proto.legacy_tree_id = tree_id.to_bytes();
|
||||
}
|
||||
MergedTreeId::Merge(tree_ids) => {
|
||||
proto.tree_ids = tree_ids.iter().map(|id| id.to_bytes()).collect();
|
||||
}
|
||||
}
|
||||
|
||||
for (file, file_state) in &self.file_states {
|
||||
proto.file_states.insert(
|
||||
file.to_internal_file_string(),
|
||||
|
@ -567,8 +582,17 @@ impl TreeState {
|
|||
}
|
||||
|
||||
fn current_tree(&self) -> Result<MergedTree, BackendError> {
|
||||
let tree = self.store.get_tree(&RepoPath::root(), &self.tree_id)?;
|
||||
Ok(MergedTree::legacy(tree))
|
||||
match &self.tree_id {
|
||||
MergedTreeId::Legacy(tree_id) => {
|
||||
let current_tree = self.store.get_tree(&RepoPath::root(), tree_id)?;
|
||||
Ok(MergedTree::legacy(current_tree))
|
||||
}
|
||||
MergedTreeId::Merge(tree_ids) => {
|
||||
let tree_merge =
|
||||
tree_ids.try_map(|tree_id| self.store.get_tree(&RepoPath::root(), tree_id))?;
|
||||
Ok(MergedTree::new(tree_merge))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn write_file_to_store(
|
||||
|
@ -673,10 +697,7 @@ impl TreeState {
|
|||
)
|
||||
})?;
|
||||
|
||||
let mut tree_builder = MergedTreeBuilder::new(
|
||||
self.store.clone(),
|
||||
MergedTreeId::Legacy(self.tree_id.clone()),
|
||||
);
|
||||
let mut tree_builder = MergedTreeBuilder::new(self.store.clone(), self.tree_id.clone());
|
||||
let mut deleted_files: HashSet<_> =
|
||||
trace_span!("collecting existing files").in_scope(|| {
|
||||
self.file_states
|
||||
|
@ -712,11 +733,7 @@ impl TreeState {
|
|||
}
|
||||
});
|
||||
trace_span!("write tree").in_scope(|| {
|
||||
let new_tree_id = tree_builder
|
||||
.write_tree()
|
||||
.unwrap()
|
||||
.as_legacy_tree_id()
|
||||
.clone();
|
||||
let new_tree_id = tree_builder.write_tree().unwrap();
|
||||
is_dirty |= new_tree_id != self.tree_id;
|
||||
self.tree_id = new_tree_id;
|
||||
});
|
||||
|
@ -1177,7 +1194,7 @@ impl TreeState {
|
|||
other => CheckoutError::InternalBackendError(other),
|
||||
})?;
|
||||
let stats = self.update(&old_tree, new_tree, self.sparse_matcher().as_ref(), Err)?;
|
||||
self.tree_id = new_tree.id().to_legacy_tree_id();
|
||||
self.tree_id = new_tree.id();
|
||||
Ok(stats)
|
||||
}
|
||||
|
||||
|
@ -1333,7 +1350,7 @@ impl TreeState {
|
|||
self.file_states.insert(path.clone(), file_state);
|
||||
}
|
||||
}
|
||||
self.tree_id = new_tree.id().to_legacy_tree_id();
|
||||
self.tree_id = new_tree.id();
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -1461,7 +1478,7 @@ impl WorkingCopy {
|
|||
Ok(self.tree_state.get_mut().unwrap())
|
||||
}
|
||||
|
||||
pub fn current_tree_id(&self) -> Result<&TreeId, TreeStateError> {
|
||||
pub fn current_tree_id(&self) -> Result<&MergedTreeId, TreeStateError> {
|
||||
Ok(self.tree_state()?.current_tree_id())
|
||||
}
|
||||
|
||||
|
@ -1516,7 +1533,7 @@ impl WorkingCopy {
|
|||
// regardless, but it's probably not what the caller wanted, so we let
|
||||
// them know.
|
||||
if let Some(old_tree_id) = old_tree_id {
|
||||
if *old_tree_id != locked_wc.old_tree_id {
|
||||
if *old_tree_id != locked_wc.old_tree_id.to_legacy_tree_id() {
|
||||
locked_wc.discard();
|
||||
return Err(CheckoutError::ConcurrentCheckout);
|
||||
}
|
||||
|
@ -1541,7 +1558,7 @@ pub struct LockedWorkingCopy<'a> {
|
|||
#[allow(dead_code)]
|
||||
lock: FileLock,
|
||||
old_operation_id: OperationId,
|
||||
old_tree_id: TreeId,
|
||||
old_tree_id: MergedTreeId,
|
||||
tree_state_dirty: bool,
|
||||
closed: bool,
|
||||
}
|
||||
|
@ -1553,7 +1570,7 @@ impl LockedWorkingCopy<'_> {
|
|||
}
|
||||
|
||||
/// The tree at the time the lock was taken
|
||||
pub fn old_tree_id(&self) -> &TreeId {
|
||||
pub fn old_tree_id(&self) -> &MergedTreeId {
|
||||
&self.old_tree_id
|
||||
}
|
||||
|
||||
|
@ -1569,7 +1586,7 @@ impl LockedWorkingCopy<'_> {
|
|||
pub fn snapshot(&mut self, options: SnapshotOptions) -> Result<TreeId, SnapshotError> {
|
||||
let tree_state = self.wc.tree_state_mut()?;
|
||||
self.tree_state_dirty |= tree_state.snapshot(options)?;
|
||||
Ok(tree_state.current_tree_id().clone())
|
||||
Ok(tree_state.current_tree_id().to_legacy_tree_id())
|
||||
}
|
||||
|
||||
pub fn check_out(&mut self, new_tree: &MergedTree) -> Result<CheckoutStats, CheckoutError> {
|
||||
|
|
|
@ -81,8 +81,12 @@ fn test_concurrent_checkout() {
|
|||
let workspace3 =
|
||||
Workspace::load(&settings, &workspace1_root, &StoreFactories::default()).unwrap();
|
||||
assert_eq!(
|
||||
workspace3.working_copy().current_tree_id().unwrap(),
|
||||
&tree_id2
|
||||
workspace3
|
||||
.working_copy()
|
||||
.current_tree_id()
|
||||
.unwrap()
|
||||
.to_legacy_tree_id(),
|
||||
tree_id2
|
||||
);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue