Skip to content

Commit 86dea8d

Browse files
committed
update code for kvs
1 parent a42005b commit 86dea8d

File tree

6 files changed

+110
-17
lines changed

6 files changed

+110
-17
lines changed

src/notes/kvs/src/bin/cli_main.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ fn main() {
77
some_init();
88
info!("[kvs] start...");
99
match cli_app() {
10-
Ok(()) => {},
10+
Ok(()) => {}
1111
Err(err) => {
1212
eprintln!("{:?}", err);
1313
}
@@ -26,7 +26,7 @@ enum MyErr {
2626

2727
/// 命令行应用
2828
/// 实现命令行下 KV 数据库的交互,支持 set/get/rm 操作
29-
fn cli_app() ->Result<(), MyErr> {
29+
fn cli_app() -> Result<(), MyErr> {
3030
let matches = App::new("kvs")
3131
.version("0.1.0")
3232
.author("SamuelSu<suhanyujie@qq.com>")

src/notes/kvs/src/error.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,13 @@ pub enum KvsError {
1313
KeyNotFound,
1414

1515
#[fail(display = "error: {}", reason)]
16-
CommonErr {
17-
reason: String
18-
}
16+
CommonErr { reason: String },
1917
}
2018

19+
impl From<io::Error> for KvsError {
20+
fn from(err: io::Error) -> Self {
21+
KvsError::Io(err)
22+
}
23+
}
2124

25+
pub type Result<T> = std::result::Result<T, KvsError>;

src/notes/kvs/src/kv.rs

Lines changed: 96 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,15 @@
33
//! 具体实现可以参考:https://github.com/pingcap/talent-plan/blob/master/courses/rust/projects/project-2/src/kv.rs
44
55
use super::util::HandyRwLock;
6+
use crate::{KvsError, Result};
67
use indexmap::IndexMap;
78
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},
915
sync::{Arc, RwLock},
1016
};
1117

@@ -24,19 +30,100 @@ struct KVStore {
2430
/// 对于 CLI,使用 KVStore 类型将加载索引,执行命令,然后退出;对于库使用,它将加载索引,然后执行多个命令,维护索引状态,直到它被删除。
2531
/// ref: https://github.com/pingcap/talent-plan/blob/master/courses/rust/projects/project-2/README.md#project-spec
2632
path: PathBuf,
33+
34+
readers: HashMap<u64, BufReaderWithPos<File>>,
2735
inner: Arc<RwLock<IndexMap<Vec<u8>, Vec<u8>>>>,
2836
}
2937

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+
}
3397
}
98+
}
3499

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);
39118
}
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+
})
40127
}
41128

42129
fn set(&mut self, k: Vec<u8>, v: Vec<u8>) -> Option<Vec<u8>> {
@@ -62,7 +149,7 @@ mod tests {
62149
let cache_key: Vec<u8> = "org_1001_info".as_bytes().into();
63150
st.set(cache_key.clone(), "hello org".as_bytes().into());
64151
assert_eq!(st.get(&cache_key), Some("hello org".as_bytes().into()));
65-
assert!(false);
152+
// assert!(false);
66153
}
67154

68155
#[test]

src/notes/kvs/src/lib.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@ Rust 中把数据持久化的一种方式是通过 [bincode crate](https://docs.
1010
1111
*/
1212

13+
mod error;
1314
mod kv;
14-
mod util;
1515
mod storage;
16-
mod error;
16+
mod util;
17+
18+
pub use error::{KvsError, Result};

src/notes/kvs/src/storage.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
use bincode::serialize_into;
32
use crc::crc32;
43
use protobuf::Message;

src/notes/kvs/tests/tests.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+

0 commit comments

Comments
 (0)