3
3
//! 具体实现可以参考:https://github.com/pingcap/talent-plan/blob/master/courses/rust/projects/project-2/src/kv.rs
4
4
5
5
use super :: util:: HandyRwLock ;
6
+ use crate :: { KvsError , Result } ;
6
7
use indexmap:: IndexMap ;
7
8
use std:: {
8
- path:: PathBuf ,
9
+ collections:: { BTreeMap , HashMap } ,
10
+ ffi:: OsStr ,
11
+ fs:: File ,
12
+ io:: { BufReader , Read , Seek , SeekFrom } ,
13
+ ops:: Range ,
14
+ path:: { Path , PathBuf } ,
9
15
sync:: { Arc , RwLock } ,
10
16
} ;
11
17
@@ -24,19 +30,100 @@ struct KVStore {
24
30
/// 对于 CLI,使用 KVStore 类型将加载索引,执行命令,然后退出;对于库使用,它将加载索引,然后执行多个命令,维护索引状态,直到它被删除。
25
31
/// ref: https://github.com/pingcap/talent-plan/blob/master/courses/rust/projects/project-2/README.md#project-spec
26
32
path : PathBuf ,
33
+
34
+ readers : HashMap < u64 , BufReaderWithPos < File > > ,
27
35
inner : Arc < RwLock < IndexMap < Vec < u8 > , Vec < u8 > > > > ,
28
36
}
29
37
30
- impl KVStore {
31
- fn new ( ) -> Self {
32
- KVStore :: from_map ( IndexMap :: new ( ) )
38
+ struct BufReaderWithPos < R : Read + Seek > {
39
+ reader : BufReader < R > ,
40
+ pos : u64 ,
41
+ }
42
+
43
+ impl < R : Read + Seek > BufReaderWithPos < R > {
44
+ fn new ( mut inner : R ) -> Result < Self > {
45
+ let pos = inner. seek ( SeekFrom :: Current ( 0 ) ) ?;
46
+ Ok ( BufReaderWithPos {
47
+ reader : BufReader :: new ( inner) ,
48
+ pos,
49
+ } )
50
+ }
51
+ }
52
+
53
+ // 将目录中的文件列表按名字进行排序,以便得到有序的日志文件列表
54
+ fn sorted_gen_list ( path : PathBuf ) -> Result < Vec < u64 > > {
55
+ let mut gen_list: Vec < u64 > = std:: fs:: read_dir ( & path) ?
56
+ . flat_map ( |res| -> Result < _ > { Ok ( res?. path ( ) ) } )
57
+ . filter ( |path| path. is_file ( ) && path. extension ( ) == Some ( "log" . as_ref ( ) ) )
58
+ . flat_map ( |path| {
59
+ path. file_name ( )
60
+ . and_then ( OsStr :: to_str)
61
+ . map ( |s| s. trim_end_matches ( ".log" ) )
62
+ . map ( str:: parse :: < u64 > )
63
+ } )
64
+ . flatten ( )
65
+ . collect ( ) ;
66
+ gen_list. sort_unstable ( ) ;
67
+ Ok ( gen_list)
68
+ }
69
+
70
+ fn log_path ( dir : & Path , gen : u64 ) -> PathBuf {
71
+ dir. join ( format ! ( "{}.log" , gen ) )
72
+ }
73
+
74
+ /// 通过文件序号,从对应的文件中读取指令并将其加载到内存中(BTreeMap)
75
+ fn load (
76
+ gen : u64 ,
77
+ reader : BufReaderWithPos < File > ,
78
+ index : & mut BTreeMap < String , CommandPos > ,
79
+ ) -> Result < u64 > {
80
+ todo ! ( )
81
+ }
82
+
83
+ /// 命令位置
84
+ struct CommandPos {
85
+ gen : u64 ,
86
+ pos : u64 ,
87
+ len : u64 ,
88
+ }
89
+
90
+ impl From < ( u64 , Range < u64 > ) > for CommandPos {
91
+ fn from ( ( gen, range) : ( u64 , Range < u64 > ) ) -> Self {
92
+ CommandPos {
93
+ gen,
94
+ pos : range. start ,
95
+ len : range. end - range. start ,
96
+ }
33
97
}
98
+ }
34
99
35
- fn from_map ( m : IndexMap < Vec < u8 > , Vec < u8 > > ) -> Self {
36
- KVStore {
37
- inner : Arc :: new ( RwLock :: new ( m) ) ,
38
- path : todo ! ( ) ,
100
+ impl KVStore {
101
+ // fn new() -> Self {
102
+ // KVStore::from_map(IndexMap::new())
103
+ // }
104
+
105
+ fn open ( path : impl Into < PathBuf > ) -> Result < Self > {
106
+ // 打开目录,查看目录中的日志文件列表,将其加载进 kvs
107
+ let path = path. into ( ) ;
108
+ std:: fs:: create_dir_all ( & path) ;
109
+ let mut readers = HashMap :: new ( ) ;
110
+ // 索引以 btree map 的形式存储在内存中
111
+ let mut index = BTreeMap :: new ( ) ;
112
+ let gen_list = sorted_gen_list ( & path) ?;
113
+ let uncompacted = 0 ;
114
+ for & gen in & gen_list {
115
+ let mut reader = BufReaderWithPos :: new ( File :: open ( log_path ( & path, gen) ) ?) ?;
116
+ uncompacted += load ( gen, & mut reader, & mut index) ?;
117
+ readers. insert ( gen, reader) ;
39
118
}
119
+
120
+ let current_gen = gen_list. last ( ) . unwrap_or ( & 0 ) + 1 ;
121
+
122
+ Ok ( KVStore {
123
+ inner : Arc :: new ( RwLock :: new ( ) ) ,
124
+ path : PathBuf :: from ( "./data" ) ,
125
+ readers : BufReaderWithPos :: new ( File :: open ( ) ) ,
126
+ } )
40
127
}
41
128
42
129
fn set ( & mut self , k : Vec < u8 > , v : Vec < u8 > ) -> Option < Vec < u8 > > {
@@ -62,7 +149,7 @@ mod tests {
62
149
let cache_key: Vec < u8 > = "org_1001_info" . as_bytes ( ) . into ( ) ;
63
150
st. set ( cache_key. clone ( ) , "hello org" . as_bytes ( ) . into ( ) ) ;
64
151
assert_eq ! ( st. get( & cache_key) , Some ( "hello org" . as_bytes( ) . into( ) ) ) ;
65
- assert ! ( false ) ;
152
+ // assert!(false);
66
153
}
67
154
68
155
#[ test]
0 commit comments