diff options
Diffstat (limited to 'vendor/gix-odb/src/store_impls/dynamic/init.rs')
-rw-r--r-- | vendor/gix-odb/src/store_impls/dynamic/init.rs | 126 |
1 files changed, 126 insertions, 0 deletions
diff --git a/vendor/gix-odb/src/store_impls/dynamic/init.rs b/vendor/gix-odb/src/store_impls/dynamic/init.rs new file mode 100644 index 000000000..2fb660ef1 --- /dev/null +++ b/vendor/gix-odb/src/store_impls/dynamic/init.rs @@ -0,0 +1,126 @@ +use std::{iter::FromIterator, path::PathBuf, sync::Arc}; + +use arc_swap::ArcSwap; + +use crate::{ + store::types::{MutableIndexAndPack, SlotMapIndex}, + Store, +}; + +/// Options for use in [`Store::at_opts()`]. +#[derive(Clone, Debug)] +pub struct Options { + /// How to obtain a size for the slot map. + pub slots: Slots, + /// The kind of hash we expect in our packs and would use for loose object iteration and object writing. + pub object_hash: gix_hash::Kind, + /// If false, no multi-pack indices will be used. If true, they will be used if their hash matches `object_hash`. + pub use_multi_pack_index: bool, + /// The current directory of the process at the time of instantiation. + /// If unset, it will be retrieved using `std::env::current_dir()`. + pub current_dir: Option<std::path::PathBuf>, +} + +impl Default for Options { + fn default() -> Self { + Options { + slots: Default::default(), + object_hash: Default::default(), + use_multi_pack_index: true, + current_dir: None, + } + } +} + +/// Configures the amount of slots in the index slotmap, which is fixed throughout the existence of the store. +#[derive(Copy, Clone, Debug)] +pub enum Slots { + /// The amount of slots to use, that is the total amount of indices we can hold at a time. + /// Using this has the advantage of avoiding an initial directory listing of the repository, and is recommended + /// on the server side where the repository setup is controlled. + /// + /// Note that this won't affect their packs, as each index can have one or more packs associated with it. + Given(u16), + /// Compute the amount of slots needed, as probably best used on the client side where a variety of repositories is encountered. + AsNeededByDiskState { + /// 1.0 means no safety, 1.1 means 10% more slots than needed + multiplier: f32, + /// The minimum amount of slots to assume + minimum: usize, + }, +} + +impl Default for Slots { + fn default() -> Self { + Slots::AsNeededByDiskState { + multiplier: 1.1, + minimum: 32, + } + } +} + +impl Store { + /// 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))`. + pub fn at_opts( + objects_dir: impl Into<PathBuf>, + replacements: impl IntoIterator<Item = (gix_hash::ObjectId, gix_hash::ObjectId)>, + Options { + slots, + object_hash, + use_multi_pack_index, + current_dir, + }: Options, + ) -> std::io::Result<Self> { + let objects_dir = objects_dir.into(); + let current_dir = current_dir.map(Ok).unwrap_or_else(std::env::current_dir)?; + if !objects_dir.is_dir() { + return Err(std::io::Error::new( + std::io::ErrorKind::Other, // TODO: use NotADirectory when stabilized + format!("'{}' wasn't a directory", objects_dir.display()), + )); + } + let slot_count = match slots { + Slots::Given(n) => n as usize, + Slots::AsNeededByDiskState { multiplier, minimum } => { + let mut db_paths = crate::alternate::resolve(&objects_dir, ¤t_dir) + .map_err(|err| std::io::Error::new(std::io::ErrorKind::Other, err))?; + db_paths.insert(0, objects_dir.clone()); + let num_slots = super::Store::collect_indices_and_mtime_sorted_by_size(db_paths, None, None) + .map_err(|err| std::io::Error::new(std::io::ErrorKind::Other, err))? + .len(); + + ((num_slots as f32 * multiplier) as usize).max(minimum) + } + }; + if slot_count > crate::store::types::PackId::max_indices() { + return Err(std::io::Error::new( + std::io::ErrorKind::Other, + "Cannot use more than 1^15 slots", + )); + } + let mut replacements: Vec<_> = replacements.into_iter().collect(); + replacements.sort_by(|a, b| a.0.cmp(&b.0)); + + Ok(Store { + current_dir, + write: Default::default(), + replacements, + path: objects_dir, + files: Vec::from_iter(std::iter::repeat_with(MutableIndexAndPack::default).take(slot_count)), + index: ArcSwap::new(Arc::new(SlotMapIndex::default())), + use_multi_pack_index, + object_hash, + num_handles_stable: Default::default(), + num_handles_unstable: Default::default(), + num_disk_state_consolidation: Default::default(), + }) + } +} |