Showing the changes to git-odb/src (1 of 1 file). Show all
Unified · Split
| @@ -7,12 +7,12 @@ use std::sync::atomic::AtomicUsize; · 6 unmodified lines | ||
| 7 | 7 | |
| 8 | 8 | /// This effectively acts like a handle but exists to be usable from the actual `crate::Handle` implementation which adds caches on top. |
| 9 | 9 | /// Each store is quickly cloned and contains thread-local state for shared packs. |
| 10 | −#[derive(Clone)] | |
| 11 | 10 | pub struct Handle<S> |
| 12 | 11 | where |
| 13 | 12 | S: Deref<Target = Store> + Clone, |
| 14 | 13 | { |
| 15 | − state: S, | |
| 14 | + pub(crate) store: S, | |
| 15 | + pub(crate) token: Option<handle::Mode>, | |
| 16 | 16 | } |
| 17 | 17 | |
| 18 | 18 | pub struct Store { |
| @@ -81,6 +81,7 @@ mod init { · 62 unmodified lines | ||
| 81 | 81 | use arc_swap::ArcSwap; |
| 82 | 82 | use git_features::threading::OwnShared; |
| 83 | 83 | use std::iter::FromIterator; |
| 84 | + use std::ops::Deref; | |
| 84 | 85 | use std::path::PathBuf; |
| 85 | 86 | use std::sync::atomic::AtomicUsize; |
| 86 | 87 | use std::sync::Arc; |
| @@ -102,10 +103,6 @@ mod init { · 15 unmodified lines | ||
| 102 | 103 | num_handles_unstable: Default::default(), |
| 103 | 104 | }) |
| 104 | 105 | } |
| 105 | − | |
| 106 | − pub fn to_handle(self: &OwnShared<Self>) -> super::Handle<OwnShared<super::Store>> { | |
| 107 | − super::Handle { state: self.clone() } | |
| 108 | − } | |
| 109 | 106 | } |
| 110 | 107 | } |
| 111 | 108 | |
| @@ -121,7 +118,7 @@ mod store { · 9 unmodified lines | ||
| 121 | 118 | |
| 122 | 119 | /// A way to indicate which pack indices we have seen already and which of them are loaded, along with an idea |
| 123 | 120 | /// of whether stored `PackId`s are still usable. |
| 124 | − #[derive(Clone, Default)] | |
| 121 | + #[derive(Default)] | |
| 125 | 122 | pub struct SlotIndexMarker { |
| 126 | 123 | /// The generation the `loaded_until_index` belongs to. Indices of different generations are completely incompatible. |
| 127 | 124 | /// This value changes once the internal representation is compacted, something that may happen only if there is no handle |
| @@ -272,6 +269,9 @@ mod store { · 144 unmodified lines | ||
| 272 | 269 | |
| 273 | 270 | pub mod handle { |
| 274 | 271 | use crate::general::store; |
| 272 | + use git_features::threading::OwnShared; | |
| 273 | + use std::ops::Deref; | |
| 274 | + use std::sync::atomic::Ordering; | |
| 275 | 275 | use std::sync::Arc; |
| 276 | 276 | |
| 277 | 277 | pub(crate) mod multi_index { |
| @@ -338,6 +338,83 @@ pub mod handle { · 60 unmodified lines | ||
| 338 | 338 | } |
| 339 | 339 | } |
| 340 | 340 | } |
| 341 | + | |
| 342 | + pub(crate) enum Mode { | |
| 343 | + DeletedPacksAreInaccessible, | |
| 344 | + /// This mode signals that we should not unload packs even after they went missing. | |
| 345 | + KeepDeletedPacksAvailable, | |
| 346 | + } | |
| 347 | + | |
| 348 | + /// Handle registration | |
| 349 | + impl super::Store { | |
| 350 | + pub(crate) fn register_handle(&self) -> Mode { | |
| 351 | + self.num_handles_unstable.fetch_add(1, Ordering::Relaxed); | |
| 352 | + Mode::DeletedPacksAreInaccessible | |
| 353 | + } | |
| 354 | + pub(crate) fn remove_handle(&self, mode: Mode) { | |
| 355 | + match mode { | |
| 356 | + Mode::KeepDeletedPacksAvailable => { | |
| 357 | + let _ = self.path.lock(); | |
| 358 | + self.num_handles_stable.fetch_sub(1, Ordering::SeqCst) | |
| 359 | + } | |
| 360 | + Mode::DeletedPacksAreInaccessible => self.num_handles_unstable.fetch_sub(1, Ordering::Relaxed), | |
| 361 | + }; | |
| 362 | + } | |
| 363 | + pub(crate) fn upgrade_handle(&self, mode: Mode) -> Mode { | |
| 364 | + if let Mode::DeletedPacksAreInaccessible = mode { | |
| 365 | + let _ = self.path.lock(); | |
| 366 | + self.num_handles_stable.fetch_add(1, Ordering::SeqCst); | |
| 367 | + self.num_handles_unstable.fetch_sub(1, Ordering::SeqCst); | |
| 368 | + } | |
| 369 | + Mode::KeepDeletedPacksAvailable | |
| 370 | + } | |
| 371 | + } | |
| 372 | + | |
| 373 | + /// Handle creation | |
| 374 | + impl super::Store { | |
| 375 | + pub fn to_handle(self: &OwnShared<Self>) -> super::Handle<OwnShared<super::Store>> { | |
| 376 | + let token = self.register_handle(); | |
| 377 | + super::Handle { | |
| 378 | + store: self.clone(), | |
| 379 | + token: Some(token), | |
| 380 | + } | |
| 381 | + } | |
| 382 | + } | |
| 383 | + | |
| 384 | + impl<S> super::Handle<S> | |
| 385 | + where | |
| 386 | + S: Deref<Target = super::Store> + Clone, | |
| 387 | + { | |
| 388 | + /// Call once if pack ids are stored and later used for lookup, meaning they should always remain mapped and not be unloaded | |
| 389 | + /// even if they disappear from disk. | |
| 390 | + /// This must be called if there is a chance that git maintenance is happening while a pack is created. | |
| 391 | + pub fn prevent_pack_unload(&mut self) { | |
| 392 | + self.token = self.token.take().map(|token| self.store.upgrade_handle(token)); | |
| 393 | + } | |
| 394 | + } | |
| 395 | + | |
| 396 | + impl<S> Drop for super::Handle<S> | |
| 397 | + where | |
| 398 | + S: Deref<Target = super::Store> + Clone, | |
| 399 | + { | |
| 400 | + fn drop(&mut self) { | |
| 401 | + if let Some(token) = self.token.take() { | |
| 402 | + self.store.remove_handle(token) | |
| 403 | + } | |
| 404 | + } | |
| 405 | + } | |
| 406 | + | |
| 407 | + impl<S> Clone for super::Handle<S> | |
| 408 | + where | |
| 409 | + S: Deref<Target = super::Store> + Clone, | |
| 410 | + { | |
| 411 | + fn clone(&self) -> Self { | |
| 412 | + super::Handle { | |
| 413 | + store: self.store.clone(), | |
| 414 | + token: self.store.register_handle().into(), | |
| 415 | + } | |
| 416 | + } | |
| 417 | + } | |
| 341 | 418 | } |
| 342 | 419 | |
| 343 | 420 | pub mod load_indices { |