Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(iroh-dns-server)!: eviction of stale zonestore entries #2997

Merged
merged 26 commits into from
Dec 5, 2024
Merged
Show file tree
Hide file tree
Changes from 23 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
7f680b7
fix(iroh-dns-server): remove accidental blocking from store
dignifiedquire Dec 2, 2024
3fb51ae
happy clippy
dignifiedquire Dec 2, 2024
642b6c2
feat(benchmark): iroh-dns-server write benchmark
Arqu Dec 2, 2024
058fc8f
adjustments
Arqu Dec 2, 2024
19f657a
fmt & cleanup exports
Arqu Dec 2, 2024
1839f5c
Move db ops into an actor and implement write batching
rklaehn Dec 3, 2024
cf00d2b
increase batch size
rklaehn Dec 3, 2024
478a2af
donate a thread to the tokio runtime so we can safely block
rklaehn Dec 3, 2024
c0e0ede
Name the thread
rklaehn Dec 3, 2024
405f80e
Add constants for max batch time and size
rklaehn Dec 3, 2024
3864b33
Add eviction
rklaehn Dec 3, 2024
136da0c
WIP add eviction
rklaehn Dec 3, 2024
02f8f2a
Wire up eviction, including configuration
rklaehn Dec 3, 2024
1505e37
Merge branch 'main' into eviction
rklaehn Dec 3, 2024
453dffb
clippy
rklaehn Dec 3, 2024
691f758
Try out the other way to do eviction
rklaehn Dec 4, 2024
ef0f0da
Merge branch 'main' into eviction
rklaehn Dec 4, 2024
9d503d2
give eviction more time
rklaehn Dec 4, 2024
e254ea5
Merge branch 'main' into eviction
rklaehn Dec 5, 2024
7173d38
more loggging for the dns server actor and eviction thread
rklaehn Dec 5, 2024
13f17cb
Add peekable receiver and make sure we don't start transactions for n…
rklaehn Dec 5, 2024
a68a2af
don't open write txn if somebody wants a snapshot
rklaehn Dec 5, 2024
091680d
Merge branch 'main' into eviction
rklaehn Dec 5, 2024
548cbd4
replace remove_all with individual remove calls
rklaehn Dec 5, 2024
54708f3
Merge branch 'main' into eviction
rklaehn Dec 5, 2024
191a0cb
clippy
rklaehn Dec 5, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion iroh-dns-server/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ governor = "0.6.3" #needs new release of tower_governor for 0.7.0
hickory-proto = "=0.25.0-alpha.2"
hickory-server = { version = "=0.25.0-alpha.2", features = ["dns-over-rustls"] }
http = "1.0.0"
iroh-metrics = "0.29"
humantime-serde = "1.1.1"
iroh-metrics = { version = "0.29.0" }
lru = "0.12.3"
parking_lot = "0.12.1"
pkarr = { version = "2.2.0", features = [ "async", "relay", "dht"], default-features = false }
Expand Down Expand Up @@ -64,6 +65,7 @@ hickory-resolver = "=0.25.0-alpha.2"
iroh = { version = "0.29.0", path = "../iroh" }
iroh-test = { version = "0.29.0", path = "../iroh-test" }
pkarr = { version = "2.2.0", features = ["rand"] }
testresult = "0.4.1"

[[bench]]
name = "write"
Expand Down
2 changes: 1 addition & 1 deletion iroh-dns-server/benches/write.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use tokio::runtime::Runtime;
const LOCALHOST_PKARR: &str = "http://localhost:8080/pkarr";

async fn start_dns_server(config: Config) -> Result<Server> {
let store = ZoneStore::persistent(Config::signed_packet_store_path()?)?;
let store = ZoneStore::persistent(Config::signed_packet_store_path()?, Default::default())?;
Server::spawn(config, store).await
}

Expand Down
53 changes: 53 additions & 0 deletions iroh-dns-server/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use std::{
env,
net::{IpAddr, Ipv4Addr, SocketAddr},
path::{Path, PathBuf},
time::Duration,
};

use anyhow::{anyhow, Context, Result};
Expand All @@ -13,6 +14,7 @@ use tracing::info;
use crate::{
dns::DnsConfig,
http::{CertMode, HttpConfig, HttpsConfig, RateLimitConfig},
store::ZoneStoreOptions,
};

const DEFAULT_METRICS_ADDR: SocketAddr = SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 9117);
Expand Down Expand Up @@ -44,11 +46,61 @@ pub struct Config {
/// Config for the mainline lookup.
pub mainline: Option<MainlineConfig>,

/// Config for the zone store.
pub zone_store: Option<StoreConfig>,

/// Config for pkarr rate limit
#[serde(default)]
pub pkarr_put_rate_limit: RateLimitConfig,
}

/// The config for the store.
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct StoreConfig {
/// Maximum number of packets to process in a single write transaction.
max_batch_size: usize,

/// Maximum time to keep a write transaction open.
#[serde(with = "humantime_serde")]
max_batch_time: Duration,

/// Time to keep packets in the store before eviction.
#[serde(with = "humantime_serde")]
eviction: Duration,

/// Pause between eviction checks.
#[serde(with = "humantime_serde")]
eviction_interval: Duration,
}

impl Default for StoreConfig {
fn default() -> Self {
ZoneStoreOptions::default().into()
}
}

impl From<ZoneStoreOptions> for StoreConfig {
fn from(value: ZoneStoreOptions) -> Self {
Self {
max_batch_size: value.max_batch_size,
max_batch_time: value.max_batch_time,
eviction: value.eviction,
eviction_interval: value.eviction_interval,
}
}
}

impl From<StoreConfig> for ZoneStoreOptions {
fn from(value: StoreConfig) -> Self {
Self {
max_batch_size: value.max_batch_size,
max_batch_time: value.max_batch_time,
eviction: value.eviction,
eviction_interval: value.eviction_interval,
}
}
}

/// The config for the metrics server.
#[derive(Debug, Serialize, Deserialize)]
pub struct MetricsConfig {
Expand Down Expand Up @@ -187,6 +239,7 @@ impl Default for Config {
rr_aaaa: None,
rr_ns: Some("ns1.irohdns.example.".to_string()),
},
zone_store: None,
metrics: None,
mainline: None,
pkarr_put_rate_limit: RateLimitConfig::default(),
Expand Down
55 changes: 52 additions & 3 deletions iroh-dns-server/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@ pub use store::ZoneStore;

#[cfg(test)]
mod tests {
use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr};
use std::{
net::{Ipv4Addr, Ipv6Addr, SocketAddr},
time::Duration,
};

use anyhow::Result;
use hickory_resolver::{
Expand All @@ -29,9 +32,16 @@ mod tests {
key::SecretKey,
};
use pkarr::{PkarrClient, SignedPacket};
use testresult::TestResult;
use url::Url;

use crate::{config::BootstrapOption, server::Server};
use crate::{
config::BootstrapOption,
server::Server,
store::{PacketSource, ZoneStoreOptions},
util::PublicKeyBytes,
ZoneStore,
};

#[tokio::test]
async fn pkarr_publish_dns_resolve() -> Result<()> {
Expand Down Expand Up @@ -178,6 +188,36 @@ mod tests {
Ok(())
}

#[tokio::test]
async fn store_eviction() -> TestResult<()> {
iroh_test::logging::setup_multithreaded();
let options = ZoneStoreOptions {
eviction: Duration::from_millis(100),
eviction_interval: Duration::from_millis(100),
max_batch_time: Duration::from_millis(100),
..Default::default()
};
let store = ZoneStore::in_memory(options)?;

// create a signed packet
let signed_packet = random_signed_packet()?;
let key = PublicKeyBytes::from_signed_packet(&signed_packet);

store
.insert(signed_packet, PacketSource::PkarrPublish)
.await?;

tokio::time::sleep(Duration::from_secs(1)).await;
for _ in 0..10 {
let entry = store.get_signed_packet(&key).await?;
if entry.is_none() {
return Ok(());
}
tokio::time::sleep(Duration::from_secs(1)).await;
}
panic!("store did not evict packet");
}

#[tokio::test]
async fn integration_mainline() -> Result<()> {
iroh_test::logging::setup_multithreaded();
Expand All @@ -188,7 +228,8 @@ mod tests {

// spawn our server with mainline support
let (server, nameserver, _http_url) =
Server::spawn_for_tests_with_mainline(Some(BootstrapOption::Custom(bootstrap))).await?;
Server::spawn_for_tests_with_options(Some(BootstrapOption::Custom(bootstrap)), None)
.await?;

let origin = "irohdns.example.";

Expand Down Expand Up @@ -228,4 +269,12 @@ mod tests {
config.add_name_server(nameserver_config);
AsyncResolver::tokio(config, Default::default())
}

fn random_signed_packet() -> Result<SignedPacket> {
let secret_key = SecretKey::generate();
let node_id = secret_key.public();
let relay_url: Url = "https://relay.example.".parse()?;
let node_info = NodeInfo::new(node_id, Some(relay_url.clone()), Default::default());
Ok(node_info.to_pkarr_signed_packet(&secret_key, 30)?)
}
}
2 changes: 2 additions & 0 deletions iroh-dns-server/src/metrics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ pub struct Metrics {
pub store_packets_inserted: Counter,
pub store_packets_removed: Counter,
pub store_packets_updated: Counter,
pub store_packets_expired: Counter,
}

impl Default for Metrics {
Expand All @@ -44,6 +45,7 @@ impl Default for Metrics {
store_packets_inserted: Counter::new("Signed packets inserted into the store"),
store_packets_removed: Counter::new("Signed packets removed from the store"),
store_packets_updated: Counter::new("Number of updates to existing packets"),
store_packets_expired: Counter::new("Number of expired packets"),
}
}
}
Expand Down
13 changes: 9 additions & 4 deletions iroh-dns-server/src/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,11 @@ use crate::{

/// Spawn the server and run until the `Ctrl-C` signal is received, then shutdown.
pub async fn run_with_config_until_ctrl_c(config: Config) -> Result<()> {
let mut store = ZoneStore::persistent(Config::signed_packet_store_path()?)?;
let zone_store_options = config.zone_store.clone().unwrap_or_default();
let mut store = ZoneStore::persistent(
Config::signed_packet_store_path()?,
zone_store_options.into(),
)?;
if let Some(bootstrap) = config.mainline_enabled() {
info!("mainline fallback enabled");
store = store.with_mainline_fallback(bootstrap);
Expand Down Expand Up @@ -96,14 +100,15 @@ impl Server {
/// HTTP server.
#[cfg(test)]
pub async fn spawn_for_tests() -> Result<(Self, std::net::SocketAddr, url::Url)> {
Self::spawn_for_tests_with_mainline(None).await
Self::spawn_for_tests_with_options(None, None).await
}

/// Spawn a server suitable for testing, while optionally enabling mainline with custom
/// bootstrap addresses.
#[cfg(test)]
pub async fn spawn_for_tests_with_mainline(
pub async fn spawn_for_tests_with_options(
mainline: Option<crate::config::BootstrapOption>,
options: Option<crate::store::ZoneStoreOptions>,
) -> Result<(Self, std::net::SocketAddr, url::Url)> {
use std::net::{IpAddr, Ipv4Addr};

Expand All @@ -117,7 +122,7 @@ impl Server {
config.https = None;
config.metrics = Some(MetricsConfig::disabled());

let mut store = ZoneStore::in_memory()?;
let mut store = ZoneStore::in_memory(options.unwrap_or_default())?;
if let Some(bootstrap) = mainline {
info!("mainline fallback enabled");
store = store.with_mainline_fallback(bootstrap);
Expand Down
9 changes: 5 additions & 4 deletions iroh-dns-server/src/store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ use crate::{
};

mod signed_packets;
pub use signed_packets::Options as ZoneStoreOptions;

/// Cache up to 1 million pkarr zones by default
pub const DEFAULT_CACHE_CAPACITY: usize = 1024 * 1024;
Expand All @@ -44,14 +45,14 @@ pub struct ZoneStore {

impl ZoneStore {
/// Create a persistent store
pub fn persistent(path: impl AsRef<Path>) -> Result<Self> {
let packet_store = SignedPacketStore::persistent(path)?;
pub fn persistent(path: impl AsRef<Path>, options: ZoneStoreOptions) -> Result<Self> {
let packet_store = SignedPacketStore::persistent(path, options)?;
Ok(Self::new(packet_store))
}

/// Create an in-memory store.
pub fn in_memory() -> Result<Self> {
let packet_store = SignedPacketStore::in_memory()?;
pub fn in_memory(options: ZoneStoreOptions) -> Result<Self> {
let packet_store = SignedPacketStore::in_memory(options)?;
Ok(Self::new(packet_store))
}

Expand Down
Loading
Loading