2024-01-19 17:28:47 +08:00
|
|
|
use std::fs::{File, OpenOptions};
|
2024-01-25 21:53:47 +08:00
|
|
|
use std::hash::Hasher;
|
2024-01-28 14:08:08 +08:00
|
|
|
use std::io::{BufWriter, Read, Write};
|
2024-01-19 11:21:38 +08:00
|
|
|
use std::path::Path;
|
2024-01-19 17:28:47 +08:00
|
|
|
use std::sync::Arc;
|
2024-01-19 11:21:38 +08:00
|
|
|
|
2024-01-25 21:53:47 +08:00
|
|
|
use anyhow::{bail, Context, Result};
|
2024-01-19 17:28:47 +08:00
|
|
|
use bytes::{Buf, BufMut, Bytes};
|
|
|
|
|
use crossbeam_skiplist::SkipMap;
|
|
|
|
|
use parking_lot::Mutex;
|
2024-01-19 11:21:38 +08:00
|
|
|
|
2024-01-19 17:28:47 +08:00
|
|
|
pub struct Wal {
|
2024-01-28 14:08:08 +08:00
|
|
|
file: Arc<Mutex<BufWriter<File>>>,
|
2024-01-19 17:28:47 +08:00
|
|
|
}
|
2024-01-19 11:21:38 +08:00
|
|
|
|
|
|
|
|
impl Wal {
|
|
|
|
|
pub fn create(path: impl AsRef<Path>) -> Result<Self> {
|
2024-01-19 17:28:47 +08:00
|
|
|
Ok(Self {
|
2024-01-28 14:08:08 +08:00
|
|
|
file: Arc::new(Mutex::new(BufWriter::new(
|
2024-01-19 17:28:47 +08:00
|
|
|
OpenOptions::new()
|
|
|
|
|
.read(true)
|
|
|
|
|
.create_new(true)
|
|
|
|
|
.write(true)
|
|
|
|
|
.open(path)
|
|
|
|
|
.context("failed to create WAL")?,
|
2024-01-28 14:08:08 +08:00
|
|
|
))),
|
2024-01-19 17:28:47 +08:00
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn recover(path: impl AsRef<Path>, skiplist: &SkipMap<Bytes, Bytes>) -> Result<Self> {
|
|
|
|
|
let path = path.as_ref();
|
|
|
|
|
let mut file = OpenOptions::new()
|
|
|
|
|
.read(true)
|
|
|
|
|
.append(true)
|
|
|
|
|
.open(path)
|
|
|
|
|
.context("failed to recover from WAL")?;
|
|
|
|
|
let mut buf = Vec::new();
|
|
|
|
|
file.read_to_end(&mut buf)?;
|
|
|
|
|
let mut rbuf: &[u8] = buf.as_slice();
|
|
|
|
|
while rbuf.has_remaining() {
|
2024-01-25 21:53:47 +08:00
|
|
|
let mut hasher = crc32fast::Hasher::new();
|
2024-01-19 17:28:47 +08:00
|
|
|
let key_len = rbuf.get_u16() as usize;
|
2024-01-25 21:53:47 +08:00
|
|
|
hasher.write_u16(key_len as u16);
|
2024-01-19 17:28:47 +08:00
|
|
|
let key = Bytes::copy_from_slice(&rbuf[..key_len]);
|
2024-01-25 21:53:47 +08:00
|
|
|
hasher.write(&key);
|
2024-01-19 17:28:47 +08:00
|
|
|
rbuf.advance(key_len);
|
|
|
|
|
let value_len = rbuf.get_u16() as usize;
|
2024-01-25 21:53:47 +08:00
|
|
|
hasher.write_u16(value_len as u16);
|
2024-01-19 17:28:47 +08:00
|
|
|
let value = Bytes::copy_from_slice(&rbuf[..value_len]);
|
2024-01-25 21:53:47 +08:00
|
|
|
hasher.write(&value);
|
2024-01-19 17:28:47 +08:00
|
|
|
rbuf.advance(value_len);
|
2024-01-25 21:53:47 +08:00
|
|
|
let checksum = rbuf.get_u32();
|
|
|
|
|
if hasher.finalize() != checksum {
|
|
|
|
|
bail!("checksum mismatch");
|
|
|
|
|
}
|
2024-01-19 17:28:47 +08:00
|
|
|
skiplist.insert(key, value);
|
|
|
|
|
}
|
|
|
|
|
Ok(Self {
|
2024-01-28 14:08:08 +08:00
|
|
|
file: Arc::new(Mutex::new(BufWriter::new(file))),
|
2024-01-19 17:28:47 +08:00
|
|
|
})
|
2024-01-19 11:21:38 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn put(&self, key: &[u8], value: &[u8]) -> Result<()> {
|
2024-01-19 17:28:47 +08:00
|
|
|
let mut file = self.file.lock();
|
|
|
|
|
let mut buf: Vec<u8> =
|
|
|
|
|
Vec::with_capacity(key.len() + value.len() + std::mem::size_of::<u16>());
|
2024-01-25 21:53:47 +08:00
|
|
|
let mut hasher = crc32fast::Hasher::new();
|
|
|
|
|
hasher.write_u16(key.len() as u16);
|
2024-01-19 17:28:47 +08:00
|
|
|
buf.put_u16(key.len() as u16);
|
2024-01-25 21:53:47 +08:00
|
|
|
hasher.write(key);
|
2024-01-19 17:28:47 +08:00
|
|
|
buf.put_slice(key);
|
2024-01-25 21:53:47 +08:00
|
|
|
hasher.write_u16(value.len() as u16);
|
2024-01-19 17:28:47 +08:00
|
|
|
buf.put_u16(value.len() as u16);
|
|
|
|
|
buf.put_slice(value);
|
2024-01-25 21:53:47 +08:00
|
|
|
hasher.write(value);
|
|
|
|
|
// add checksum: week 2 day 7
|
|
|
|
|
buf.put_u32(hasher.finalize());
|
2024-01-19 17:44:38 +08:00
|
|
|
file.write_all(&buf)?;
|
2024-01-19 11:21:38 +08:00
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
2024-07-02 20:23:33 -04:00
|
|
|
/// Implement this in week 3, day 5.
|
|
|
|
|
pub fn put_batch(&self, _data: &[(&[u8], &[u8])]) -> Result<()> {
|
|
|
|
|
unimplemented!()
|
|
|
|
|
}
|
|
|
|
|
|
2024-01-19 11:21:38 +08:00
|
|
|
pub fn sync(&self) -> Result<()> {
|
2024-01-28 14:08:08 +08:00
|
|
|
let mut file = self.file.lock();
|
|
|
|
|
file.flush()?;
|
|
|
|
|
file.get_mut().sync_all()?;
|
2024-01-19 11:21:38 +08:00
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
}
|