Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
19 changes: 12 additions & 7 deletions src/file_indexer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -390,13 +390,18 @@ impl FileIndexManager {
// Fetch content for matching files and calculate relevance scores
let mut files_with_content = Vec::new();

// Limit the number of files to fetch
for file_path in matching_files.iter().take(5) {
match self
.gitlab_client
.get_file_content(project_id, file_path, None)
.await
{
// Limit the number of files to fetch and run requests concurrently
let files_to_fetch: Vec<_> = matching_files.iter().take(5).collect();

let fetch_futures = files_to_fetch.iter().map(|file_path| {
let client = self.gitlab_client.clone();
async move { client.get_file_content(project_id, file_path, None).await }
});

let results = futures::future::join_all(fetch_futures).await;

for (result, file_path) in results.into_iter().zip(files_to_fetch) {
match result {
Ok(mut file) => {
// Calculate relevance score based on content
let content_score = if let Some(content) = &file.content {
Expand Down
78 changes: 78 additions & 0 deletions src/tests/file_indexer_perf_test.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
use crate::config::AppSettings;
use crate::file_indexer::FileIndexManager;
use crate::gitlab::GitlabApiClient;
use std::sync::Arc;
use std::time::{Duration, Instant};
use urlencoding::encode;
use wiremock::matchers::{method, path, query_param};
use wiremock::{Mock, MockServer, ResponseTemplate};

#[tokio::test]
async fn test_search_files_performance() {
let mock_server = MockServer::start().await;

let mut settings = AppSettings::default();
settings.gitlab_url = mock_server.uri();
settings.gitlab_token = "token".to_string();
settings.default_branch = "main".to_string();

let client = Arc::new(GitlabApiClient::new(Arc::new(settings)).unwrap());
let manager = Arc::new(FileIndexManager::new(client.clone(), 60));

let project_id = 1;
let index = manager.get_or_create_index(project_id);

// Populate index with 5 files that match the keyword "test"
for i in 0..5 {
let file_path = format!("src/file_{}.rs", i);
index.add_file(&file_path, "fn test() {}");

let encoded_path = encode(&file_path);
let endpoint_path = format!(
"/api/v4/projects/{}/repository/files/{}",
project_id, encoded_path
);

let content = base64::encode("fn test() {}");
let response_body = serde_json::json!({
"file_name": format!("file_{}.rs", i),
"file_path": file_path,
"size": 100,
"encoding": "base64",
"content": content,
"ref": "main",
"blob_id": "123",
"commit_id": "456",
"last_commit_id": "789"
});

Mock::given(method("GET"))
.and(path(endpoint_path))
.and(query_param("ref", "main"))
.respond_with(
ResponseTemplate::new(200)
.set_body_json(response_body)
.set_delay(Duration::from_millis(100)),
)
.mount(&mock_server)
.await;
}

let start = Instant::now();
let results = manager
.search_files(project_id, &["test".to_string()])
.await
.unwrap();
let duration = start.elapsed();

println!("Search took {:?}", duration);
assert_eq!(results.len(), 5);

// In concurrent mode, it should be close to the max delay of a single request (100ms)
// We assert < 250ms to allow for some overhead (was ~500ms sequentially)
assert!(
duration.as_millis() < 250,
"Expected duration < 250ms (concurrent), got {:?}",
duration
);
}
2 changes: 2 additions & 0 deletions src/tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ pub mod agents_md_perf_test;
#[cfg(test)]
pub mod config_tests;
#[cfg(test)]
pub mod file_indexer_perf_test;
#[cfg(test)]
pub mod file_indexer_search_test;
#[cfg(test)]
pub mod file_indexer_simple_test;
Expand Down