11use super :: * ;
2+
3+ use crate :: cache_sled:: sled_open_josh_trees;
4+ use crate :: cache_stack:: CacheStack ;
5+
26use std:: collections:: HashMap ;
37use std:: sync:: { LazyLock , RwLock } ;
48
9+ pub ( crate ) const CACHE_VERSION : u64 = 24 ;
10+
11+ pub trait CacheBackend : Send + Sync {
12+ fn read ( & self , filter : filter:: Filter , from : git2:: Oid ) -> JoshResult < Option < git2:: Oid > > ;
13+
14+ fn write ( & self , filter : filter:: Filter , from : git2:: Oid , to : git2:: Oid ) -> JoshResult < ( ) > ;
15+ }
16+
517pub trait FilterHook {
618 fn filter_for_commit ( & self , commit_oid : git2:: Oid , arg : & str ) -> JoshResult < filter:: Filter > ;
719}
820
9- const CACHE_VERSION : u64 = 24 ;
10-
1121lazy_static ! {
1222 static ref DB : std:: sync:: Mutex <Option <sled:: Db >> = std:: sync:: Mutex :: new( None ) ;
1323}
@@ -21,39 +31,40 @@ static POPULATE_MAP: LazyLock<RwLock<HashMap<(git2::Oid, git2::Oid), git2::Oid>>
2131static GLOB_MAP : LazyLock < RwLock < HashMap < ( git2:: Oid , git2:: Oid ) , git2:: Oid > > > =
2232 LazyLock :: new ( Default :: default) ;
2333
24- pub fn load ( path : & std:: path:: Path ) -> JoshResult < ( ) > {
25- * DB . lock ( ) ? = Some (
26- sled:: Config :: default ( )
27- . path ( path. join ( format ! ( "josh/{}/sled/" , CACHE_VERSION ) ) )
28- . flush_every_ms ( Some ( 200 ) )
29- . open ( ) ?,
30- ) ;
31- Ok ( ( ) )
34+ pub struct TransactionContext {
35+ path : std:: path:: PathBuf ,
36+ cache : std:: sync:: Arc < CacheStack > ,
3237}
3338
34- pub fn print_stats ( ) {
35- let d = DB . lock ( ) . unwrap ( ) ;
36- let db = d. as_ref ( ) . unwrap ( ) ;
37- db. flush ( ) . unwrap ( ) ;
38- log:: debug!( "Trees:" ) ;
39- let mut v = vec ! [ ] ;
40- for name in db. tree_names ( ) {
41- let name = String :: from_utf8 ( name. to_vec ( ) ) . unwrap ( ) ;
42- let t = db. open_tree ( & name) . unwrap ( ) ;
43- if !t. is_empty ( ) {
44- let name = if let Ok ( filter) = filter:: parse ( & name) {
45- filter:: pretty ( filter, 4 )
46- } else {
47- name. clone ( )
48- } ;
49- v. push ( ( t. len ( ) , name) ) ;
39+ impl TransactionContext {
40+ pub fn from_env ( cache : std:: sync:: Arc < CacheStack > ) -> JoshResult < Self > {
41+ let repo = git2:: Repository :: open_from_env ( ) ?;
42+ let path = repo. path ( ) . to_owned ( ) ;
43+
44+ Ok ( Self { path, cache } )
45+ }
46+
47+ pub fn new ( path : impl AsRef < std:: path:: Path > , cache : std:: sync:: Arc < CacheStack > ) -> Self {
48+ Self {
49+ path : path. as_ref ( ) . to_path_buf ( ) ,
50+ cache,
5051 }
5152 }
5253
53- v. sort ( ) ;
54+ pub fn open ( & self , ref_prefix : Option < & str > ) -> JoshResult < Transaction > {
55+ if !self . path . exists ( ) {
56+ return Err ( josh_error ( "path does not exist" ) ) ;
57+ }
5458
55- for ( len, name) in v. iter ( ) {
56- println ! ( "[{}] {}" , len, name) ;
59+ Ok ( Transaction :: new (
60+ git2:: Repository :: open_ext (
61+ & self . path ,
62+ git2:: RepositoryOpenFlags :: NO_SEARCH ,
63+ & [ ] as & [ & std:: ffi:: OsStr ] ,
64+ ) ?,
65+ self . cache . clone ( ) ,
66+ ref_prefix,
67+ ) )
5768 }
5869}
5970
@@ -64,7 +75,7 @@ struct Transaction2 {
6475 subtract_map : HashMap < ( git2:: Oid , git2:: Oid ) , git2:: Oid > ,
6576 overlay_map : HashMap < ( git2:: Oid , git2:: Oid ) , git2:: Oid > ,
6677 unapply_map : HashMap < git2:: Oid , HashMap < git2:: Oid , git2:: Oid > > ,
67- sled_trees : HashMap < git2 :: Oid , sled :: Tree > ,
78+ cache : std :: sync :: Arc < CacheStack > ,
6879 path_tree : sled:: Tree ,
6980 invert_tree : sled:: Tree ,
7081 trigram_index_tree : sled:: Tree ,
@@ -81,67 +92,24 @@ pub struct Transaction {
8192}
8293
8394impl Transaction {
84- pub fn open ( path : & std:: path:: Path , ref_prefix : Option < & str > ) -> JoshResult < Transaction > {
85- if !path. exists ( ) {
86- return Err ( josh_error ( "path does not exist" ) ) ;
87- }
88- Ok ( Transaction :: new (
89- git2:: Repository :: open_ext (
90- path,
91- git2:: RepositoryOpenFlags :: NO_SEARCH ,
92- & [ ] as & [ & std:: ffi:: OsStr ] ,
93- ) ?,
94- ref_prefix,
95- ) )
96- }
97-
98- pub fn open_from_env ( load_cache : bool ) -> JoshResult < Transaction > {
99- let repo = git2:: Repository :: open_from_env ( ) ?;
100- let path = repo. path ( ) . to_owned ( ) ;
101- if load_cache {
102- load ( & path) ?
103- } ;
104-
105- Ok ( Transaction :: new ( repo, None ) )
106- }
95+ fn new (
96+ repo : git2:: Repository ,
97+ cache : std:: sync:: Arc < CacheStack > ,
98+ ref_prefix : Option < & str > ,
99+ ) -> Transaction {
100+ log:: debug!( "new transaction" ) ;
107101
108- pub fn status ( & self , _msg : & str ) {
109- /* let mut t2 = self.t2.borrow_mut(); */
110- /* write!(t2.out, "{}", msg).ok(); */
111- /* t2.out.flush().ok(); */
112- }
102+ let ( path_tree, invert_tree, trigram_index_tree) =
103+ sled_open_josh_trees ( ) . expect ( "failed to open transaction" ) ;
113104
114- fn new ( repo : git2:: Repository , ref_prefix : Option < & str > ) -> Transaction {
115- log:: debug!( "new transaction" ) ;
116- let path_tree = DB
117- . lock ( )
118- . unwrap ( )
119- . as_ref ( )
120- . unwrap ( )
121- . open_tree ( "_paths" )
122- . unwrap ( ) ;
123- let invert_tree = DB
124- . lock ( )
125- . unwrap ( )
126- . as_ref ( )
127- . unwrap ( )
128- . open_tree ( "_invert" )
129- . unwrap ( ) ;
130- let trigram_index_tree = DB
131- . lock ( )
132- . unwrap ( )
133- . as_ref ( )
134- . unwrap ( )
135- . open_tree ( "_trigram_index" )
136- . unwrap ( ) ;
137105 Transaction {
138106 t2 : std:: cell:: RefCell :: new ( Transaction2 {
139107 commit_map : HashMap :: new ( ) ,
140108 apply_map : HashMap :: new ( ) ,
141109 subtract_map : HashMap :: new ( ) ,
142110 overlay_map : HashMap :: new ( ) ,
143111 unapply_map : HashMap :: new ( ) ,
144- sled_trees : HashMap :: new ( ) ,
112+ cache ,
145113 path_tree,
146114 invert_tree,
147115 trigram_index_tree,
@@ -156,7 +124,12 @@ impl Transaction {
156124 }
157125
158126 pub fn try_clone ( & self ) -> JoshResult < Transaction > {
159- Transaction :: open ( self . repo . path ( ) , Some ( & self . ref_prefix ) )
127+ let context = TransactionContext {
128+ cache : self . t2 . borrow ( ) . cache . clone ( ) ,
129+ path : self . repo . path ( ) . to_owned ( ) ,
130+ } ;
131+
132+ context. open ( Some ( & self . ref_prefix ) )
160133 }
161134
162135 pub fn repo ( & self ) -> & git2:: Repository {
@@ -348,34 +321,12 @@ impl Transaction {
348321 // random extra commits (probability 1/256) to avoid long searches for filters that reduce
349322 // the history length by a very large factor.
350323 if store || from. as_bytes ( ) [ 0 ] == 0 {
351- let t = t2. sled_trees . entry ( filter. id ( ) ) . or_insert_with ( || {
352- DB . lock ( )
353- . unwrap ( )
354- . as_ref ( )
355- . unwrap ( )
356- . open_tree ( filter:: spec ( filter) )
357- . unwrap ( )
358- } ) ;
359-
360- t. insert ( from. as_bytes ( ) , to. as_bytes ( ) ) . unwrap ( ) ;
324+ t2. cache
325+ . write_all ( filter, from, to)
326+ . expect ( "Failed to write cache" ) ;
361327 }
362328 }
363329
364- #[ allow( clippy:: len_without_is_empty) ]
365- pub fn len ( & self , filter : filter:: Filter ) -> usize {
366- let mut t2 = self . t2 . borrow_mut ( ) ;
367- let t = t2. sled_trees . entry ( filter. id ( ) ) . or_insert_with ( || {
368- DB . lock ( )
369- . unwrap ( )
370- . as_ref ( )
371- . unwrap ( )
372- . open_tree ( filter:: spec ( filter) )
373- . unwrap ( )
374- } ) ;
375-
376- t. len ( )
377- }
378-
379330 pub fn get_missing ( & self ) -> Vec < ( filter:: Filter , git2:: Oid ) > {
380331 let mut missing = self . t2 . borrow ( ) . missing . clone ( ) ;
381332 missing. sort_by_key ( |( f, i) | ( filter:: nesting ( * f) , * f, * i) ) ;
@@ -404,25 +355,25 @@ impl Transaction {
404355 if filter == filter:: nop ( ) {
405356 return Some ( from) ;
406357 }
407- let mut t2 = self . t2 . borrow_mut ( ) ;
358+ let t2 = self . t2 . borrow_mut ( ) ;
408359 if let Some ( m) = t2. commit_map . get ( & filter. id ( ) ) {
409360 if let Some ( oid) = m. get ( & from) . cloned ( ) {
410361 return Some ( oid) ;
411362 }
412363 }
413- let t = t2. sled_trees . entry ( filter. id ( ) ) . or_insert_with ( || {
414- DB . lock ( )
415- . unwrap ( )
416- . as_ref ( )
417- . unwrap ( )
418- . open_tree ( filter:: spec ( filter) )
419- . unwrap ( )
420- } ) ;
421- if let Some ( oid) = t. get ( from. as_bytes ( ) ) . unwrap ( ) {
422- let oid = git2:: Oid :: from_bytes ( & oid) . unwrap ( ) ;
364+
365+ let oid = t2
366+ . cache
367+ . read_propagate ( filter, from)
368+ . expect ( "Failed to read from cache backend" ) ;
369+
370+ let oid = if let Some ( oid) = oid { Some ( oid) } else { None } ;
371+
372+ if let Some ( oid) = oid {
423373 if oid == git2:: Oid :: zero ( ) {
424374 return Some ( oid) ;
425375 }
376+
426377 if self . repo . odb ( ) . unwrap ( ) . exists ( oid) {
427378 // Only report an object as cached if it exists in the object database.
428379 // This forces a rebuild in case the object was garbage collected.
0 commit comments