Skip to content

Commit

Permalink
feat: spawn concurrent list-repo tasks
Browse files Browse the repository at this point in the history
Concurrently lookup repositories when caling "list_repos". Because I'm
really not an async Rust expert, there's a bunch of unsafe code to allow
for immutable references to Self. Avoiding those would be awesome, but
even with the unsafe trickery, the speed-up is insane:
instead of listing 30 repos with a response time of ~100ms sequentially,
we make 30 responses in parallel, which only takes a couple hundred ms
in total!
  • Loading branch information
benpueschel committed Jul 17, 2024
1 parent fbc54b5 commit 36ebef1
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 10 deletions.
19 changes: 15 additions & 4 deletions src/remote/gitea.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
use crate::error::{Error, ErrorKind, Result};
use async_trait::async_trait;
use teatime::{error::{TeatimeError, TeatimeErrorKind}, Client, CreateRepoOption, GetCommitsOption};
use teatime::{
error::{TeatimeError, TeatimeErrorKind},
Client, CreateRepoOption, GetCommitsOption,
};

use super::*;

Expand Down Expand Up @@ -61,9 +64,16 @@ impl Remote for GiteaRemote {
..Default::default()
};
let repos = self.client.search_repositories(&search_option).await?;
let mut result = Vec::new();
let mut futures = Vec::new();
for repo in repos {
result.push(self.get_repo_info(repo).await?);
// SAFETY: We are not moving `self` in the closure, self is guaranteed to be valid as
// long as the closure is running and we're not mutating it, so this is safe.
let this = unsafe { &*(self as *const Self) };
futures.push(tokio::spawn((*this).get_repo_info(repo)));
}
let mut result = Vec::with_capacity(futures.len());
for future in futures {
result.push(future.await.unwrap()?);
}
Ok(result)
}
Expand All @@ -75,7 +85,8 @@ impl Remote for GiteaRemote {
}

async fn delete_repo(&self, name: &str) -> Result<()> {
Ok(self.client
Ok(self
.client
.delete_repository(&self.config.username, name)
.await?)
}
Expand Down
24 changes: 18 additions & 6 deletions src/remote/github.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,20 +113,33 @@ impl Remote for GitHubRemote {
.order("desc")
.send()
.await?;
let mut result = Vec::new();
let mut futures = Vec::new();
for repo in repos {
let base = self
// SAFETY: We are not moving `self` in the closure, self is guaranteed to be valid as
// long as the closure is running and we're not mutating it, so this is safe.
let this = unsafe { &*(self as *const Self) };
let base = this
.crab
.repos(self.config.username.clone(), repo.name.clone());
result.push(self.get_repo_info(base, repo).await?);
let username = &self.config.username;
futures.push(tokio::spawn(Self::get_repo_info(
username.clone(),
base,
repo,
)));
}
let mut result = Vec::with_capacity(futures.len());
for future in futures {
let f = future.await.unwrap()?;
result.push(f);
}
Ok(result)
}

async fn get_repo_info(&self, name: &str) -> Result<Repository> {
let base = self.crab.repos(self.config.username.clone(), name);
let repo = base.get().await?;
self.get_repo_info(base, repo).await
Self::get_repo_info(self.config.username.clone(), base, repo).await
}

async fn delete_repo(&self, name: &str) -> Result<()> {
Expand All @@ -141,11 +154,10 @@ impl Remote for GitHubRemote {

impl GitHubRemote {
async fn get_repo_info(
&self,
username: String,
base: RepoHandler<'_>,
repo: models::Repository,
) -> Result<Repository> {
let username = &self.config.username;
let commits = base
.list_commits()
.per_page(super::COMMIT_COUNT)
Expand Down

0 comments on commit 36ebef1

Please sign in to comment.