20
20
//! `LruCache` implementation port from github.com/facebook/rocksdb. The class `LruCache` is
21
21
//! thread-safe, because every operation on cache will be protected by a spin lock.
22
22
use std:: collections:: HashMap ;
23
+ use std:: error:: Error ;
23
24
use std:: future:: Future ;
24
25
use std:: hash:: Hash ;
25
26
use std:: ptr:: null_mut;
26
27
use std:: sync:: atomic:: { AtomicUsize , Ordering } ;
27
28
use std:: sync:: Arc ;
28
29
29
- use futures:: channel:: oneshot:: { channel, Receiver , Sender } ;
30
+ use futures:: channel:: oneshot:: { channel, Canceled , Receiver , Sender } ;
30
31
use spin:: Mutex ;
31
32
32
- use crate :: hummock:: { HummockError , HummockResult } ;
33
-
34
33
const IN_CACHE : u8 = 1 ;
35
34
const REVERSE_IN_CACHE : u8 = !IN_CACHE ;
36
35
@@ -520,20 +519,22 @@ impl<K: LruKey, T: LruValue> LruCacheShard<K, T> {
520
519
}
521
520
522
521
// Clears the content of the cache.
523
- // This method only works if no cache entries are referenced outside.
524
- fn clear ( & mut self ) {
522
+ // This method is safe to use only if no cache entries are referenced outside.
523
+ unsafe fn clear ( & mut self ) {
525
524
while !std:: ptr:: eq ( self . lru . next , self . lru . as_mut ( ) ) {
526
525
let handle = self . lru . next ;
527
- unsafe {
528
- self . erase ( ( * handle) . hash , ( * handle) . get_key ( ) ) ;
529
- }
526
+ self . erase ( ( * handle) . hash , ( * handle) . get_key ( ) ) ;
530
527
}
531
528
}
532
529
}
533
530
534
531
impl < K : LruKey , T : LruValue > Drop for LruCacheShard < K , T > {
535
532
fn drop ( & mut self ) {
536
- self . clear ( ) ;
533
+ // Since the shard is being drop, there must be no cache entries referenced outside. So we
534
+ // are safe to call clear.
535
+ unsafe {
536
+ self . clear ( ) ;
537
+ }
537
538
}
538
539
}
539
540
@@ -674,8 +675,10 @@ impl<K: LruKey, T: LruValue> LruCache<K, T> {
674
675
hash as usize % self . shards . len ( )
675
676
}
676
677
677
- #[ cfg( test) ]
678
- pub fn clear ( & self ) {
678
+ /// # Safety
679
+ ///
680
+ /// This method can only be called when no cache entry are referenced outside.
681
+ pub unsafe fn clear ( & self ) {
679
682
for shard in & self . shards {
680
683
let mut shard = shard. lock ( ) ;
681
684
shard. clear ( ) ;
@@ -684,30 +687,31 @@ impl<K: LruKey, T: LruValue> LruCache<K, T> {
684
687
}
685
688
686
689
impl < K : LruKey + Clone , T : LruValue > LruCache < K , T > {
687
- pub async fn lookup_with_request_dedup < F , VC > (
690
+ pub async fn lookup_with_request_dedup < F , E , VC > (
688
691
self : & Arc < Self > ,
689
692
hash : u64 ,
690
693
key : K ,
691
694
fetch_value : F ,
692
- ) -> HummockResult < CachableEntry < K , T > >
695
+ ) -> Result < Result < CachableEntry < K , T > , E > , Canceled >
693
696
where
694
697
F : FnOnce ( ) -> VC ,
695
- VC : Future < Output = HummockResult < ( T , usize ) > > ,
698
+ E : Error ,
699
+ VC : Future < Output = Result < ( T , usize ) , E > > ,
696
700
{
697
701
match self . lookup_for_request ( hash, key. clone ( ) ) {
698
- LookupResult :: Cached ( entry) => Ok ( entry) ,
702
+ LookupResult :: Cached ( entry) => Ok ( Ok ( entry) ) ,
699
703
LookupResult :: WaitPendingRequest ( recv) => {
700
- let entry = recv. await . map_err ( HummockError :: other ) ?;
701
- Ok ( entry)
704
+ let entry = recv. await ?;
705
+ Ok ( Ok ( entry) )
702
706
}
703
707
LookupResult :: Miss => match fetch_value ( ) . await {
704
708
Ok ( ( value, charge) ) => {
705
709
let entry = self . insert ( key, hash, charge, value) ;
706
- Ok ( entry)
710
+ Ok ( Ok ( entry) )
707
711
}
708
712
Err ( e) => {
709
713
self . clear_pending_request ( & key, hash) ;
710
- Err ( e)
714
+ Ok ( Err ( e) )
711
715
}
712
716
} ,
713
717
}
@@ -753,8 +757,6 @@ mod tests {
753
757
use rand:: { RngCore , SeedableRng } ;
754
758
755
759
use super :: * ;
756
- use crate :: hummock:: cache:: LruHandle ;
757
- use crate :: hummock:: LruCache ;
758
760
759
761
pub struct Block {
760
762
pub offset : u64 ,
0 commit comments