1
1
//! Storage primitive which is used to interact with Keys
2
2
3
3
use std:: hash:: BuildHasherDefault ;
4
+ use std:: mem:: size_of_val;
4
5
use std:: sync:: atomic:: AtomicU32 ;
5
6
use std:: sync:: Arc ;
6
7
7
8
use bytes:: Bytes ;
8
9
use bytestring:: ByteString ;
9
10
use coarsetime:: Instant ;
11
+ use rand:: random;
10
12
use rustc_hash:: FxHasher ;
11
13
use scc:: HashMap ;
12
14
@@ -16,14 +18,14 @@ use crate::infrastructure::hash::HASH_SLOT_MAX;
16
18
#[ derive( Debug ) ]
17
19
pub struct StorageValue {
18
20
pub expired : Option < Instant > ,
19
- pub val : Bytes ,
21
+ pub val : Vec < u8 > ,
20
22
}
21
23
22
24
/// A [StorageSegment] is shared across multiple threads and owns a part of the
23
25
/// hashing keys.
24
26
#[ derive( Debug , Clone ) ]
25
27
pub struct StorageSegment {
26
- db : Arc < HashMap < ByteString , StorageValue , BuildHasherDefault < FxHasher > > > ,
28
+ db : Arc < HashMap < Vec < u8 > , StorageValue , BuildHasherDefault < FxHasher > > > ,
27
29
slot : Slot ,
28
30
count : Arc < AtomicU32 > ,
29
31
}
@@ -36,15 +38,17 @@ pub struct SetOptions {
36
38
impl StorageSegment {
37
39
/// Create a new [StorageSegment] by specifying the hash slot it handles.
38
40
pub fn new ( slot : Slot ) -> Self {
39
- for _ in 0 ..4096 {
41
+ let h = HashMap :: with_capacity_and_hasher (
42
+ 2usize . pow ( 20 ) ,
43
+ Default :: default ( ) ,
44
+ ) ;
45
+
46
+ for _ in 0 ..( 2usize . pow ( 20 ) ) {
40
47
drop ( scc:: ebr:: Guard :: new ( ) ) ;
41
48
}
42
49
43
50
Self {
44
- db : Arc :: new ( HashMap :: with_capacity_and_hasher (
45
- 4096 ,
46
- Default :: default ( ) ,
47
- ) ) ,
51
+ db : Arc :: new ( h) ,
48
52
slot,
49
53
count : Arc :: new ( AtomicU32 :: new ( 0 ) ) ,
50
54
}
@@ -54,36 +58,31 @@ impl StorageSegment {
54
58
self . slot . contains ( & i)
55
59
}
56
60
57
- /// Set a key
58
- pub async fn set_async (
61
+ /// Set a key into the storage
62
+ pub fn set_async (
59
63
& self ,
60
64
key : ByteString ,
61
65
val : Bytes ,
62
66
opt : SetOptions ,
63
67
) -> Result < Option < StorageValue > , ( String , StorageValue ) > {
68
+ let mut val = val. to_vec ( ) ;
69
+ val. shrink_to_fit ( ) ;
70
+
64
71
let val = StorageValue {
65
72
expired : opt. expired ,
66
73
val,
67
74
} ;
68
75
69
- let _old = self
76
+ let mut key = key. into_bytes ( ) . to_vec ( ) ;
77
+ key. shrink_to_fit ( ) ;
78
+
79
+ let old = self
70
80
. count
71
81
. fetch_add ( 1 , std:: sync:: atomic:: Ordering :: Relaxed ) ;
72
- /*
73
- // Simulate some eviction mechanisme when we have too many keys
74
- if old > 200_000 {
75
- // dbg!("remove");
76
- // TODO: If the RC is for the DB instead, we could have a spawn from
77
- // monoio for this task instead, it would save us some
78
- // time for the p99.9
79
- let count = self.count.clone();
80
- let db = self.db.clone();
81
- monoio::spawn(async move {
82
- db.retain_async(|_, _| false).await;
83
- count.swap(0, std::sync::atomic::Ordering::Relaxed);
84
- });
82
+
83
+ if old % 1_000_000 == 0 {
84
+ dbg ! ( old) ;
85
85
}
86
- */
87
86
88
87
if let Err ( ( key, val) ) = self . db . insert ( key, val) {
89
88
let old = self . db . update ( & key, |_, _| val) ;
@@ -101,6 +100,9 @@ impl StorageSegment {
101
100
key : ByteString ,
102
101
now : Instant ,
103
102
) -> Option < Bytes > {
103
+ let mut key = key. into_bytes ( ) . to_vec ( ) ;
104
+ key. shrink_to_fit ( ) ;
105
+
104
106
match self . db . entry_async ( key) . await {
105
107
scc:: hash_map:: Entry :: Occupied ( oqp) => {
106
108
let val = oqp. get ( ) ;
@@ -109,10 +111,10 @@ impl StorageSegment {
109
111
110
112
// TODO: Better handle expiration
111
113
if is_expired {
112
- // oqp.remove()? ;
114
+ let _ = oqp. remove ( ) ;
113
115
None
114
116
} else {
115
- Some ( val. val . clone ( ) )
117
+ Some ( Bytes :: from ( val. val . clone ( ) ) )
116
118
}
117
119
}
118
120
scc:: hash_map:: Entry :: Vacant ( _) => None ,
0 commit comments