Skip to content

Commit 8e56f2f

Browse files
committed
feat: add sstable
1 parent 21c4e02 commit 8e56f2f

2 files changed

Lines changed: 192 additions & 4 deletions

File tree

src/lib.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
pub mod database;
22
mod mem_table;
3+
mod sstable;
34
mod utils;
45
mod wal;
56
mod wal_iterator;
6-
7-
// mod table;
8-
// mod table_manager;
9-
// mod utils;

src/sstable.rs

Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
use std::fs::{File, OpenOptions};
2+
use std::io::{self, BufRead, BufReader, BufWriter, Read, Seek, SeekFrom, Write};
3+
use std::path::Path;
4+
use std::time::{SystemTime, UNIX_EPOCH};
5+
use std::{u8, usize};
6+
7+
use crate::mem_table::MemTable;
8+
9+
pub struct SSTableEntry {
10+
key: Vec<u8>,
11+
value: Option<Vec<u8>>,
12+
timestamp: u128,
13+
}
14+
15+
pub struct SSTable {
16+
file: BufReader<File>,
17+
offsets: Vec<u64>,
18+
low_key: Vec<u8>,
19+
high_key: Vec<u8>,
20+
}
21+
22+
impl SSTable {
23+
pub fn new(memtable: &MemTable, level: usize, dir: &Path) -> io::Result<SSTable> {
24+
let timestamp = SystemTime::now()
25+
.duration_since(UNIX_EPOCH)
26+
.unwrap()
27+
.as_micros();
28+
29+
let path = Path::new(dir).join(format!("{}/{}.sstable", level, timestamp.to_string()));
30+
let file = OpenOptions::new().append(true).create(true).open(&path)?;
31+
let mut file = BufWriter::new(file);
32+
33+
let mut offsets = Vec::new();
34+
let mut offset = 0;
35+
for item in memtable.entries() {
36+
offsets.push(offset as u64);
37+
38+
file.write_all(&item.key.len().to_le_bytes())?;
39+
file.write_all(&item.key)?;
40+
file.write_all(&(item.deleted as u8).to_le_bytes())?;
41+
if !item.deleted {
42+
file.write_all(&item.value.as_ref().unwrap().len().to_le_bytes())?;
43+
file.write_all(item.value.as_ref().unwrap())?;
44+
}
45+
file.write_all(&timestamp.to_le_bytes())?;
46+
47+
offset += size_of::<usize>()
48+
+ size_of::<usize>()
49+
+ size_of::<u8>()
50+
+ size_of::<u128>()
51+
+ item.key.len()
52+
+ item.value.as_ref().unwrap_or(&vec![]).len();
53+
}
54+
55+
file.flush()?;
56+
57+
let file = OpenOptions::new().read(true).open(&path)?;
58+
let file = BufReader::new(file);
59+
60+
Ok(SSTable {
61+
file,
62+
offsets,
63+
low_key: memtable.entries().first().unwrap().key.clone(),
64+
high_key: memtable.entries().last().unwrap().key.clone(),
65+
})
66+
}
67+
68+
pub fn load_from_path(path: &Path) -> io::Result<SSTable> {
69+
let file = OpenOptions::new().read(true).open(&path)?;
70+
let mut file = BufReader::new(file);
71+
72+
let mut offsets = Vec::new();
73+
let mut offset = 0;
74+
while file.fill_buf()?.len() > 0 {
75+
offsets.push(offset as u64);
76+
77+
let mut buf = [0u8; size_of::<usize>()];
78+
file.read_exact(&mut buf)?;
79+
80+
let key_len = usize::from_le_bytes(buf);
81+
file.consume(key_len);
82+
83+
let mut buf = [0u8; size_of::<u8>()];
84+
file.read_exact(&mut buf)?;
85+
86+
let mut val_len = 0;
87+
if buf[0] != 0 {
88+
let mut buf = [0u8; size_of::<usize>()];
89+
file.read_exact(&mut buf)?;
90+
91+
val_len = usize::from_le_bytes(buf);
92+
file.consume(key_len);
93+
}
94+
95+
file.consume(size_of::<u128>());
96+
97+
offset += size_of::<usize>()
98+
+ size_of::<usize>()
99+
+ size_of::<u8>()
100+
+ size_of::<u128>()
101+
+ key_len
102+
+ val_len;
103+
}
104+
105+
file.seek(SeekFrom::Start(0))?;
106+
107+
let mut buf = [0u8; size_of::<usize>()];
108+
file.read_exact(&mut buf)?;
109+
110+
let key_len = usize::from_le_bytes(buf);
111+
let mut low_key = vec![0u8; key_len];
112+
file.read_exact(&mut low_key)?;
113+
114+
file.seek(SeekFrom::Start(*offsets.last().unwrap() as u64))?;
115+
116+
let mut buf = [0u8; size_of::<usize>()];
117+
file.read_exact(&mut buf)?;
118+
119+
let key_len = usize::from_le_bytes(buf);
120+
let mut high_key = vec![0u8; key_len];
121+
file.read_exact(&mut high_key)?;
122+
123+
Ok(SSTable {
124+
file,
125+
offsets,
126+
low_key,
127+
high_key,
128+
})
129+
}
130+
131+
pub fn key_in_range(&self, key: &[u8]) -> bool {
132+
key >= &self.low_key && key <= &self.high_key
133+
}
134+
135+
pub fn get(&mut self, key: &[u8]) -> io::Result<Option<SSTableEntry>> {
136+
let mut a = 0;
137+
let mut b = 0;
138+
while a <= b {
139+
let m = (a + b) / 2;
140+
let offset = self.offsets[m];
141+
142+
self.file.seek(SeekFrom::Start(offset))?;
143+
144+
let mut buf = [0u8; size_of::<usize>()];
145+
self.file.read_exact(&mut buf)?;
146+
147+
let key_len = usize::from_le_bytes(buf);
148+
let mut table_key = vec![0u8; key_len];
149+
self.file.read_exact(&mut table_key)?;
150+
151+
if key == &table_key {
152+
let mut buf = [0u8; size_of::<u8>()];
153+
self.file.read_exact(&mut buf)?;
154+
155+
let deleted = buf[0] == 1;
156+
157+
let mut val = None;
158+
if !deleted {
159+
let mut buf = [0u8; size_of::<usize>()];
160+
self.file.read_exact(&mut buf)?;
161+
162+
let val_len = usize::from_le_bytes(buf);
163+
let mut table_value = vec![0u8; val_len];
164+
self.file.read_exact(&mut table_value)?;
165+
166+
val = Some(table_value)
167+
}
168+
169+
let mut buf = [0u8; size_of::<u128>()];
170+
self.file.read_exact(&mut buf)?;
171+
172+
let timestamp = u128::from_le_bytes(buf);
173+
174+
return Ok(Some(SSTableEntry {
175+
key: table_key,
176+
value: val,
177+
timestamp,
178+
}));
179+
} else if key > &table_key {
180+
a = m + 1;
181+
} else if key < &table_key {
182+
b = m - 1;
183+
}
184+
}
185+
186+
Ok(None)
187+
}
188+
}
189+
190+
#[cfg(test)]
191+
mod tests {}

0 commit comments

Comments
 (0)