-
Notifications
You must be signed in to change notification settings - Fork 213
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Loading status checks…
feat(iroh-relay)!: use explicit key cache (#3053)
## Description This wires up an explicit key cache to replace the implicit one that was removed in #3051. ~~The default for a key cache is Disabled. A disabled key cache has a size of 1 pointer and otherwise zero performance overhead.~~ I have removed the Default instance for both KeyCache and DerpProtocol so you don't accidentally pass the default despite having a cache available. We use the lru crate for the cache for now. Please comment if it should be something else. Benchmarks have shown that conversion from a [u8;32] to a VerifyingKey is relatively cheap, so the purpose of the cache is solely to validate incoming public keys. We add a Borrow instance to PublicKey so we can use it as a cache key. Some performance measurements: ``` Benchmarking validate valid ed25519 key: 3.7674 µs Benchmarking validate invalid ed25519 key: 3.6637 µs Benchmarking validate valid iroh ed25519 key: 67.089 ns Benchmarking validate invalid iroh ed25519 key: 64.004 ns ``` So just from validating incoming keys, without cache you would be limited to ~250 000 msgs/s per thread. At a message size of 1KiB that would be 250MB/s, which is not great. With the cache deserialization can do 14 000 000 msgs/s, which means that this is no longer a bottleneck. ## Breaking Changes - RelayConfig has new public field key_cache_capacity ## Notes & open questions - Size of the cache - source_and_box has a PublicKey::try_from. Is that perf critical? ## Change checklist - [ ] Self-review. - [ ] Documentation updates following the [style guide](https://rust-lang.github.io/rfcs/1574-more-api-documentation-conventions.html#appendix-a-full-conventions-text), if relevant. - [ ] Tests if relevant. - [ ] All breaking changes documented. --------- Co-authored-by: dignifiedquire <[email protected]>
1 parent
ac74c53
commit d4f72fa
Showing
18 changed files
with
211 additions
and
47 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
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
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,63 @@ | ||
use std::{ | ||
num::NonZeroUsize, | ||
sync::{Arc, Mutex}, | ||
}; | ||
|
||
use iroh_base::PublicKey; | ||
|
||
type SignatureError = <PublicKey as TryFrom<&'static [u8]>>::Error; | ||
type PublicKeyBytes = [u8; PublicKey::LENGTH]; | ||
|
||
/// A cache for public keys. | ||
/// | ||
/// This is used solely to make parsing public keys from byte slices more | ||
/// efficient for the very common case where a large number of identical keys | ||
/// are being parsed, like in the relay server. | ||
/// | ||
/// The cache stores only successful parse results. | ||
#[derive(Debug, Clone)] | ||
pub enum KeyCache { | ||
/// The key cache is disabled. | ||
Disabled, | ||
/// The key cache is enabled with a fixed capacity. It is shared between | ||
/// multiple threads. | ||
Shared(Arc<Mutex<lru::LruCache<PublicKey, ()>>>), | ||
} | ||
|
||
impl KeyCache { | ||
/// Key cache to be used in tests. | ||
#[cfg(test)] | ||
pub fn test() -> Self { | ||
Self::Disabled | ||
} | ||
|
||
/// Create a new key cache with the given capacity. | ||
/// | ||
/// If the capacity is zero, the cache is disabled and has zero overhead. | ||
pub fn new(capacity: usize) -> Self { | ||
let Some(capacity) = NonZeroUsize::new(capacity) else { | ||
return Self::Disabled; | ||
}; | ||
let cache = lru::LruCache::new(capacity); | ||
Self::Shared(Arc::new(Mutex::new(cache))) | ||
} | ||
|
||
/// Get a key from a slice of bytes. | ||
pub fn key_from_slice(&self, slice: &[u8]) -> Result<PublicKey, SignatureError> { | ||
let Self::Shared(cache) = self else { | ||
return PublicKey::try_from(slice); | ||
}; | ||
let Ok(bytes) = PublicKeyBytes::try_from(slice) else { | ||
// if the size is wrong, use PublicKey::try_from to fail with a | ||
// SignatureError. | ||
return Err(PublicKey::try_from(slice).expect_err("invalid length")); | ||
}; | ||
let mut cache = cache.lock().expect("not poisoned"); | ||
if let Some((key, _)) = cache.get_key_value(&bytes) { | ||
return Ok(*key); | ||
} | ||
let key = PublicKey::from_bytes(&bytes)?; | ||
cache.put(key, ()); | ||
Ok(key) | ||
} | ||
} |
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
Oops, something went wrong.