//! The standard object store which should fit all needs.use std::{cell::RefCell, ops::Deref}; use crate::Store; /// This effectively acts like a handle but exists to be usable from the actual `crate::Handle` implementation which adds caches on top./// Each store is quickly cloned and contains thread-local state for shared packs.pub struct Handle<S>where S: Deref<Target = Store> + Clone,{ pub(crate) store: S, /// Defines what happens when there is no more indices to load. pub refresh: RefreshMode, /// The maximum recursion depth for resolving ref-delta base objects, that is objects referring to other objects within /// a pack. /// Recursive loops are possible only in purposefully crafted packs. /// This value doesn't have to be huge as in typical scenarios, these kind of objects are rare and chains supposedly are /// even more rare. pub max_recursion_depth: usize, /// If true, replacements will not be performed even if these are available. pub ignore_replacements: bool, pub(crate) token: Option<handle::Mode>, snapshot: RefCell<load_index::Snapshot>,} /// Decide what happens when all indices are loaded.#[derive(Clone, Copy)]pub enum RefreshMode { /// Check for new or changed pack indices (and pack data files) when the last known index is loaded. /// During runtime we will keep pack indices stable by never reusing them, however, there is the option for /// clearing internal caches which is likely to change pack ids and it will trigger unloading of packs as they are missing on disk. AfterAllIndicesLoaded, /// Use this if you expect a lot of missing objects that shouldn't trigger refreshes even after all packs are loaded. /// This comes at the risk of not learning that the packs have changed in the mean time. Never,} impl Default for RefreshMode { fn default() -> Self { RefreshMode::AfterAllIndicesLoaded }} impl RefreshMode { /// Set this refresh mode to never refresh. pub fn never(&mut self) { *self = RefreshMode::Never; }} ///pub mod find; ///pub mod iter; ///pub mod write; ///pub mod init; pub(crate) mod types;pub use types::Metrics; pub(crate) mod handle; ///pub mod load_index; ///pub mod verify; mod load_one; mod metrics; mod access; ///pub mod structure { use std::path::PathBuf; use crate::{store::load_index, types::IndexAndPacks, Store}; /// A record of a structural element of an object database. #[derive(Debug, Clone, PartialEq, Eq)] #[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))] pub enum Record { /// A loose object database. LooseObjectDatabase { /// The root of the object database. objects_directory: PathBuf, /// The amount of object files. num_objects: usize, }, /// A pack index file Index { /// The location of the index file, path: PathBuf, /// Whether or not the index is mapped into memory. state: IndexState, }, /// A multi-index file MultiIndex { /// The location of the multi-index file, path: PathBuf, /// Whether or not the index is mapped into memory. state: IndexState, }, /// An empty slot was encountered, this is possibly happening as the ODB changes during query with /// a file being removed. Empty, } #[derive(Debug, Clone, PartialEq, Eq)] #[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))] /// Possible stats of pack indices. pub enum IndexState { /// The index is active in memory because a mapping exists. Loaded, /// The index couldn't be unloaded as it was still in use, but that can happen another time. Disposable, /// The index isn't loaded/memory mapped. Unloaded, } impl Store { /// 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 likelyhood of actual changes is low though as these still depend on something /// changing on disk and somebody reading at the same time. pub fn structure(&self) -> Result<Vec<Record>, load_index::Error> { let index = self.index.load(); if !index.is_initialized() { self.consolidate_with_disk_state(true, false /*load one new index*/)?; } let index = self.index.load(); let mut res: Vec<_> = index .loose_dbs .iter() .map(|db| Record::LooseObjectDatabase { objects_directory: db.path.clone(), num_objects: db.iter().count(), }) .collect(); for slot in index.slot_indices.iter().map(|idx| &self.files[*idx]) { let files = slot.files.load(); let record = match &**files { Some(index) => { let state = if index.is_disposable() { IndexState::Disposable } else if index.index_is_loaded() { IndexState::Loaded } else { IndexState::Unloaded }; match index { IndexAndPacks::Index(b) => Record::Index { path: b.index.path().into(), state, }, IndexAndPacks::MultiIndex(b) => Record::MultiIndex { path: b.multi_index.path().into(), state, }, } } None => Record::Empty, }; res.push(record); } Ok(res) } }}
//! The standard object store which should fit all needs.
use std::{cell::RefCell, ops::Deref};
use crate::Store;
/// This effectively acts like a handle but exists to be usable from the actual `crate::Handle` implementation which adds caches on top.
/// Each store is quickly cloned and contains thread-local state for shared packs.
pub struct Handle<S>
where
S: Deref<Target = Store> + Clone,
{
pub(crate) store: S,
/// Defines what happens when there is no more indices to load.
pub refresh: RefreshMode,
/// The maximum recursion depth for resolving ref-delta base objects, that is objects referring to other objects within
/// a pack.
/// Recursive loops are possible only in purposefully crafted packs.
/// This value doesn't have to be huge as in typical scenarios, these kind of objects are rare and chains supposedly are
/// even more rare.
pub max_recursion_depth: usize,
/// If true, replacements will not be performed even if these are available.
pub ignore_replacements: bool,
pub(crate) token: Option<handle::Mode>,
snapshot: RefCell<load_index::Snapshot>,
}
/// Decide what happens when all indices are loaded.
#[derive(Clone, Copy)]
pub enum RefreshMode {
/// Check for new or changed pack indices (and pack data files) when the last known index is loaded.
/// During runtime we will keep pack indices stable by never reusing them, however, there is the option for
/// clearing internal caches which is likely to change pack ids and it will trigger unloading of packs as they are missing on disk.
AfterAllIndicesLoaded,
/// Use this if you expect a lot of missing objects that shouldn't trigger refreshes even after all packs are loaded.
/// This comes at the risk of not learning that the packs have changed in the mean time.
Never,
}
impl Default for RefreshMode {
fn default() -> Self {
RefreshMode::AfterAllIndicesLoaded
}
}
impl RefreshMode {
/// Set this refresh mode to never refresh.
pub fn never(&mut self) {
*self = RefreshMode::Never;
}
}
///
pub mod find;
///
pub mod iter;
///
pub mod write;
///
pub mod init;
pub(crate) mod types;
pub use types::Metrics;
pub(crate) mod handle;
///
pub mod load_index;
///
pub mod verify;
mod load_one;
mod metrics;
mod access;
///
pub mod structure {
use std::path::PathBuf;
use crate::{store::load_index, types::IndexAndPacks, Store};
/// A record of a structural element of an object database.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))]
pub enum Record {
/// A loose object database.
LooseObjectDatabase {
/// The root of the object database.
objects_directory: PathBuf,
/// The amount of object files.
num_objects: usize,
},
/// A pack index file
Index {
/// The location of the index file,
path: PathBuf,
/// Whether or not the index is mapped into memory.
state: IndexState,
},
/// A multi-index file
MultiIndex {
/// The location of the multi-index file,
path: PathBuf,
/// Whether or not the index is mapped into memory.
state: IndexState,
},
/// An empty slot was encountered, this is possibly happening as the ODB changes during query with
/// a file being removed.
Empty,
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))]
/// Possible stats of pack indices.
pub enum IndexState {
/// The index is active in memory because a mapping exists.
Loaded,
/// The index couldn't be unloaded as it was still in use, but that can happen another time.
Disposable,
/// The index isn't loaded/memory mapped.
Unloaded,
}
impl Store {
/// 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 likelyhood of actual changes is low though as these still depend on something
/// changing on disk and somebody reading at the same time.
pub fn structure(&self) -> Result<Vec<Record>, load_index::Error> {
let index = self.index.load();
if !index.is_initialized() {
self.consolidate_with_disk_state(true, false /*load one new index*/)?;
}
let index = self.index.load();
let mut res: Vec<_> = index
.loose_dbs
.iter()
.map(|db| Record::LooseObjectDatabase {
objects_directory: db.path.clone(),
num_objects: db.iter().count(),
})
.collect();
for slot in index.slot_indices.iter().map(|idx| &self.files[*idx]) {
let files = slot.files.load();
let record = match &**files {
Some(index) => {
let state = if index.is_disposable() {
IndexState::Disposable
} else if index.index_is_loaded() {
IndexState::Loaded
} else {
IndexState::Unloaded
};
match index {
IndexAndPacks::Index(b) => Record::Index {
path: b.index.path().into(),
state,
},
IndexAndPacks::MultiIndex(b) => Record::MultiIndex {
path: b.multi_index.path().into(),
state,
},
}
}
None => Record::Empty,
};
res.push(record);
}
Ok(res)
}
}
}