Mercurial > hg
comparison rust/hg-core/src/repo.rs @ 48419:c8659e61073d
rhg: Make Repo::dirstate_parents a LazyCell
Unify with the same abstraction used for other lazily-initialized components
Differential Revision: https://phab.mercurial-scm.org/D11837
author | Simon Sapin <simon.sapin@octobus.net> |
---|---|
date | Mon, 29 Nov 2021 19:00:11 +0100 |
parents | 5734b03ecf3e |
children | c7c23bb036c9 |
comparison
equal
deleted
inserted
replaced
48418:abeae090ce67 | 48419:c8659e61073d |
---|---|
14 use crate::utils::hg_path::HgPath; | 14 use crate::utils::hg_path::HgPath; |
15 use crate::utils::SliceExt; | 15 use crate::utils::SliceExt; |
16 use crate::vfs::{is_dir, is_file, Vfs}; | 16 use crate::vfs::{is_dir, is_file, Vfs}; |
17 use crate::{requirements, NodePrefix}; | 17 use crate::{requirements, NodePrefix}; |
18 use crate::{DirstateError, Revision}; | 18 use crate::{DirstateError, Revision}; |
19 use std::cell::{Cell, Ref, RefCell, RefMut}; | 19 use std::cell::{Ref, RefCell, RefMut}; |
20 use std::collections::HashSet; | 20 use std::collections::HashSet; |
21 use std::path::{Path, PathBuf}; | 21 use std::path::{Path, PathBuf}; |
22 | 22 |
23 /// A repository on disk | 23 /// A repository on disk |
24 pub struct Repo { | 24 pub struct Repo { |
25 working_directory: PathBuf, | 25 working_directory: PathBuf, |
26 dot_hg: PathBuf, | 26 dot_hg: PathBuf, |
27 store: PathBuf, | 27 store: PathBuf, |
28 requirements: HashSet<String>, | 28 requirements: HashSet<String>, |
29 config: Config, | 29 config: Config, |
30 // None means not known/initialized yet | 30 dirstate_parents: LazyCell<DirstateParents, HgError>, |
31 dirstate_parents: Cell<Option<DirstateParents>>, | |
32 dirstate_map: LazyCell<OwningDirstateMap, DirstateError>, | 31 dirstate_map: LazyCell<OwningDirstateMap, DirstateError>, |
33 changelog: LazyCell<Changelog, HgError>, | 32 changelog: LazyCell<Changelog, HgError>, |
34 manifestlog: LazyCell<Manifestlog, HgError>, | 33 manifestlog: LazyCell<Manifestlog, HgError>, |
35 } | 34 } |
36 | 35 |
201 requirements: reqs, | 200 requirements: reqs, |
202 working_directory, | 201 working_directory, |
203 store: store_path, | 202 store: store_path, |
204 dot_hg, | 203 dot_hg, |
205 config: repo_config, | 204 config: repo_config, |
206 dirstate_parents: Cell::new(None), | 205 dirstate_parents: LazyCell::new(Self::read_dirstate_parents), |
207 dirstate_map: LazyCell::new(Self::new_dirstate_map), | 206 dirstate_map: LazyCell::new(Self::new_dirstate_map), |
208 changelog: LazyCell::new(Changelog::open), | 207 changelog: LazyCell::new(Changelog::open), |
209 manifestlog: LazyCell::new(Manifestlog::open), | 208 manifestlog: LazyCell::new(Manifestlog::open), |
210 }; | 209 }; |
211 | 210 |
271 .io_not_found_as_none()? | 270 .io_not_found_as_none()? |
272 .unwrap_or(Vec::new())) | 271 .unwrap_or(Vec::new())) |
273 } | 272 } |
274 | 273 |
275 pub fn dirstate_parents(&self) -> Result<DirstateParents, HgError> { | 274 pub fn dirstate_parents(&self) -> Result<DirstateParents, HgError> { |
276 if let Some(parents) = self.dirstate_parents.get() { | 275 Ok(*self.dirstate_parents.get_or_init(self)?) |
277 return Ok(parents); | 276 } |
278 } | 277 |
278 fn read_dirstate_parents(&self) -> Result<DirstateParents, HgError> { | |
279 let dirstate = self.dirstate_file_contents()?; | 279 let dirstate = self.dirstate_file_contents()?; |
280 let parents = if dirstate.is_empty() { | 280 let parents = if dirstate.is_empty() { |
281 DirstateParents::NULL | 281 DirstateParents::NULL |
282 } else if self.has_dirstate_v2() { | 282 } else if self.has_dirstate_v2() { |
283 crate::dirstate_tree::on_disk::read_docket(&dirstate)?.parents() | 283 crate::dirstate_tree::on_disk::read_docket(&dirstate)?.parents() |
284 } else { | 284 } else { |
285 crate::dirstate::parsers::parse_dirstate_parents(&dirstate)? | 285 crate::dirstate::parsers::parse_dirstate_parents(&dirstate)? |
286 .clone() | 286 .clone() |
287 }; | 287 }; |
288 self.dirstate_parents.set(Some(parents)); | 288 self.dirstate_parents.set(parents); |
289 Ok(parents) | 289 Ok(parents) |
290 } | 290 } |
291 | 291 |
292 fn new_dirstate_map(&self) -> Result<OwningDirstateMap, DirstateError> { | 292 fn new_dirstate_map(&self) -> Result<OwningDirstateMap, DirstateError> { |
293 let dirstate_file_contents = self.dirstate_file_contents()?; | 293 let dirstate_file_contents = self.dirstate_file_contents()?; |
294 if dirstate_file_contents.is_empty() { | 294 if dirstate_file_contents.is_empty() { |
295 self.dirstate_parents.set(Some(DirstateParents::NULL)); | 295 self.dirstate_parents.set(DirstateParents::NULL); |
296 Ok(OwningDirstateMap::new_empty(Vec::new())) | 296 Ok(OwningDirstateMap::new_empty(Vec::new())) |
297 } else if self.has_dirstate_v2() { | 297 } else if self.has_dirstate_v2() { |
298 let docket = crate::dirstate_tree::on_disk::read_docket( | 298 let docket = crate::dirstate_tree::on_disk::read_docket( |
299 &dirstate_file_contents, | 299 &dirstate_file_contents, |
300 )?; | 300 )?; |
301 self.dirstate_parents.set(Some(docket.parents())); | 301 self.dirstate_parents.set(docket.parents()); |
302 let data_size = docket.data_size(); | 302 let data_size = docket.data_size(); |
303 let metadata = docket.tree_metadata(); | 303 let metadata = docket.tree_metadata(); |
304 let mut map = if let Some(data_mmap) = self | 304 let mut map = if let Some(data_mmap) = self |
305 .hg_vfs() | 305 .hg_vfs() |
306 .mmap_open(docket.data_filename()) | 306 .mmap_open(docket.data_filename()) |
316 } else { | 316 } else { |
317 let mut map = OwningDirstateMap::new_empty(dirstate_file_contents); | 317 let mut map = OwningDirstateMap::new_empty(dirstate_file_contents); |
318 let (on_disk, placeholder) = map.get_pair_mut(); | 318 let (on_disk, placeholder) = map.get_pair_mut(); |
319 let (inner, parents) = DirstateMap::new_v1(on_disk)?; | 319 let (inner, parents) = DirstateMap::new_v1(on_disk)?; |
320 self.dirstate_parents | 320 self.dirstate_parents |
321 .set(Some(parents.unwrap_or(DirstateParents::NULL))); | 321 .set(parents.unwrap_or(DirstateParents::NULL)); |
322 *placeholder = inner; | 322 *placeholder = inner; |
323 Ok(map) | 323 Ok(map) |
324 } | 324 } |
325 } | 325 } |
326 | 326 |
400 value: RefCell::new(None), | 400 value: RefCell::new(None), |
401 init: Box::new(init), | 401 init: Box::new(init), |
402 } | 402 } |
403 } | 403 } |
404 | 404 |
405 fn set(&self, value: T) { | |
406 *self.value.borrow_mut() = Some(value) | |
407 } | |
408 | |
405 fn get_or_init(&self, repo: &Repo) -> Result<Ref<T>, E> { | 409 fn get_or_init(&self, repo: &Repo) -> Result<Ref<T>, E> { |
406 let mut borrowed = self.value.borrow(); | 410 let mut borrowed = self.value.borrow(); |
407 if borrowed.is_none() { | 411 if borrowed.is_none() { |
408 drop(borrowed); | 412 drop(borrowed); |
409 // Only use `borrow_mut` if it is really needed to avoid panic in | 413 // Only use `borrow_mut` if it is really needed to avoid panic in |
413 borrowed = self.value.borrow() | 417 borrowed = self.value.borrow() |
414 } | 418 } |
415 Ok(Ref::map(borrowed, |option| option.as_ref().unwrap())) | 419 Ok(Ref::map(borrowed, |option| option.as_ref().unwrap())) |
416 } | 420 } |
417 | 421 |
418 pub fn get_mut_or_init(&self, repo: &Repo) -> Result<RefMut<T>, E> { | 422 fn get_mut_or_init(&self, repo: &Repo) -> Result<RefMut<T>, E> { |
419 let mut borrowed = self.value.borrow_mut(); | 423 let mut borrowed = self.value.borrow_mut(); |
420 if borrowed.is_none() { | 424 if borrowed.is_none() { |
421 *borrowed = Some((self.init)(repo)?); | 425 *borrowed = Some((self.init)(repo)?); |
422 } | 426 } |
423 Ok(RefMut::map(borrowed, |option| option.as_mut().unwrap())) | 427 Ok(RefMut::map(borrowed, |option| option.as_mut().unwrap())) |