|
1 | 1 | use super::*; |
2 | 2 | use std::collections::HashMap; |
| 3 | +use std::sync::{LazyLock, RwLock}; |
3 | 4 |
|
4 | 5 | const CACHE_VERSION: u64 = 24; |
5 | 6 |
|
| 7 | +fn josh_commit_signature<'a>() -> JoshResult<git2::Signature<'a>> { |
| 8 | + Ok(if let Ok(time) = std::env::var("JOSH_COMMIT_TIME") { |
| 9 | + git2::Signature::new( |
| 10 | + "JOSH", |
| 11 | + "josh@josh-project.dev", |
| 12 | + &git2::Time::new(time.parse()?, 0), |
| 13 | + )? |
| 14 | + } else { |
| 15 | + git2::Signature::now("JOSH", "josh@josh-project.dev")? |
| 16 | + }) |
| 17 | +} |
| 18 | + |
| 19 | +fn store_note(repo: &git2::Repository, kind: &str, key: git2::Oid, from: git2::Oid, to: git2::Oid) { |
| 20 | + let signature = josh_commit_signature().unwrap(); |
| 21 | + repo.note( |
| 22 | + &signature, |
| 23 | + &signature, |
| 24 | + Some(&format!("refs/josh/{}/{}/{}", kind, CACHE_VERSION, key)), |
| 25 | + from, |
| 26 | + &format!("{}", to), |
| 27 | + true, |
| 28 | + ) |
| 29 | + .unwrap(); |
| 30 | +} |
| 31 | + |
| 32 | +fn lookup_note( |
| 33 | + repo: &git2::Repository, |
| 34 | + kind: &str, |
| 35 | + key: git2::Oid, |
| 36 | + from: git2::Oid, |
| 37 | +) -> Option<git2::Oid> { |
| 38 | + if from.as_bytes()[0] != 0 { |
| 39 | + return None; |
| 40 | + } |
| 41 | + if let Ok(note) = repo.find_note( |
| 42 | + Some(&format!("refs/josh/{}/{}/{}", kind, CACHE_VERSION, key)), |
| 43 | + from, |
| 44 | + ) { |
| 45 | + Some(git2::Oid::from_str(note.message().unwrap()).unwrap()) |
| 46 | + } else { |
| 47 | + None |
| 48 | + } |
| 49 | +} |
| 50 | + |
6 | 51 | lazy_static! { |
7 | 52 | static ref DB: std::sync::Mutex<Option<sled::Db>> = std::sync::Mutex::new(None); |
8 | | - static ref REF_CACHE: std::sync::Mutex<HashMap<git2::Oid, HashMap<git2::Oid, git2::Oid>>> = |
9 | | - std::sync::Mutex::new(HashMap::new()); |
10 | | - static ref POPULATE_MAP: std::sync::Mutex<HashMap<(git2::Oid, git2::Oid), git2::Oid>> = |
11 | | - std::sync::Mutex::new(HashMap::new()); |
12 | | - static ref GLOB_MAP: std::sync::Mutex<HashMap<(git2::Oid, git2::Oid), git2::Oid>> = |
13 | | - std::sync::Mutex::new(HashMap::new()); |
14 | 53 | } |
15 | 54 |
|
| 55 | +static REF_CACHE: LazyLock<RwLock<HashMap<git2::Oid, HashMap<git2::Oid, git2::Oid>>>> = |
| 56 | + LazyLock::new(Default::default); |
| 57 | + |
| 58 | +static POPULATE_MAP: LazyLock<RwLock<HashMap<(git2::Oid, git2::Oid), git2::Oid>>> = |
| 59 | + LazyLock::new(Default::default); |
| 60 | + |
| 61 | +static GLOB_MAP: LazyLock<RwLock<HashMap<(git2::Oid, git2::Oid), git2::Oid>>> = |
| 62 | + LazyLock::new(Default::default); |
| 63 | + |
16 | 64 | pub fn load(path: &std::path::Path) -> JoshResult<()> { |
17 | 65 | *DB.lock()? = Some( |
18 | 66 | sled::Config::default() |
@@ -272,32 +320,32 @@ impl Transaction { |
272 | 320 | } |
273 | 321 |
|
274 | 322 | pub fn insert_populate(&self, tree: (git2::Oid, git2::Oid), result: git2::Oid) { |
275 | | - POPULATE_MAP.lock().unwrap().entry(tree).or_insert(result); |
| 323 | + POPULATE_MAP.write().unwrap().entry(tree).or_insert(result); |
276 | 324 | } |
277 | 325 |
|
278 | 326 | pub fn get_populate(&self, tree: (git2::Oid, git2::Oid)) -> Option<git2::Oid> { |
279 | | - return POPULATE_MAP.lock().unwrap().get(&tree).cloned(); |
| 327 | + POPULATE_MAP.read().unwrap().get(&tree).cloned() |
280 | 328 | } |
281 | 329 |
|
282 | 330 | pub fn insert_glob(&self, tree: (git2::Oid, git2::Oid), result: git2::Oid) { |
283 | | - GLOB_MAP.lock().unwrap().entry(tree).or_insert(result); |
| 331 | + GLOB_MAP.write().unwrap().entry(tree).or_insert(result); |
284 | 332 | } |
285 | 333 |
|
286 | 334 | pub fn get_glob(&self, tree: (git2::Oid, git2::Oid)) -> Option<git2::Oid> { |
287 | | - return GLOB_MAP.lock().unwrap().get(&tree).cloned(); |
| 335 | + GLOB_MAP.read().unwrap().get(&tree).cloned() |
288 | 336 | } |
289 | 337 |
|
290 | 338 | pub fn insert_ref(&self, filter: filter::Filter, from: git2::Oid, to: git2::Oid) { |
291 | 339 | REF_CACHE |
292 | | - .lock() |
| 340 | + .write() |
293 | 341 | .unwrap() |
294 | 342 | .entry(filter.id()) |
295 | 343 | .or_default() |
296 | 344 | .insert(from, to); |
297 | 345 | } |
298 | 346 |
|
299 | 347 | pub fn get_ref(&self, filter: filter::Filter, from: git2::Oid) -> Option<git2::Oid> { |
300 | | - if let Some(m) = REF_CACHE.lock().unwrap().get(&filter.id()) { |
| 348 | + if let Some(m) = REF_CACHE.read().unwrap().get(&filter.id()) { |
301 | 349 | if let Some(oid) = m.get(&from) { |
302 | 350 | if self.repo.odb().unwrap().exists(*oid) { |
303 | 351 | return Some(*oid); |
@@ -336,6 +384,9 @@ impl Transaction { |
336 | 384 | }); |
337 | 385 |
|
338 | 386 | t.insert(from.as_bytes(), to.as_bytes()).unwrap(); |
| 387 | + if from.as_bytes()[0] == 0 { |
| 388 | + store_note(&self.repo, "cache", filter.id(), from, to); |
| 389 | + } |
339 | 390 | } |
340 | 391 | } |
341 | 392 |
|
@@ -396,8 +447,15 @@ impl Transaction { |
396 | 447 | .open_tree(filter::spec(filter)) |
397 | 448 | .unwrap() |
398 | 449 | }); |
399 | | - if let Some(oid) = t.get(from.as_bytes()).unwrap() { |
400 | | - let oid = git2::Oid::from_bytes(&oid).unwrap(); |
| 450 | + let oid = if let Some(oid) = t.get(from.as_bytes()).unwrap() { |
| 451 | + Some(git2::Oid::from_bytes(&oid).unwrap()) |
| 452 | + } else if let Some(oid) = lookup_note(&self.repo, "cache", filter.id(), from) { |
| 453 | + Some(oid) |
| 454 | + } else { |
| 455 | + None |
| 456 | + }; |
| 457 | + |
| 458 | + if let Some(oid) = oid { |
401 | 459 | if oid == git2::Oid::zero() { |
402 | 460 | return Some(oid); |
403 | 461 | } |
|
0 commit comments