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()))