Skip to content

Commit 9e8b46b

Browse files
feat: Implement LRU caching for line search results, optimize move parsing
1 parent 14dc84e commit 9e8b46b

File tree

4 files changed

+46
-14
lines changed

4 files changed

+46
-14
lines changed

src-tauri/Cargo.lock

Lines changed: 28 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src-tauri/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ derivative = "2.2.0"
4646
dashmap = "6.1.0"
4747
once_cell = "1.21.3"
4848
rand = "0.8.5"
49+
lru = "0.12"
4950
vampirc-uci = { git = "https://github.com/Pawn-Appetit/vampirc-uci.git", rev = "5d0ee12d5804d71c9eec6132325b9ac6d72a022a", features = [
5051
"specta",
5152
"serde",

src-tauri/src/db/search.rs

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,11 @@ impl<'a> MoveStream<'a> {
241241
}
242242
move_byte => {
243243
// Parse actual chess move
244-
if let Some(chess_move) = self.position.legal_moves().get(move_byte as usize) {
244+
// Get legal moves once instead of on every iteration
245+
let legal_moves = self.position.legal_moves();
246+
if let Some(chess_move) = legal_moves.get(move_byte as usize) {
247+
// Only clone position when we're returning it
248+
// This avoids cloning on every move in the game
245249
let san = SanPlus::from_move_and_play_unchecked(&mut self.position, chess_move);
246250
let move_string = san.to_string();
247251
self.index += 1;
@@ -461,24 +465,22 @@ pub async fn search_position(
461465

462466
let position_query = position_query.unwrap();
463467

464-
// Cache management
468+
// Cache management with LRU
465469
const DISABLE_CACHE: bool = false;
466470

467471
if !DISABLE_CACHE {
468472
let cache_key = (query.clone(), file.clone());
469473

470474
// Return cached results if available
471-
if let Some(cached_result) = state.line_cache.get(&cache_key) {
475+
// LRU cache automatically updates access order on get()
476+
let mut cache = state.line_cache.lock().unwrap();
477+
if let Some(cached_result) = cache.get(&cache_key) {
472478
info!("Using cached results: {} stats, {} games",
473479
cached_result.0.len(), cached_result.1.len());
474480
return Ok(cached_result.clone());
475481
}
476-
477-
// Clear cache if it gets too large
478-
if state.line_cache.len() > 100 {
479-
info!("Clearing cache (too many entries: {})", state.line_cache.len());
480-
state.line_cache.clear();
481-
}
482+
// LRU cache automatically evicts least recently used entries when capacity is reached
483+
// No need for manual size checking and clearing
482484
}
483485

484486
// Handle request cancellation
@@ -896,7 +898,8 @@ pub async fn search_position(
896898
let result = (openings.clone(), normalized_games.clone());
897899
if !DISABLE_CACHE {
898900
let cache_key = (query.clone(), file.clone());
899-
state.line_cache.insert(cache_key.clone(), result.clone());
901+
// LRU cache automatically evicts least recently used entry if at capacity
902+
state.line_cache.lock().unwrap().push(cache_key.clone(), result.clone());
900903
info!("Cached position search results for FEN '{}': {} position stats, {} games",
901904
cache_key.0.position.as_ref().map(|p| p.fen.as_str()).unwrap_or("None"),
902905
openings.len(),
@@ -939,7 +942,7 @@ pub async fn is_position_in_db(
939942
info!("Checking if position exists in DB with FEN: {}", pos_query.fen);
940943
}
941944

942-
if let Some(pos) = state.line_cache.get(&(query.clone(), file.clone())) {
945+
if let Some(pos) = state.line_cache.lock().unwrap().get(&(query.clone(), file.clone())) {
943946
info!("Using cached result for position existence check: {}", !pos.0.is_empty());
944947
return Ok(!pos.0.is_empty());
945948
}
@@ -1010,7 +1013,7 @@ pub async fn is_position_in_db(
10101013

10111014
if !exists {
10121015
info!("Position not found in DB, caching empty result");
1013-
state.line_cache.insert((query, file), (vec![], vec![]));
1016+
state.line_cache.lock().unwrap().push((query, file), (vec![], vec![]));
10141017
} else {
10151018
info!("Position found in DB");
10161019
}

src-tauri/src/lib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,8 @@ pub struct AppState {
7777
String,
7878
diesel::r2d2::Pool<diesel::r2d2::ConnectionManager<diesel::SqliteConnection>>,
7979
>,
80-
line_cache: DashMap<(GameQueryJs, std::path::PathBuf), (Vec<PositionStats>, Vec<NormalizedGame>)>,
80+
#[derivative(Default(value = "Mutex::new(lru::LruCache::new(std::num::NonZeroUsize::new(100).unwrap()))"))]
81+
line_cache: Mutex<lru::LruCache<(GameQueryJs, std::path::PathBuf), (Vec<PositionStats>, Vec<NormalizedGame>)>>,
8182
db_cache: Mutex<Vec<GameData>>,
8283
#[derivative(Default(value = "Arc::new(Semaphore::new(2))"))]
8384
new_request: Arc<Semaphore>,

0 commit comments

Comments
 (0)