pub struct Store { /* private fields */ }
Expand description
The object store for use in any applications with support for auto-updates in the light of changes to the object database.
Features
- entirely lazy, creating an instance does no disk IO at all if
Slots::Given
is used. - multi-threaded lazy-loading of indices and packs
- per-thread pack and object caching avoiding cache trashing.
- most-recently-used packs are always first for speedups if objects are stored in the same pack, typical for packs organized by commit graph and object age.
- lock-free reading for perfect scaling across all cores, and changes to it don’t affect readers as long as these don’t want to enter the same branch.
- sync with the state on disk if objects aren’t found to catch up with changes if an object seems to be missing.
- turn off the behaviour above for all handles if objects are expected to be missing due to spare checkouts.
Implementations§
source§impl Store
impl Store
sourcepub fn iter(&self) -> Result<AllObjects, Error>
pub fn iter(&self) -> Result<AllObjects, Error>
Like Handle::iter()
, but accessible directly on the store.
source§impl Store
impl Store
sourcepub fn at_opts(
objects_dir: impl Into<PathBuf>,
replacements: impl IntoIterator<Item = (ObjectId, ObjectId)>,
_: Options
) -> Result<Self>
pub fn at_opts(
objects_dir: impl Into<PathBuf>,
replacements: impl IntoIterator<Item = (ObjectId, ObjectId)>,
_: Options
) -> Result<Self>
Open the store at objects_dir
(containing loose objects and packs/
), which must only be a directory for
the store to be created without any additional work being done.
slots
defines how many multi-pack-indices as well as indices we can know about at a time, which includes
the allowance for all additional object databases coming in via alternates
as well.
Note that the slots
isn’t used for packs, these are included with their multi-index or index respectively.
For example, In a repository with 250m objects and geometric packing one would expect 27 index/pack pairs,
or a single multi-pack index.
replacements
is an iterator over pairs of old and new object ids for replacement support.
This means that when asking for object X
, one will receive object X-replaced
given an iterator like Some((X, X-replaced))
.
Examples found in repository?
More examples
345 346 347 348 349 350 351 352 353 354 355 356
fn try_from(s: &super::Store) -> Result<Self, Self::Error> {
super::Store::at_opts(
s.path(),
s.replacements(),
crate::store::init::Options {
slots: crate::store::init::Slots::Given(s.files.len().try_into().expect("BUG: too many slots")),
object_hash: Default::default(),
use_multi_pack_index: false,
current_dir: s.current_dir.clone().into(),
},
)
}
source§impl Store
impl Store
Handle creation
sourcepub const INITIAL_MAX_RECURSION_DEPTH: usize = 32usize
pub const INITIAL_MAX_RECURSION_DEPTH: usize = 32usize
The amount of times a ref-delta base can be followed when multi-indices are involved.
sourcepub fn to_cache(self: &OwnShared<Self>) -> Cache<Handle<OwnShared<Store>>>
pub fn to_cache(self: &OwnShared<Self>) -> Cache<Handle<OwnShared<Store>>>
Create a new cache filled with a handle to this store, if this store is supporting shared ownership.
Note that the actual type of OwnShared
depends on the parallel
feature toggle of the git-features
crate.
sourcepub fn to_cache_arc(self: &Arc<Self>) -> Cache<Handle<Arc<Store>>>
pub fn to_cache_arc(self: &Arc<Self>) -> Cache<Handle<Arc<Store>>>
Create a new cache filled with a handle to this store if this store is held in an Arc
.
sourcepub fn to_handle(self: &OwnShared<Self>) -> Handle<OwnShared<Store>>
pub fn to_handle(self: &OwnShared<Self>) -> Handle<OwnShared<Store>>
Create a new database handle to this store if this store is supporting shared ownership.
See also, to_cache()
which is probably more useful.
Examples found in repository?
More examples
sourcepub fn to_handle_arc(self: &Arc<Self>) -> Handle<Arc<Store>>
pub fn to_handle_arc(self: &Arc<Self>) -> Handle<Arc<Store>>
Create a new database handle to this store if this store is held in an Arc
.
This method is useful in applications that know they will use threads.
Examples found in repository?
246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367
pub fn to_cache_arc(self: &Arc<Self>) -> crate::Cache<super::Handle<Arc<super::Store>>> {
self.to_handle_arc().into()
}
/// Create a new database handle to this store if this store is supporting shared ownership.
///
/// See also, [`to_cache()`][super::Store::to_cache()] which is probably more useful.
pub fn to_handle(self: &OwnShared<Self>) -> super::Handle<OwnShared<super::Store>> {
let token = self.register_handle();
super::Handle {
store: self.clone(),
refresh: RefreshMode::default(),
ignore_replacements: false,
token: Some(token),
snapshot: RefCell::new(self.collect_snapshot()),
max_recursion_depth: Self::INITIAL_MAX_RECURSION_DEPTH,
packed_object_count: Default::default(),
}
}
/// Create a new database handle to this store if this store is held in an `Arc`.
///
/// This method is useful in applications that know they will use threads.
pub fn to_handle_arc(self: &Arc<Self>) -> super::Handle<Arc<super::Store>> {
let token = self.register_handle();
super::Handle {
store: self.clone(),
refresh: Default::default(),
ignore_replacements: false,
token: Some(token),
snapshot: RefCell::new(self.collect_snapshot()),
max_recursion_depth: Self::INITIAL_MAX_RECURSION_DEPTH,
packed_object_count: Default::default(),
}
}
/// Transform the only instance into an `Arc<Self>` or panic if this is not the only Rc handle
/// to the contained store.
///
/// This is meant to be used when the `git_features::threading::OwnShared` refers to an `Rc` as it was compiled without the
/// `parallel` feature toggle.
pub fn into_shared_arc(self: OwnShared<Self>) -> Arc<Self> {
match OwnShared::try_unwrap(self) {
Ok(this) => Arc::new(this),
Err(_) => panic!("BUG: Must be called when there is only one owner for this RC"),
}
}
}
impl<S> super::Handle<S>
where
S: Deref<Target = super::Store> + Clone,
{
/// Call once if pack ids are stored and later used for lookup, meaning they should always remain mapped and not be unloaded
/// even if they disappear from disk.
/// This must be called if there is a chance that git maintenance is happening while a pack is created.
pub fn prevent_pack_unload(&mut self) {
self.token = self.token.take().map(|token| self.store.upgrade_handle(token));
}
/// Return a shared reference to the contained store.
pub fn store_ref(&self) -> &S::Target {
&self.store
}
/// Return an owned store with shared ownership.
pub fn store(&self) -> S {
self.store.clone()
}
/// Set the handle to never cause ODB refreshes if an object could not be found.
///
/// The latter is the default, as typically all objects referenced in a git repository are contained in the local clone.
/// More recently, however, this doesn't always have to be the case due to sparse checkouts and other ways to only have a
/// limited amount of objects available locally.
pub fn refresh_never(&mut self) {
self.refresh = RefreshMode::Never;
}
/// Return the current refresh mode.
pub fn refresh_mode(&mut self) -> RefreshMode {
self.refresh
}
}
impl<S> Drop for super::Handle<S>
where
S: Deref<Target = super::Store> + Clone,
{
fn drop(&mut self) {
if let Some(token) = self.token.take() {
self.store.remove_handle(token)
}
}
}
impl TryFrom<&super::Store> for super::Store {
type Error = std::io::Error;
fn try_from(s: &super::Store) -> Result<Self, Self::Error> {
super::Store::at_opts(
s.path(),
s.replacements(),
crate::store::init::Options {
slots: crate::store::init::Slots::Given(s.files.len().try_into().expect("BUG: too many slots")),
object_hash: Default::default(),
use_multi_pack_index: false,
current_dir: s.current_dir.clone().into(),
},
)
}
}
impl super::Handle<Rc<super::Store>> {
/// Convert a ref counted store into one that is ref-counted and thread-safe, by creating a new Store.
pub fn into_arc(self) -> std::io::Result<super::Handle<Arc<super::Store>>> {
let store = Arc::new(super::Store::try_from(self.store_ref())?);
let mut cache = store.to_handle_arc();
cache.refresh = self.refresh;
cache.max_recursion_depth = self.max_recursion_depth;
Ok(cache)
}
Transform the only instance into an Arc<Self>
or panic if this is not the only Rc handle
to the contained store.
This is meant to be used when the git_features::threading::OwnShared
refers to an Rc
as it was compiled without the
parallel
feature toggle.
source§impl Store
impl Store
sourcepub fn verify_integrity<C, P, F>(
&self,
progress: P,
should_interrupt: &AtomicBool,
options: Options<F>
) -> Result<Outcome<P>, Error>where
P: Progress,
C: DecodeEntry,
F: Fn() -> C + Send + Clone,
pub fn verify_integrity<C, P, F>(
&self,
progress: P,
should_interrupt: &AtomicBool,
options: Options<F>
) -> Result<Outcome<P>, Error>where
P: Progress,
C: DecodeEntry,
F: Fn() -> C + Send + Clone,
Check the integrity of all objects as per the given options
.
Note that this will not not force loading all indices or packs permanently, as we will only use the momentarily loaded disk state. This does, however, include all alternates.
source§impl Store
impl Store
sourcepub fn path(&self) -> &Path
pub fn path(&self) -> &Path
The root path at which we expect to find all objects and packs, and which is the source of the alternate file traversal in case there are linked repositories.
Examples found in repository?
345 346 347 348 349 350 351 352 353 354 355 356
fn try_from(s: &super::Store) -> Result<Self, Self::Error> {
super::Store::at_opts(
s.path(),
s.replacements(),
crate::store::init::Options {
slots: crate::store::init::Slots::Given(s.files.len().try_into().expect("BUG: too many slots")),
object_hash: Default::default(),
use_multi_pack_index: false,
current_dir: s.current_dir.clone().into(),
},
)
}
sourcepub fn object_hash(&self) -> Kind
pub fn object_hash(&self) -> Kind
The kind of object hash to assume when dealing with pack indices and pack data files.
sourcepub fn use_multi_pack_index(&self) -> bool
pub fn use_multi_pack_index(&self) -> bool
Whether or not we are allowed to use multi-pack indices
sourcepub fn replacements(&self) -> impl Iterator<Item = (ObjectId, ObjectId)> + '_
pub fn replacements(&self) -> impl Iterator<Item = (ObjectId, ObjectId)> + '_
An iterator over replacements from object-ids X
to X-replaced
as (X, X-replaced)
, sorted by the original id X
.
Examples found in repository?
345 346 347 348 349 350 351 352 353 354 355 356
fn try_from(s: &super::Store) -> Result<Self, Self::Error> {
super::Store::at_opts(
s.path(),
s.replacements(),
crate::store::init::Options {
slots: crate::store::init::Slots::Given(s.files.len().try_into().expect("BUG: too many slots")),
object_hash: Default::default(),
use_multi_pack_index: false,
current_dir: s.current_dir.clone().into(),
},
)
}
source§impl Store
impl Store
sourcepub fn structure(&self) -> Result<Vec<Record>, Error>
pub fn structure(&self) -> Result<Vec<Record>, Error>
Return information about all files known to us as well as their loading state.
Note that this call is expensive as it gathers additional information about loose object databases. Note that it may change as we collect information due to the highly volatile nature of the implementation. The likelihood of actual changes is low though as these still depend on something changing on disk and somebody reading at the same time.