1919//TODO: Mark this module #[test] only
2020
2121use super :: * ;
22- use crate :: key:: CompactCacheKey ;
22+ use crate :: key:: { CompactCacheKey , HashBinary } ;
2323use crate :: storage:: { streaming_write:: U64WriteId , HandleHit , HandleMiss } ;
2424use crate :: trace:: SpanHandle ;
2525
@@ -37,7 +37,7 @@ type BinaryMeta = (Vec<u8>, Vec<u8>);
3737
3838pub ( crate ) struct CacheObject {
3939 pub meta : BinaryMeta ,
40- pub body : Arc < Vec < u8 > > ,
40+ pub body : Bytes ,
4141}
4242
4343pub ( crate ) struct TempObject {
@@ -56,10 +56,10 @@ impl TempObject {
5656 bytes_written : Arc :: new ( tx) ,
5757 }
5858 }
59- // this is not at all optimized
6059 fn make_cache_object ( & self ) -> CacheObject {
6160 let meta = self . meta . clone ( ) ;
62- let body = Arc :: new ( self . body . read ( ) . clone ( ) ) ;
61+ // Convert Vec<u8> to Bytes for zero-copy slicing
62+ let body = Bytes :: from ( self . body . read ( ) . clone ( ) ) ;
6363 CacheObject { meta, body }
6464 }
6565}
@@ -68,8 +68,12 @@ impl TempObject {
6868///
6969/// For testing only, not for production use.
7070pub struct MemCache {
71- pub ( crate ) cached : Arc < RwLock < HashMap < String , CacheObject > > > ,
72- pub ( crate ) temp : Arc < RwLock < HashMap < String , HashMap < u64 , TempObject > > > > ,
71+ // Use HashBinary ([u8; 16]) keys instead of String for better performance:
72+ // - Avoids hex string conversion (6% CPU savings)
73+ // - Smaller key size (16 bytes vs 32+ bytes)
74+ // - No heap allocation for keys
75+ pub ( crate ) cached : Arc < RwLock < HashMap < HashBinary , CacheObject > > > ,
76+ pub ( crate ) temp : Arc < RwLock < HashMap < HashBinary , HashMap < u64 , TempObject > > > > ,
7377 pub ( crate ) last_temp_id : AtomicU64 ,
7478}
7579
@@ -96,7 +100,7 @@ enum PartialState {
96100}
97101
98102pub struct CompleteHit {
99- body : Arc < Vec < u8 > > ,
103+ body : Bytes ,
100104 done : bool ,
101105 range_start : usize ,
102106 range_end : usize ,
@@ -108,9 +112,8 @@ impl CompleteHit {
108112 None
109113 } else {
110114 self . done = true ;
111- Some ( Bytes :: copy_from_slice (
112- & self . body . as_slice ( ) [ self . range_start ..self . range_end ] ,
113- ) )
115+ // Zero-copy slice instead of copy_from_slice
116+ Some ( self . body . slice ( self . range_start ..self . range_end ) )
114117 }
115118 }
116119
@@ -236,12 +239,12 @@ pub struct MemMissHandler {
236239 body : Arc < RwLock < Vec < u8 > > > ,
237240 bytes_written : Arc < watch:: Sender < PartialState > > ,
238241 // these are used only in finish() to data from temp to cache
239- key : String ,
242+ key : HashBinary ,
240243 temp_id : U64WriteId ,
241244 // key -> cache object
242- cache : Arc < RwLock < HashMap < String , CacheObject > > > ,
245+ cache : Arc < RwLock < HashMap < HashBinary , CacheObject > > > ,
243246 // key -> (temp writer id -> temp object) to support concurrent writers
244- temp : Arc < RwLock < HashMap < String , HashMap < u64 , TempObject > > > > ,
247+ temp : Arc < RwLock < HashMap < HashBinary , HashMap < u64 , TempObject > > > > ,
245248}
246249
247250#[ async_trait]
@@ -273,7 +276,8 @@ impl HandleMiss for MemMissHandler {
273276 . unwrap ( )
274277 . make_cache_object ( ) ;
275278 let size = cache_object. body . len ( ) ; // FIXME: this just body size, also track meta size
276- self . cache . write ( ) . insert ( self . key . clone ( ) , cache_object) ;
279+
280+ self . cache . write ( ) . insert ( self . key , cache_object) ;
277281 self . temp
278282 . write ( )
279283 . get_mut ( & self . key )
@@ -313,7 +317,8 @@ impl Storage for MemCache {
313317 key : & CacheKey ,
314318 _trace : & SpanHandle ,
315319 ) -> Result < Option < ( CacheMeta , HitHandler ) > > {
316- let hash = key. combined ( ) ;
320+ // Use combined_bin() to get binary hash directly, avoiding hex string conversion
321+ let hash = key. combined_bin ( ) ;
317322 // always prefer partial read otherwise fresh asset will not be visible on expired asset
318323 // until it is fully updated
319324 // no preference on which partial read we get (if there are multiple writers)
@@ -345,7 +350,7 @@ impl Storage for MemCache {
345350 streaming_write_tag : Option < & [ u8 ] > ,
346351 _trace : & SpanHandle ,
347352 ) -> Result < Option < ( CacheMeta , HitHandler ) > > {
348- let hash = key. combined ( ) ;
353+ let hash = key. combined_bin ( ) ;
349354 let write_tag: U64WriteId = streaming_write_tag
350355 . expect ( "tag must be set during streaming write" )
351356 . try_into ( )
@@ -365,14 +370,15 @@ impl Storage for MemCache {
365370 meta : & CacheMeta ,
366371 _trace : & SpanHandle ,
367372 ) -> Result < MissHandler > {
368- let hash = key. combined ( ) ;
373+ let hash = key. combined_bin ( ) ;
369374 let meta = meta. serialize ( ) ?;
370375 let temp_obj = TempObject :: new ( meta) ;
371376 let temp_id = self . last_temp_id . fetch_add ( 1 , Ordering :: Relaxed ) ;
372377 let miss_handler = MemMissHandler {
373378 body : temp_obj. body . clone ( ) ,
374379 bytes_written : temp_obj. bytes_written . clone ( ) ,
375- key : hash. clone ( ) ,
380+
381+ key : hash,
376382 cache : self . cached . clone ( ) ,
377383 temp : self . temp . clone ( ) ,
378384 temp_id : temp_id. into ( ) ,
@@ -393,7 +399,7 @@ impl Storage for MemCache {
393399 ) -> Result < bool > {
394400 // This usually purges the primary key because, without a lookup, the variance key is usually
395401 // empty
396- let hash = key. combined ( ) ;
402+ let hash = key. combined_bin ( ) ;
397403 let temp_removed = self . temp . write ( ) . remove ( & hash) . is_some ( ) ;
398404 let cache_removed = self . cached . write ( ) . remove ( & hash) . is_some ( ) ;
399405 Ok ( temp_removed || cache_removed)
@@ -405,7 +411,7 @@ impl Storage for MemCache {
405411 meta : & CacheMeta ,
406412 _trace : & SpanHandle ,
407413 ) -> Result < bool > {
408- let hash = key. combined ( ) ;
414+ let hash = key. combined_bin ( ) ;
409415 if let Some ( obj) = self . cached . write ( ) . get_mut ( & hash) {
410416 obj. meta = meta. serialize ( ) ?;
411417 Ok ( true )
@@ -598,7 +604,7 @@ mod test {
598604 let cache = & MEM_CACHE ;
599605
600606 let key = CacheKey :: new ( "" , "a" , "1" ) . to_compact ( ) ;
601- let hash = key. combined ( ) ;
607+ let hash = key. combined_bin ( ) ;
602608 let meta = (
603609 "meta_key" . as_bytes ( ) . to_vec ( ) ,
604610 "meta_value" . as_bytes ( ) . to_vec ( ) ,
@@ -607,7 +613,8 @@ mod test {
607613 let temp_obj = TempObject :: new ( meta) ;
608614 let mut map = HashMap :: new ( ) ;
609615 map. insert ( 0 , temp_obj) ;
610- cache. temp . write ( ) . insert ( hash. clone ( ) , map) ;
616+
617+ cache. temp . write ( ) . insert ( hash, map) ;
611618
612619 assert ! ( cache. temp. read( ) . contains_key( & hash) ) ;
613620
@@ -625,17 +632,18 @@ mod test {
625632 let cache = & MEM_CACHE ;
626633
627634 let key = CacheKey :: new ( "" , "a" , "1" ) . to_compact ( ) ;
628- let hash = key. combined ( ) ;
635+ let hash = key. combined_bin ( ) ;
629636 let meta = (
630637 "meta_key" . as_bytes ( ) . to_vec ( ) ,
631638 "meta_value" . as_bytes ( ) . to_vec ( ) ,
632639 ) ;
633640 let body = vec ! [ 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 0 ] ;
634641 let cache_obj = CacheObject {
635642 meta,
636- body : Arc :: new ( body) ,
643+ body : Bytes :: from ( body) ,
637644 } ;
638- cache. cached . write ( ) . insert ( hash. clone ( ) , cache_obj) ;
645+
646+ cache. cached . write ( ) . insert ( hash, cache_obj) ;
639647
640648 assert ! ( cache. cached. read( ) . contains_key( & hash) ) ;
641649
0 commit comments