diff options
Diffstat (limited to 'vendor/gix-odb/src/store_impls/dynamic/mod.rs')
-rw-r--r-- | vendor/gix-odb/src/store_impls/dynamic/mod.rs | 188 |
1 files changed, 188 insertions, 0 deletions
diff --git a/vendor/gix-odb/src/store_impls/dynamic/mod.rs b/vendor/gix-odb/src/store_impls/dynamic/mod.rs new file mode 100644 index 000000000..5cf2a26ee --- /dev/null +++ b/vendor/gix-odb/src/store_impls/dynamic/mod.rs @@ -0,0 +1,188 @@ +//! 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>, + packed_object_count: RefCell<Option<u64>>, +} + +/// 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 prefix; + +mod header; + +/// +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 likelihood 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) + } + } +} |