repo: get change id index from revset instead of building it in repo

This replaces the direct use of `IdIndex` in `ReadonlyRepo` by use of
`Revset::change_id_index()`.

I made the `Index` trait require `Send` and `Sync` in order to be able
to store an instance of it in `ReadonlyRepo` (via `ChangeIdIndex`) and
still have that be `Send` and `Sync`. We could alternatively store the
`ChangeIdIndex` in a `Mutex`. Now that will be up to the
`ChangeIdIndex` instead.
This commit is contained in:
Martin von Zweigbergk 2023-03-20 22:04:21 -07:00 committed by Martin von Zweigbergk
parent 27a7fccefa
commit 68cff2fa22
4 changed files with 30 additions and 24 deletions

View file

@ -799,7 +799,7 @@ impl MutableIndex for MutableIndexImpl {
} }
} }
trait IndexSegment { trait IndexSegment: Send + Sync {
fn segment_num_parent_commits(&self) -> u32; fn segment_num_parent_commits(&self) -> u32;
fn segment_num_commits(&self) -> u32; fn segment_num_commits(&self) -> u32;

View file

@ -47,7 +47,7 @@ pub trait IndexStore: Send + Sync + Debug {
) -> Result<Box<dyn ReadonlyIndex>, IndexWriteError>; ) -> Result<Box<dyn ReadonlyIndex>, IndexWriteError>;
} }
pub trait Index { pub trait Index: Send + Sync {
fn as_any(&self) -> &dyn Any; fn as_any(&self) -> &dyn Any;
fn commit_id_to_pos(&self, commit_id: &CommitId) -> Option<IndexPosition>; fn commit_id_to_pos(&self, commit_id: &CommitId) -> Option<IndexPosition>;

View file

@ -15,7 +15,9 @@
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
use std::fmt::{Debug, Formatter}; use std::fmt::{Debug, Formatter};
use std::io::ErrorKind; use std::io::ErrorKind;
use std::ops::Deref;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::pin::Pin;
use std::sync::Arc; use std::sync::Arc;
use std::{fs, io}; use std::{fs, io};
@ -28,7 +30,7 @@ use crate::backend::{Backend, BackendError, BackendResult, ChangeId, CommitId, O
use crate::commit::Commit; use crate::commit::Commit;
use crate::commit_builder::CommitBuilder; use crate::commit_builder::CommitBuilder;
use crate::dag_walk::topo_order_reverse; use crate::dag_walk::topo_order_reverse;
use crate::default_index_store::{DefaultIndexStore, IndexPosition}; use crate::default_index_store::DefaultIndexStore;
use crate::git_backend::GitBackend; use crate::git_backend::GitBackend;
use crate::index::{HexPrefix, Index, IndexStore, MutableIndex, PrefixResolution, ReadonlyIndex}; use crate::index::{HexPrefix, Index, IndexStore, MutableIndex, PrefixResolution, ReadonlyIndex};
use crate::local_backend::LocalBackend; use crate::local_backend::LocalBackend;
@ -36,6 +38,7 @@ use crate::op_heads_store::{self, OpHeadResolutionError, OpHeadsStore};
use crate::op_store::{BranchTarget, OpStore, OperationId, RefTarget, WorkspaceId}; use crate::op_store::{BranchTarget, OpStore, OperationId, RefTarget, WorkspaceId};
use crate::operation::Operation; use crate::operation::Operation;
use crate::refs::merge_ref_targets; use crate::refs::merge_ref_targets;
use crate::revset::{ChangeIdIndex, Revset, RevsetExpression};
use crate::rewrite::DescendantRebaser; use crate::rewrite::DescendantRebaser;
use crate::settings::{RepoSettings, UserSettings}; use crate::settings::{RepoSettings, UserSettings};
use crate::simple_op_heads_store::SimpleOpHeadsStore; use crate::simple_op_heads_store::SimpleOpHeadsStore;
@ -77,9 +80,10 @@ pub struct ReadonlyRepo {
operation: Operation, operation: Operation,
settings: RepoSettings, settings: RepoSettings,
index_store: Arc<dyn IndexStore>, index_store: Arc<dyn IndexStore>,
index: OnceCell<Box<dyn ReadonlyIndex>>, index: OnceCell<Pin<Box<dyn ReadonlyIndex>>>,
// Declared after `change_id_index` since it must outlive it on drop.
change_id_index: OnceCell<Box<dyn ChangeIdIndex>>,
// TODO: This should eventually become part of the index and not be stored fully in memory. // TODO: This should eventually become part of the index and not be stored fully in memory.
change_id_index: OnceCell<ChangeIdIndex>,
view: View, view: View,
} }
@ -209,21 +213,27 @@ impl ReadonlyRepo {
pub fn readonly_index(&self) -> &dyn ReadonlyIndex { pub fn readonly_index(&self) -> &dyn ReadonlyIndex {
self.index self.index
.get_or_init(|| { .get_or_init(|| {
self.index_store Box::into_pin(
.get_index_at_op(&self.operation, &self.store) self.index_store
.get_index_at_op(&self.operation, &self.store),
)
}) })
.as_ref() .deref()
} }
fn change_id_index(&self) -> &ChangeIdIndex { fn change_id_index<'a>(&'a self) -> &'a (dyn ChangeIdIndex + 'a) {
self.change_id_index.get_or_init(|| { let change_id_index: &'a (dyn ChangeIdIndex + 'a) = self
let heads = self.view().heads().iter().cloned().collect_vec(); .change_id_index
let walk = self.readonly_index().as_index().walk_revs(&heads, &[]); .get_or_init(|| {
IdIndex::from_vec( let revset: Box<dyn Revset<'a>> = RevsetExpression::all().evaluate(self).unwrap();
walk.map(|entry| (entry.change_id(), entry.position())) let change_id_index: Box<dyn ChangeIdIndex + 'a> = revset.change_id_index();
.collect(), // evaluate() above only borrows the index, not the whole repo
) let change_id_index: Box<dyn ChangeIdIndex> =
}) unsafe { std::mem::transmute(change_id_index) };
change_id_index
})
.as_ref();
change_id_index
} }
pub fn op_heads_store(&self) -> &Arc<dyn OpHeadsStore> { pub fn op_heads_store(&self) -> &Arc<dyn OpHeadsStore> {
@ -277,9 +287,7 @@ impl Repo for ReadonlyRepo {
} }
fn resolve_change_id_prefix(&self, prefix: &HexPrefix) -> PrefixResolution<Vec<CommitId>> { fn resolve_change_id_prefix(&self, prefix: &HexPrefix) -> PrefixResolution<Vec<CommitId>> {
let index = self.index(); self.change_id_index().resolve_prefix(prefix)
self.change_id_index()
.resolve_prefix_with(prefix, |&pos| index.entry_by_pos(pos).commit_id())
} }
fn shortest_unique_change_id_prefix_len(&self, target_id: &ChangeId) -> usize { fn shortest_unique_change_id_prefix_len(&self, target_id: &ChangeId) -> usize {
@ -578,7 +586,7 @@ impl RepoLoader {
operation, operation,
settings: self.repo_settings.clone(), settings: self.repo_settings.clone(),
index_store: self.index_store.clone(), index_store: self.index_store.clone(),
index: OnceCell::with_value(index), index: OnceCell::with_value(Box::into_pin(index)),
change_id_index: OnceCell::new(), change_id_index: OnceCell::new(),
view, view,
}; };
@ -1272,8 +1280,6 @@ mod dirty_cell {
} }
} }
type ChangeIdIndex = IdIndex<ChangeId, IndexPosition>;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct IdIndex<K, V>(Vec<(K, V)>); pub struct IdIndex<K, V>(Vec<(K, V)>);

View file

@ -1582,7 +1582,7 @@ pub trait Revset<'index> {
fn is_empty(&self) -> bool; fn is_empty(&self) -> bool;
} }
pub trait ChangeIdIndex { pub trait ChangeIdIndex: Send + Sync {
/// Resolve an unambiguous change ID prefix to the commit IDs in the revset. /// Resolve an unambiguous change ID prefix to the commit IDs in the revset.
fn resolve_prefix(&self, prefix: &HexPrefix) -> PrefixResolution<Vec<CommitId>>; fn resolve_prefix(&self, prefix: &HexPrefix) -> PrefixResolution<Vec<CommitId>>;