-
-
Notifications
You must be signed in to change notification settings - Fork 148
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(subscriber): spill callsites into hash set (#97)
This changes the `Callsites` behavior when the array of callsites is full. Currently, we panic in this case. This means that we are quite generous with array sizes, for cases where, e.g., multiple async runtimes are in use. However, being more generous with the array's length makes the linear search performance worse. This branch replaces the panicking behavior with a spillover behavior. Once the array of callsites is full, we will now store any additional callsites in a `HashSet`, rather than panicking. This means we can make the arrays a bit shorter, and (perhaps more importantly) it means we will no longer panic in the (rare) case where an app contains a big pile of interesting callsites. The spillover `HashSet` is protected by a `RwLock`, which is kind of a bummer, since it may be locked when checking if a span/event is in the set of callsites we care about (but only if we have spilled over). However, it should be _contended_ only very rarely, since writes only occur when registering a new callsite. I added an optional `parking_lot` feature to use `parking_lot`'s `RwLock` implementation, which likely offers better performance than `std`'s lock (especially when uncontended, which this lock often is). The feature is disabled by default, for users who don't want the additional dependency. Signed-off-by: Eliza Weisman <eliza@buoyant.io>
- Loading branch information
Showing
4 changed files
with
114 additions
and
25 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
// Some of these methods and re-exports may not be used currently. | ||
#![allow(dead_code, unused_imports)] | ||
|
||
#[cfg(feature = "parking_lot")] | ||
pub(crate) use parking_lot_crate::{RwLock, RwLockReadGuard, RwLockWriteGuard}; | ||
|
||
#[cfg(not(feature = "parking_lot"))] | ||
pub(crate) use self::std_impl::*; | ||
|
||
#[cfg(not(feature = "parking_lot"))] | ||
mod std_impl { | ||
use std::sync::{self, PoisonError, TryLockError}; | ||
pub use std::sync::{RwLockReadGuard, RwLockWriteGuard}; | ||
|
||
#[derive(Debug, Default)] | ||
pub(crate) struct RwLock<T: ?Sized>(sync::RwLock<T>); | ||
|
||
impl<T> RwLock<T> { | ||
pub(crate) fn new(data: T) -> Self { | ||
Self(sync::RwLock::new(data)) | ||
} | ||
} | ||
|
||
impl<T: ?Sized> RwLock<T> { | ||
pub(crate) fn read(&self) -> RwLockReadGuard<'_, T> { | ||
self.0.read().unwrap_or_else(PoisonError::into_inner) | ||
} | ||
|
||
pub(crate) fn try_read(&self) -> Option<RwLockReadGuard<'_, T>> { | ||
match self.0.try_read() { | ||
Ok(guard) => Some(guard), | ||
Err(TryLockError::Poisoned(p)) => Some(p.into_inner()), | ||
Err(TryLockError::WouldBlock) => None, | ||
} | ||
} | ||
|
||
pub(crate) fn write(&self) -> RwLockWriteGuard<'_, T> { | ||
self.0.write().unwrap_or_else(PoisonError::into_inner) | ||
} | ||
|
||
pub(crate) fn try_write(&self) -> Option<RwLockWriteGuard<'_, T>> { | ||
match self.0.try_write() { | ||
Ok(guard) => Some(guard), | ||
Err(TryLockError::Poisoned(p)) => Some(p.into_inner()), | ||
Err(TryLockError::WouldBlock) => None, | ||
} | ||
} | ||
} | ||
} |