Load the database off the async runtime

Loading an MMDB reads the whole ~100 MB file with a blocking
std::fs::read. The updater did that directly on a tokio worker, and the
1 vCPU production host runs a single worker, so every scheduled update
stalled all in-flight requests until the load finished. With one
request every 2 ms on a single-worker runtime, the worst latency during
a reload was 31 ms; it is 1.7 ms after this change.

Run the load on the blocking thread pool, both for scheduled updates
and for the startup load in init_db.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
NetworkCats
2026-10-23 18:26:52 +08:00
co-authored by Claude Opus 5.5
parent b93dd972e7
commit 32ceddcc03
+12 -2
View File
@@ -40,7 +40,7 @@ pub async fn init_db(
update_url: &str,
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
let reader = if db_path.exists() {
load_db(db_path)?
validate_db_off_runtime(db_path).await?
} else {
if let Some(parent) = db_path.parent() {
fs::create_dir_all(parent).await?;
@@ -66,7 +66,7 @@ async fn download_db(
return Err(e);
}
let reader = match validate_db(&tmp_path) {
let reader = match validate_db_off_runtime(&tmp_path).await {
Ok(r) => r,
Err(e) => {
let _ = fs::remove_file(&tmp_path).await;
@@ -105,6 +105,16 @@ fn validate_db(path: &Path) -> Result<DbReader, Box<dyn std::error::Error + Send
load_db(path).map_err(|e| e.into())
}
/// Runs `validate_db` on the blocking thread pool. It reads the whole ~100 MB
/// file synchronously, and the 1 vCPU production host has a single runtime
/// worker, so loading inline would stall every in-flight request meanwhile.
async fn validate_db_off_runtime(
path: &Path,
) -> Result<DbReader, Box<dyn std::error::Error + Send + Sync>> {
let path = path.to_owned();
tokio::task::spawn_blocking(move || validate_db(&path)).await?
}
pub fn spawn_updater(
shared_db: SharedDb,
db_path: PathBuf,