1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
#![allow(non_camel_case_types)]
#![feature(is_terminal)]
#![feature(const_trait_impl)]
#![feature(exact_size_is_empty)]
// just for cursor.is_empty()
#![feature(cursor_remaining)]


//! `kv-rs` is a key-value pairs to an append-only log file,
//! and keeps a mapping of keys to file positions in memory.
//! All live keys must fit in memory.
//! Deletes write a tombstone value to the log file.
//! To remove old garbage, logs can be compacted by writing new logs containing only live
//! data, skipping replaced values and tombstones. [Author fengyang]
//!
//! ## Getting started
//!
//! ```rust
//! use std::path::PathBuf;
//! use kv_rs::error::Error;
//! use kv_rs::storage::engine::Engine;
//! use kv_rs::storage::log_cask::LogCask;
//!
//! fn main() {
//!     println!("Hello, kv CLI!");
//!
//!     run().unwrap();
//!
//!     println!("Bye~");
//! }
//!
//! fn run() -> Result<(), Error> {
//!     let storage_path = PathBuf::new().join("D:/workspace/kv/storage/kvdb");
//!     // let storage_path = tempdir::TempDir::new("demo")?.path().join("kvdb");
//!
//!     let mut engine = LogCask::new(storage_path)?;
//!     engine.set(b"b", vec![0x01])?;
//!     engine.set(b"b", vec![0x02])?;
//!
//!     engine.set(b"e", vec![0x05])?;
//!     engine.delete(b"e")?;
//!
//!     engine.set(b"c", vec![0x00])?;
//!     engine.delete(b"c")?;
//!     engine.set(b"c", vec![0x03])?;
//!
//!     engine.set(b"", vec![])?;
//!
//!     engine.set(b"a", vec![0x01])?;
//!
//!     engine.delete(b"f")?;
//!
//!     engine.delete(b"d")?;
//!     engine.set(b"d", vec![0x04])?;
//!
//!     // Make sure the scan yields the expected results.
//!     assert_eq!(
//!             vec![
//!                 (b"".to_vec(), vec![]),
//!                 (b"a".to_vec(), vec![0x01]),
//!                 (b"b".to_vec(), vec![0x02]),
//!                 (b"c".to_vec(), vec![0x03]),
//!                 (b"d".to_vec(), vec![0x04]),
//!             ],
//!             engine.scan(..).collect::<Result<Vec<_>,Error>> ()?,
//!         );
//!
//!     let rs = engine.flush();
//!
//!     Ok(())
//! }
//! ```

pub mod error;
pub mod storage;
pub mod codec;
pub mod mvcc;
pub mod row;
pub mod snapshot;
pub mod info;

#[cfg(test)]
mod test {
    use crate::error::Error;
    use crate::storage::engine::Engine;
    use crate::storage::log_cask::LogCask;

    #[test]
    fn run() -> Result<(), Error> {
        let storage_path = "";
        let path = tempdir::TempDir::new("demo")?.path().join("whosdb");

        let mut engine = LogCask::new(path)?;
        engine.set(b"b", vec![0x01])?;
        engine.set(b"b", vec![0x02])?;

        engine.set(b"e", vec![0x05])?;
        engine.delete(b"e")?;

        engine.set(b"c", vec![0x00])?;
        engine.delete(b"c")?;
        engine.set(b"c", vec![0x03])?;

        engine.set(b"", vec![])?;

        engine.set(b"a", vec![0x01])?;

        engine.delete(b"f")?;

        engine.delete(b"d")?;
        engine.set(b"d", vec![0x04])?;

        // Make sure the scan yields the expected results.
        assert_eq!(
            vec![
                (b"".to_vec(), vec![]),
                (b"a".to_vec(), vec![0x01]),
                (b"b".to_vec(), vec![0x02]),
                (b"c".to_vec(), vec![0x03]),
                (b"d".to_vec(), vec![0x04]),
            ],
            engine.scan(..).collect::<Result<Vec<_>,Error>> ()?,
        );

        let rs = engine.flush();

        Ok(())
    }
}