perf: cache getProjectSchema results in memory The on-demand fallback parses all ~490 files through tree-sitter on every request, taking 8+ seconds. Results are now cached keyed by (did, repo, commit_oid). First request parses; subsequent requests return instantly. Cache invalidates naturally when a new commit is pushed (different commit_oid = different cache key).

Author: Aaron Steven White
Commit c36f1890546a58036f5b3af48dc973998795f900
Parent: 1f39318fd1
Structural diff unavailable

These commits were pushed via plain git push, so no pre-parsed schemas are available. Install git-remote-cospan and re-push via panproto:// to see scope-level changes, breaking change detection, and semantic diffs.

brew install panproto/tap/git-remote-cospan
1 file changed +26 -5
@@ -8,11 +8,16 @@
88 //! stored schema's vertex IDs (which encode the file path prefix).
99 
1010 use std::collections::HashMap;
11-use std::sync::Arc;
11+use std::sync::{Arc, LazyLock, Mutex};
1212 
1313 use axum::Json;
1414 use axum::extract::{Query, State};
1515 use panproto_core::vcs::{Object, Store};
16+
17+/// Cache for on-demand project schema results. Keyed by (did, repo, commit_oid).
18+/// Avoids reparsing 490 files on every page load.
19+static SCHEMA_CACHE: LazyLock<Mutex<HashMap<String, serde_json::Value>>> =
20+    LazyLock::new(|| Mutex::new(HashMap::new()));
1621 use serde::Deserialize;
1722 use serde_json::{Value, json};
1823 
@@ -70,6 +75,14 @@ pub async fn get_project_schema(
7075             _ => None,
7176         });
7277 
78+    // Check cache first (avoids reparsing 490 files on every page load).
79+    let cache_key = format!("{}:{}:{}", params.did, params.repo, commit_oid);
80+    if let Ok(cache) = SCHEMA_CACHE.lock() {
81+        if let Some(cached) = cache.get(&cache_key) {
82+            return Ok(Json(cached.clone()));
83+        }
84+    }
85+
7386     // Walk the git tree for file listing and language detection.
7487     let commit = mirror
7588         .find_commit(commit_oid)
@@ -218,7 +231,7 @@ pub async fn get_project_schema(
218231 
219232         let parsed_count = file_vertex_counts.len();
220233 
221-        return Ok(Json(json!({
234+        let result = json!({
222235             "commit": commit_oid.to_string(),
223236             "protocol": protocol,
224237             "totalVertexCount": total_vc,
@@ -227,7 +240,11 @@ pub async fn get_project_schema(
227240             "parsedFileCount": parsed_count,
228241             "languages": languages,
229242             "fileSchemas": file_schemas,
230-        })));
243+        });
244+        if let Ok(mut cache) = SCHEMA_CACHE.lock() {
245+            cache.insert(cache_key, result.clone());
246+        }
247+        return Ok(Json(result));
231248     }
232249 
233250     // Fallback: no vcs store data. Parse all files on demand.
@@ -320,7 +337,7 @@ pub async fn get_project_schema(
320337         .map(|(name, _)| name.clone())
321338         .unwrap_or_default();
322339 
323-    Ok(Json(json!({
340+    let result = json!({
324341         "commit": commit_oid.to_string(),
325342         "protocol": protocol,
326343         "totalVertexCount": total_vc,
@@ -329,5 +346,9 @@ pub async fn get_project_schema(
329346         "parsedFileCount": parsed_count,
330347         "languages": languages,
331348         "fileSchemas": file_schemas,
332-    })))
349+    });
350+    if let Ok(mut cache) = SCHEMA_CACHE.lock() {
351+        cache.insert(cache_key, result.clone());
352+    }
353+    Ok(Json(result))
333354 }
cospan · schematic version control on atproto built on AT Protocol