ReadonlyEvolution: make ReadonlyRepo responsible for lazy calculation

This patch changes it so that `ReadonlyEvolution` does not lazily
calculate its state and the caller, i.e. `ReadonlyRepo`, is instead
responsible for the laziness. That will allow the caller to make
decisions based on whether the state has been
calculated. Specifically, we don't want to calculate the evolution
state in order to update it incrementally if it hasn't already been
calculated. It's better to just leave it uncalculated in that case.

As a result of moving the laziness out of `ReadonlyEvolution`, we also
don't need to the reference to `ReadonlyRepo` anymore, which
simplifies things a bunch. The next patch will continue by making the
corresponding change to `MutableEvolution`, which will let us simplify
even more.
This commit is contained in:
Martin von Zweigbergk 2021-03-14 23:04:04 -07:00
parent 43315bc9d2
commit 61acee52f4
2 changed files with 37 additions and 68 deletions

View file

@ -13,7 +13,7 @@
// limitations under the License.
use std::collections::{HashMap, HashSet};
use std::sync::{Arc, Mutex};
use std::sync::Arc;
use crate::commit::Commit;
use crate::commit_builder::CommitBuilder;
@ -316,7 +316,7 @@ impl State {
}
pub enum EvolutionRef<'a, 'm: 'a, 'r: 'm> {
Readonly(&'a ReadonlyEvolution<'r>),
Readonly(Arc<ReadonlyEvolution>),
Mutable(&'a MutableEvolution<'m, 'r>),
}
@ -364,17 +364,16 @@ impl EvolutionRef<'_, '_, '_> {
/// change id as A). Then C is rebased to somewhere else and becomes C'.
/// We will choose that C' as effective successor even though it has a
/// different change id and is not a descendant of one that does.
pub fn new_parent(&self, old_parent_id: &CommitId) -> HashSet<CommitId> {
pub fn new_parent(&self, store: &StoreWrapper, old_parent_id: &CommitId) -> HashSet<CommitId> {
match self {
EvolutionRef::Readonly(evolution) => evolution.new_parent(old_parent_id),
EvolutionRef::Readonly(evolution) => evolution.new_parent(store, old_parent_id),
EvolutionRef::Mutable(evolution) => evolution.new_parent(old_parent_id),
}
}
}
pub struct ReadonlyEvolution<'r> {
repo: &'r ReadonlyRepo,
state: Mutex<Option<Arc<State>>>,
pub struct ReadonlyEvolution {
state: State,
}
pub trait EvolveListener {
@ -394,48 +393,41 @@ pub trait EvolveListener {
);
}
impl<'r> ReadonlyEvolution<'r> {
pub fn new(repo: &'r ReadonlyRepo) -> Self {
impl ReadonlyEvolution {
pub fn new(repo: &ReadonlyRepo) -> ReadonlyEvolution {
ReadonlyEvolution {
repo,
state: Mutex::new(None),
state: State::calculate(repo.as_repo_ref()),
}
}
fn get_state(&self) -> Arc<State> {
let mut locked_state = self.state.lock().unwrap();
if locked_state.is_none() {
locked_state.replace(Arc::new(State::calculate(self.repo.as_repo_ref())));
}
locked_state.as_ref().unwrap().clone()
}
pub fn start_modification<'m>(&self, repo: &'m MutableRepo<'r>) -> MutableEvolution<'r, 'm> {
pub fn start_modification<'r: 'm, 'm>(
&self,
repo: &'m MutableRepo<'r>,
) -> MutableEvolution<'r, 'm> {
MutableEvolution {
repo,
state: self.get_state().as_ref().clone(),
state: self.state.clone(),
}
}
pub fn successors(&self, commit_id: &CommitId) -> HashSet<CommitId> {
self.get_state().successors(commit_id)
self.state.successors(commit_id)
}
pub fn is_obsolete(&self, commit_id: &CommitId) -> bool {
self.get_state().is_obsolete(commit_id)
self.state.is_obsolete(commit_id)
}
pub fn is_orphan(&self, commit_id: &CommitId) -> bool {
self.get_state().is_orphan(commit_id)
self.state.is_orphan(commit_id)
}
pub fn is_divergent(&self, change_id: &ChangeId) -> bool {
self.get_state().is_divergent(change_id)
self.state.is_divergent(change_id)
}
pub fn new_parent(&self, old_parent_id: &CommitId) -> HashSet<CommitId> {
self.get_state()
.new_parent(self.repo.store(), old_parent_id)
pub fn new_parent(&self, store: &StoreWrapper, old_parent_id: &CommitId) -> HashSet<CommitId> {
self.state.new_parent(store, old_parent_id)
}
}

View file

@ -117,7 +117,7 @@ pub struct ReadonlyRepo {
index: Mutex<Option<Arc<ReadonlyIndex>>>,
working_copy: Arc<Mutex<WorkingCopy>>,
view: ReadonlyView,
evolution: Option<ReadonlyEvolution<'static>>,
evolution: Mutex<Option<Arc<ReadonlyEvolution>>>,
}
impl Debug for ReadonlyRepo {
@ -235,14 +235,9 @@ impl ReadonlyRepo {
index: Mutex::new(None),
working_copy: Arc::new(Mutex::new(working_copy)),
view,
evolution: None,
evolution: Mutex::new(None),
};
let mut repo = Arc::new(repo);
let repo_ref: &ReadonlyRepo = repo.as_ref();
let static_lifetime_repo: &'static ReadonlyRepo = unsafe { std::mem::transmute(repo_ref) };
let evolution = ReadonlyEvolution::new(static_lifetime_repo);
Arc::get_mut(&mut repo).unwrap().evolution = Some(evolution);
let repo = Arc::new(repo);
repo.working_copy_locked()
.check_out(checkout_commit)
@ -294,10 +289,12 @@ impl ReadonlyRepo {
&self.view
}
pub fn evolution<'a>(&'a self) -> &ReadonlyEvolution<'a> {
let evolution: &ReadonlyEvolution<'static> = self.evolution.as_ref().unwrap();
let evolution: &ReadonlyEvolution<'a> = unsafe { std::mem::transmute(evolution) };
evolution
pub fn evolution(&self) -> Arc<ReadonlyEvolution> {
let mut locked_evolution = self.evolution.lock().unwrap();
if locked_evolution.is_none() {
locked_evolution.replace(Arc::new(ReadonlyEvolution::new(self)));
}
locked_evolution.as_ref().unwrap().clone()
}
pub fn index(&self) -> Arc<ReadonlyIndex> {
@ -349,12 +346,7 @@ impl ReadonlyRepo {
}
pub fn start_transaction(&self, description: &str) -> Transaction {
let mut_repo = MutableRepo::new(
self,
self.index(),
&self.view,
&self.evolution.as_ref().unwrap(),
);
let mut_repo = MutableRepo::new(self, self.index(), &self.view, self.evolution());
Transaction::new(mut_repo, description)
}
@ -366,25 +358,15 @@ impl ReadonlyRepo {
.unwrap();
self.op_id = operation.id().clone();
self.view = ReadonlyView::new(self.store.clone(), operation.view().take_store_view());
let repo_ref: &ReadonlyRepo = self;
let static_lifetime_repo: &'static ReadonlyRepo = unsafe { std::mem::transmute(repo_ref) };
{
let mut locked_index = self.index.lock().unwrap();
locked_index.take();
}
self.evolution = Some(ReadonlyEvolution::new(static_lifetime_repo));
self.index.lock().unwrap().take();
self.evolution.lock().unwrap().take();
}
pub fn reload_at(&mut self, operation: &Operation) {
self.op_id = operation.id().clone();
self.view = ReadonlyView::new(self.store.clone(), operation.view().take_store_view());
let repo_ref: &ReadonlyRepo = self;
let static_lifetime_repo: &'static ReadonlyRepo = unsafe { std::mem::transmute(repo_ref) };
{
let mut locked_index = self.index.lock().unwrap();
locked_index.take();
}
self.evolution = Some(ReadonlyEvolution::new(static_lifetime_repo));
self.index.lock().unwrap().take();
self.evolution.lock().unwrap().take();
}
}
@ -490,14 +472,9 @@ impl RepoLoader {
index: Mutex::new(None),
working_copy: Arc::new(Mutex::new(working_copy)),
view,
evolution: None,
evolution: Mutex::new(None),
};
let mut repo = Arc::new(repo);
let repo_ref: &ReadonlyRepo = repo.as_ref();
let static_lifetime_repo: &'static ReadonlyRepo = unsafe { std::mem::transmute(repo_ref) };
let evolution = ReadonlyEvolution::new(static_lifetime_repo);
Arc::get_mut(&mut repo).unwrap().evolution = Some(evolution);
Ok(repo)
Ok(Arc::new(repo))
}
}
@ -513,7 +490,7 @@ impl<'r> MutableRepo<'r> {
repo: &'r ReadonlyRepo,
index: Arc<ReadonlyIndex>,
view: &ReadonlyView,
evolution: &ReadonlyEvolution<'r>,
evolution: Arc<ReadonlyEvolution>,
) -> Arc<MutableRepo<'r>> {
let mut_view = view.start_modification();
let mut_index = MutableIndex::incremental(index);