@@ -5,12 +5,18 @@ use std::collections::BTreeMap;
5
5
use std:: fs:: { self , File } ;
6
6
use std:: io:: { BufReader , BufWriter , Seek , SeekFrom , Write } ;
7
7
use std:: path:: PathBuf ;
8
+ use std:: sync:: { Arc , Mutex } ;
8
9
9
10
const COMPACTION_THRESHOLD : u64 = 1024 ;
10
11
const LOG_FILE_NAME : & str = "current.db" ;
11
12
12
- #[ derive( Debug ) ]
13
+ #[ derive( Debug , Clone ) ]
13
14
pub struct KvStore {
15
+ inner : Arc < Mutex < InnerKvStore > > ,
16
+ }
17
+
18
+ #[ derive( Debug ) ]
19
+ struct InnerKvStore {
14
20
path : PathBuf ,
15
21
log : File ,
16
22
map : BTreeMap < String , LogPointer > ,
@@ -36,44 +42,53 @@ struct LogPointer {
36
42
}
37
43
38
44
impl KvsEngine for KvStore {
39
- fn set ( & mut self , key : String , value : String ) -> Result < ( ) > {
40
- let offset = self . log . seek ( SeekFrom :: End ( 0 ) ) ?;
45
+ fn set ( & self , key : String , value : String ) -> Result < ( ) > {
46
+ let mut inner = self . inner . lock ( ) . unwrap ( ) ;
47
+
48
+ let offset = inner. log . seek ( SeekFrom :: End ( 0 ) ) ?;
41
49
let command = Command {
42
50
cmd : CommandType :: Set ,
43
51
key : key. clone ( ) ,
44
52
value,
45
53
} ;
46
54
// encoding before writing to log
47
- serde_json:: to_writer ( & mut self . log , & command) ?;
48
- self . log . flush ( ) ?;
49
- let current_offset = self . log . seek ( SeekFrom :: End ( 0 ) ) ?;
50
- self . map . insert (
55
+ serde_json:: to_writer ( & mut inner . log , & command) ?;
56
+ inner . log . flush ( ) ?;
57
+ let current_offset = inner . log . seek ( SeekFrom :: End ( 0 ) ) ?;
58
+ inner . map . insert (
51
59
key,
52
60
LogPointer {
53
61
offset,
54
62
len : current_offset - offset,
55
63
} ,
56
64
) ;
57
65
if current_offset > COMPACTION_THRESHOLD {
58
- self . compact ( ) ?;
66
+ inner . compact ( ) ?;
59
67
}
60
68
Ok ( ( ) )
61
69
}
62
70
63
- fn get ( & mut self , key : String ) -> Result < Option < String > > {
64
- if let Some ( pointer) = self . map . get ( & key) {
65
- & self . log . seek ( SeekFrom :: Start ( pointer. offset ) ) ;
66
- let mut de = serde_json:: Deserializer :: from_reader ( & self . log ) ;
67
- let cmd: Command = serde:: de:: Deserialize :: deserialize ( & mut de) ?;
68
- Ok ( Some ( cmd. value ) )
69
- } else {
70
- Ok ( None )
71
+ fn get ( & self , key : String ) -> Result < Option < String > > {
72
+ let mut inner = self . inner . lock ( ) . unwrap ( ) ;
73
+
74
+ if !inner. map . contains_key ( & key) {
75
+ return Ok ( None ) ;
71
76
}
77
+
78
+ let pointer = inner. map . get ( & key) . unwrap ( ) ;
79
+ let pos = SeekFrom :: Start ( pointer. offset ) ;
80
+
81
+ inner. log . seek ( pos) ?;
82
+ let mut de = serde_json:: Deserializer :: from_reader ( & inner. log ) ;
83
+ let cmd: Command = serde:: de:: Deserialize :: deserialize ( & mut de) ?;
84
+ Ok ( Some ( cmd. value ) )
72
85
}
73
86
74
- fn remove ( & mut self , key : String ) -> Result < ( ) > {
75
- self . log . seek ( SeekFrom :: End ( 0 ) ) ?;
76
- if self . map . get ( & key) . is_none ( ) {
87
+ fn remove ( & self , key : String ) -> Result < ( ) > {
88
+ let mut inner = self . inner . lock ( ) . unwrap ( ) ;
89
+
90
+ inner. log . seek ( SeekFrom :: End ( 0 ) ) ?;
91
+ if inner. map . get ( & key) . is_none ( ) {
77
92
return Err ( KvsError :: KeyNotFound ) ;
78
93
}
79
94
let command = Command {
@@ -82,30 +97,35 @@ impl KvsEngine for KvStore {
82
97
value : String :: new ( ) ,
83
98
} ;
84
99
// encoding before writing to log
85
- serde_json:: to_writer ( & mut self . log , & command) ?;
86
- self . log . flush ( ) ?;
87
- self . map . remove ( & key) ;
100
+ serde_json:: to_writer ( & mut inner . log , & command) ?;
101
+ inner . log . flush ( ) ?;
102
+ inner . map . remove ( & key) ;
88
103
Ok ( ( ) )
89
104
}
90
105
}
91
106
92
107
impl KvStore {
93
108
pub fn open ( path : impl Into < PathBuf > ) -> Result < KvStore > {
94
109
let path = path. into ( ) ;
95
- fs:: create_dir_all ( & path) ?;
96
- let log = Self :: new_log_file ( & path) ?;
110
+ fs:: create_dir_all ( & * path) ?;
111
+ let log = InnerKvStore :: new_log_file ( & path) ?;
97
112
98
- let mut store = KvStore {
99
- path : path ,
100
- log : log ,
113
+ let mut inner = InnerKvStore {
114
+ path,
115
+ log,
101
116
map : BTreeMap :: new ( ) ,
102
117
} ;
103
118
104
119
// Load from log files
105
- store. load_from_log ( ) ?;
106
- Ok ( store)
120
+ inner. load_from_log ( ) ?;
121
+
122
+ Ok ( KvStore {
123
+ inner : Arc :: new ( Mutex :: new ( inner) ) ,
124
+ } )
107
125
}
126
+ }
108
127
128
+ impl InnerKvStore {
109
129
fn load_from_log ( & mut self ) -> Result < ( ) > {
110
130
let mut reader = BufReader :: new ( File :: open ( & self . path . join ( LOG_FILE_NAME ) ) ?) ;
111
131
let mut offset = reader. seek ( SeekFrom :: Start ( 0 ) ) ?;
@@ -141,7 +161,7 @@ impl KvStore {
141
161
Ok ( ( ) )
142
162
}
143
163
144
- fn compact ( & mut self ) -> Result < ( ) > {
164
+ fn compact ( & self ) -> Result < ( ) > {
145
165
let tmp_path: PathBuf = self . path . join ( "tmp.db" ) ;
146
166
let file_path: PathBuf = self . path . join ( LOG_FILE_NAME ) ;
147
167
let mut work_file = self . log . try_clone ( ) ?;
0 commit comments