working_copy: use OnceCell to manage {operation_id, workspace_id}

For consistency with the tree_state handling. This isn't that simple and
concise compared to the tree_state one, so I'm fine to drop the series.

I've extracted {operation_id, workspace_id} pair so these values can be
safely initialized by OnceCell. The extracted struct is named after the
"checkout" file.
This commit is contained in:
Yuya Nishihara 2022-10-02 18:42:20 +09:00 committed by Martin von Zweigbergk
parent a2f750171a
commit c0c1eade91

View file

@ -12,7 +12,6 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
use std::cell::RefCell;
use std::collections::{BTreeMap, HashSet}; use std::collections::{BTreeMap, HashSet};
use std::ffi::OsString; use std::ffi::OsString;
use std::fs; use std::fs;
@ -958,12 +957,18 @@ impl TreeState {
} }
} }
/// Working copy state stored in "checkout" file.
#[derive(Clone, Debug)]
struct CheckoutState {
operation_id: OperationId,
workspace_id: WorkspaceId,
}
pub struct WorkingCopy { pub struct WorkingCopy {
store: Arc<Store>, store: Arc<Store>,
working_copy_path: PathBuf, working_copy_path: PathBuf,
state_path: PathBuf, state_path: PathBuf,
operation_id: RefCell<Option<OperationId>>, checkout_state: OnceCell<CheckoutState>,
workspace_id: RefCell<Option<WorkspaceId>>,
tree_state: OnceCell<TreeState>, tree_state: OnceCell<TreeState>,
} }
@ -991,8 +996,7 @@ impl WorkingCopy {
store, store,
working_copy_path, working_copy_path,
state_path, state_path,
operation_id: RefCell::new(Some(operation_id)), checkout_state: OnceCell::new(),
workspace_id: RefCell::new(Some(workspace_id)),
tree_state: OnceCell::new(), tree_state: OnceCell::new(),
} }
} }
@ -1002,8 +1006,7 @@ impl WorkingCopy {
store, store,
working_copy_path, working_copy_path,
state_path, state_path,
operation_id: RefCell::new(None), checkout_state: OnceCell::new(),
workspace_id: RefCell::new(None),
tree_state: OnceCell::new(), tree_state: OnceCell::new(),
} }
} }
@ -1024,36 +1027,35 @@ impl WorkingCopy {
temp_file.persist(self.state_path.join("checkout")).unwrap(); temp_file.persist(self.state_path.join("checkout")).unwrap();
} }
fn load_proto(&self) { fn checkout_state(&self) -> &CheckoutState {
let mut file = File::open(self.state_path.join("checkout")).unwrap(); self.checkout_state.get_or_init(|| {
let proto: crate::protos::working_copy::Checkout = let mut file = File::open(self.state_path.join("checkout")).unwrap();
Message::parse_from_reader(&mut file).unwrap(); let proto: crate::protos::working_copy::Checkout =
self.operation_id Message::parse_from_reader(&mut file).unwrap();
.replace(Some(OperationId::new(proto.operation_id))); CheckoutState {
let workspace_id = if proto.workspace_id.is_empty() { operation_id: OperationId::new(proto.operation_id),
// For compatibility with old working copies. workspace_id: if proto.workspace_id.is_empty() {
// TODO: Delete in mid 2022 or so // For compatibility with old working copies.
WorkspaceId::default() // TODO: Delete in mid 2022 or so
} else { WorkspaceId::default()
WorkspaceId::new(proto.workspace_id) } else {
}; WorkspaceId::new(proto.workspace_id)
self.workspace_id.replace(Some(workspace_id)); },
}
})
}
fn checkout_state_mut(&mut self) -> &mut CheckoutState {
self.checkout_state(); // ensure loaded
self.checkout_state.get_mut().unwrap()
} }
pub fn operation_id(&self) -> OperationId { pub fn operation_id(&self) -> OperationId {
if self.operation_id.borrow().is_none() { self.checkout_state().operation_id.clone()
self.load_proto();
}
self.operation_id.borrow().as_ref().unwrap().clone()
} }
pub fn workspace_id(&self) -> WorkspaceId { pub fn workspace_id(&self) -> WorkspaceId {
if self.workspace_id.borrow().is_none() { self.checkout_state().workspace_id.clone()
self.load_proto();
}
self.workspace_id.borrow().as_ref().unwrap().clone()
} }
fn tree_state(&self) -> &TreeState { fn tree_state(&self) -> &TreeState {
@ -1095,7 +1097,7 @@ impl WorkingCopy {
let lock = FileLock::lock(lock_path); let lock = FileLock::lock(lock_path);
// Re-read from disk after taking the lock // Re-read from disk after taking the lock
self.load_proto(); self.checkout_state.take();
// TODO: It's expensive to reload the whole tree. We should first check if it // TODO: It's expensive to reload the whole tree. We should first check if it
// has changed. // has changed.
self.tree_state.take(); self.tree_state.take();
@ -1204,7 +1206,7 @@ impl LockedWorkingCopy<'_> {
self.wc.tree_state_mut().save(); self.wc.tree_state_mut().save();
} }
if self.old_operation_id != operation_id { if self.old_operation_id != operation_id {
self.wc.operation_id.replace(Some(operation_id)); self.wc.checkout_state_mut().operation_id = operation_id;
self.wc.save(); self.wc.save();
} }
// TODO: Clear the "pending_checkout" file here. // TODO: Clear the "pending_checkout" file here.