Skip to content

Commit 3863707

Browse files
committed
perf(metadata): parallelize metadata fetch, use gzip on request
1 parent 58b812c commit 3863707

File tree

8 files changed

+68
-21
lines changed

8 files changed

+68
-21
lines changed

Diff for: Cargo.lock

+15
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: Cargo.toml

+2-1
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,9 @@ panic = "abort"
2525
futures = "0.3.31"
2626
rayon = "1.10.0"
2727
regex = { version = "1.11.1", default-features = false, features = ["unicode-case", "unicode-perl", "std"] }
28-
reqwest = { version = "0.12.9", default-features = false, features = ["rustls-tls", "blocking", "http2", "json", "stream"] }
28+
reqwest = { version = "0.12.9", default-features = false, features = ["rustls-tls", "blocking", "http2", "json", "stream", "gzip"] }
2929
rusqlite = { version = "0.33.0", features = ["bundled", "rusqlite-macros"] }
3030
serde = { version = "1.0.217", features = ["derive"] }
3131
serde_json = { version = "1.0.135", features = ["indexmap"] }
3232
soar-dl = "0.3.3"
33+
tracing = { version = "0.1.41", default-features = false }

Diff for: soar-cli/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -32,5 +32,5 @@ soar-core = { version = "0.1.2", path = "../soar-core" }
3232
soar-dl = { workspace = true }
3333
tokio = { version = "1.42.0", features = ["macros", "rt-multi-thread"] }
3434
toml = "0.8.19"
35-
tracing = { version = "0.1.41", default-features = false }
35+
tracing = { workspace = true }
3636
tracing-subscriber = { version = "0.3.19", default-features = false, features = ["env-filter", "fmt", "json", "nu-ansi-term"] }

Diff for: soar-cli/src/state.rs

+11-1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use soar_core::{
1010
config::{get_config, Config},
1111
constants::CORE_MIGRATIONS,
1212
database::{connection::Database, migration::MigrationManager},
13+
error::SoarError,
1314
metadata::fetch_metadata,
1415
SoarResult,
1516
};
@@ -39,13 +40,22 @@ impl AppState {
3940
}
4041

4142
async fn init_repo_dbs(&self) -> SoarResult<()> {
43+
let mut tasks = Vec::new();
44+
4245
for repo in &self.inner.config.repositories {
4346
let db_file = repo.get_path()?.join("metadata.db");
4447
if !db_file.exists() {
4548
fs::create_dir_all(repo.get_path()?)?;
4649
File::create(&db_file)?;
4750
}
48-
fetch_metadata(repo.clone()).await?;
51+
let repo_clone = repo.clone();
52+
let task = tokio::task::spawn(async move { fetch_metadata(repo_clone).await });
53+
tasks.push(task);
54+
}
55+
56+
for task in tasks {
57+
task.await
58+
.map_err(|err| SoarError::Custom(format!("Join handle error: {}", err)))??;
4959
}
5060
Ok(())
5161
}

Diff for: soar-core/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,4 @@ soar-dl = { workspace = true }
2828
squishy = { version = "0.3.1", features = ["appimage"] }
2929
thiserror = "2.0.6"
3030
toml = "0.8.19"
31+
tracing = { workspace = true }

Diff for: soar-core/migrations/metadata/V1_initial.sql

+1-1
Original file line numberDiff line numberDiff line change
@@ -61,5 +61,5 @@ CREATE TABLE packages (
6161
download_count INTEGER,
6262
download_count_week INTEGER,
6363
download_count_month INTEGER,
64-
UNIQUE (pkg_id, pkg_name)
64+
UNIQUE (pkg_id, pkg_name, version)
6565
);

Diff for: soar-core/src/database/statements.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ impl<'a> DbStatements<'a> {
4242
?26, jsonb(?27), jsonb(?28), jsonb(?29), jsonb(?30), jsonb(?31), ?32, ?33, ?34, ?35, ?36,
4343
jsonb(?37), jsonb(?38), jsonb(?39), ?40, ?41, ?42
4444
)
45-
ON CONFLICT (pkg_id, pkg_name) DO NOTHING",
45+
ON CONFLICT (pkg_id, pkg_name, version) DO NOTHING",
4646
)?,
4747
})
4848
}

Diff for: soar-core/src/metadata.rs

+36-16
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
use std::fs::{self, File};
22

3+
use futures::TryStreamExt;
34
use reqwest::header::{self, HeaderMap};
45
use rusqlite::Connection;
6+
use tracing::info;
57

68
use crate::{
79
config::Repository,
@@ -30,32 +32,50 @@ pub async fn fetch_metadata(repo: Repository) -> SoarResult<()> {
3032

3133
let metadata_db = repo_path.join("metadata.db");
3234

33-
let conn = Connection::open(&metadata_db)?;
34-
let etag: String = conn
35-
.query_row("SELECT etag FROM repository", [], |row| row.get(0))
36-
.unwrap_or_default();
37-
38-
let etag = if let Some(remote_etag) = resp.headers().get(header::ETAG) {
39-
let remote_etag = remote_etag.to_str().unwrap();
40-
if etag == remote_etag {
41-
return Ok(());
35+
let etag = {
36+
let conn = Connection::open(&metadata_db)?;
37+
let etag: String = conn
38+
.query_row("SELECT etag FROM repository", [], |row| row.get(0))
39+
.unwrap_or_default();
40+
41+
match resp.headers().get(header::ETAG) {
42+
Some(remote_etag) => {
43+
let remote_etag = remote_etag.to_str().unwrap();
44+
if etag == remote_etag {
45+
return Ok(());
46+
}
47+
remote_etag.to_string()
48+
}
49+
None => {
50+
return Err(SoarError::Custom(
51+
"etag is required in metadata response header.".to_string(),
52+
))
53+
}
4254
}
43-
remote_etag.to_string()
44-
} else {
45-
return Err(SoarError::Custom(
46-
"etag is required in metadata response header.".to_string(),
47-
));
4855
};
49-
let _ = conn.close();
5056

5157
let _ = fs::remove_file(&metadata_db);
5258
File::create(&metadata_db)?;
5359

60+
info!("Fetching metadata from {}", repo.url);
61+
5462
let conn = Connection::open(&metadata_db)?;
5563
let mut manager = MigrationManager::new(conn)?;
5664
manager.migrate_from_dir(METADATA_MIGRATIONS)?;
5765

58-
let remote_metadata: Vec<RemotePackage> = resp.json().await?;
66+
let mut content = Vec::new();
67+
let mut stream = resp.bytes_stream();
68+
69+
while let Ok(Some(chunk)) = stream.try_next().await {
70+
content.extend_from_slice(&chunk);
71+
}
72+
73+
let remote_metadata: Vec<RemotePackage> = serde_json::from_slice(&content).map_err(|err| {
74+
SoarError::Custom(format!(
75+
"Failed to parse metadata response from {}: {:#?}",
76+
repo.url, err
77+
))
78+
})?;
5979

6080
let db = Database::new(metadata_db)?;
6181
db.from_remote_metadata(remote_metadata.as_ref(), &repo.name, &etag)?;

0 commit comments

Comments
 (0)