Unified · Split
| @@ -7,12 +7,12 @@ use std::sync::atomic::AtomicUsize; · 6 unmodified lines | |||
| 7 | 7 | ||
| 8 | /// This effectively acts like a handle but exists to be usable from the actual `crate::Handle` implementation which adds caches on top. | 8 | /// This effectively acts like a handle but exists to be usable from the actual `crate::Handle` implementation which adds caches on top. |
| 9 | /// Each store is quickly cloned and contains thread-local state for shared packs. | 9 | /// Each store is quickly cloned and contains thread-local state for shared packs. |
| 10 | #[derive(Clone)] | ||
| 11 | pub struct Handle<S> | 10 | pub struct Handle<S> |
| 12 | where | 11 | where |
| 13 | S: Deref<Target = Store> + Clone, | 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 | pub struct Store { | 18 | pub struct Store { |
| @@ -81,6 +81,7 @@ mod init { · 62 unmodified lines | |||
| 81 | use arc_swap::ArcSwap; | 81 | use arc_swap::ArcSwap; |
| 82 | use git_features::threading::OwnShared; | 82 | use git_features::threading::OwnShared; |
| 83 | use std::iter::FromIterator; | 83 | use std::iter::FromIterator; |
| 84 | use std::ops::Deref; | ||
| 84 | use std::path::PathBuf; | 85 | use std::path::PathBuf; |
| 85 | use std::sync::atomic::AtomicUsize; | 86 | use std::sync::atomic::AtomicUsize; |
| 86 | use std::sync::Arc; | 87 | use std::sync::Arc; |
| @@ -102,10 +103,6 @@ mod init { · 15 unmodified lines | |||
| 102 | num_handles_unstable: Default::default(), | 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 | /// A way to indicate which pack indices we have seen already and which of them are loaded, along with an idea | 119 | /// A way to indicate which pack indices we have seen already and which of them are loaded, along with an idea |
| 123 | /// of whether stored `PackId`s are still usable. | 120 | /// of whether stored `PackId`s are still usable. |
| 124 | #[derive(Clone, Default)] | 121 | #[derive(Default)] |
| 125 | pub struct SlotIndexMarker { | 122 | pub struct SlotIndexMarker { |
| 126 | /// The generation the `loaded_until_index` belongs to. Indices of different generations are completely incompatible. | 123 | /// The generation the `loaded_until_index` belongs to. Indices of different generations are completely incompatible. |
| 127 | /// This value changes once the internal representation is compacted, something that may happen only if there is no handle | 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 | pub mod handle { | 270 | pub mod handle { |
| 274 | use crate::general::store; | 271 | use crate::general::store; |
| 272 | use git_features::threading::OwnShared; | ||
| 273 | use std::ops::Deref; | ||
| 274 | use std::sync::atomic::Ordering; | ||
| 275 | use std::sync::Arc; | 275 | use std::sync::Arc; |
| 276 | 276 | ||
| 277 | pub(crate) mod multi_index { | 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 | pub mod load_indices { | 420 | pub mod load_indices { |