Skip to content

Commit

Permalink
impl memtable
Browse files Browse the repository at this point in the history
  • Loading branch information
summerxwu committed Aug 29, 2023
1 parent 2a8e6c5 commit 433cc89
Show file tree
Hide file tree
Showing 8 changed files with 118 additions and 32 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@ edition = "2021"

[dependencies]
bytes = "1.4.0"
anyhow = "1.0.75"
anyhow = "1.0.75"
8 changes: 4 additions & 4 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
#![allow(unused_variables)]
#![allow(dead_code)]
pub mod blocks;
mod sstable;
mod memtable;
mod util;
pub mod sstable;
pub mod memtable;
pub mod util;

mod iterator;
pub mod iterator;
pub fn add(left: usize, right: usize) -> usize {
left + right
}
Expand Down
57 changes: 46 additions & 11 deletions src/memtable.rs
Original file line number Diff line number Diff line change
@@ -1,25 +1,60 @@
use crate::util::env::FileObject;
use crate::memtable::logger::{LogRecordsBuilder, MemTableLogger, OperationType};
use crate::util::env::{get_global_sequence_number, FileObject};
use anyhow::Result;
use bytes::Bytes;
use std::collections::BTreeMap;

mod logger;

pub struct MemTable {}
pub struct MemTable {
/// table is the sorted searching data structure
/// `key` is the user record key, `value` is the user record value
table: BTreeMap<Bytes, Bytes>,
/// memtable unique sequence number, which represents the related log
/// file number, it is global unique
seq: u64,
logger: MemTableLogger,
}

impl MemTable {
fn new() -> Self {
todo!()
pub fn new() -> Self {
let seq = get_global_sequence_number();
MemTable {
table: BTreeMap::new(),
seq,
logger: MemTableLogger::new(seq),
}
}
fn put(&mut self, key: &[u8], value: &[u8]) -> Result<()> {
todo!()
pub fn put(&mut self, key: &[u8], value: &[u8]) -> Result<()> {
// logging and flushing to disk first
let mut log_record_builder = LogRecordsBuilder::new();
log_record_builder.add(OperationType::PUT, key, value)?;
let ret = self
.logger
.log_and_sync(log_record_builder.build().as_slice());

assert!(ret.is_ok());
self.table
.insert(Bytes::copy_from_slice(key), Bytes::copy_from_slice(value));
Ok(())
}
fn get(&self, key: &[u8]) -> Result<Bytes> {
todo!()
pub fn get(&self, key: &[u8]) -> Option<Bytes> {
match self.table.get(key) {
None => None,
Some(value) => Some(value.clone()),
}
}
fn delete(&mut self, key: &[u8]) -> Result<()> {
todo!()
pub fn delete(&mut self, key: &[u8]) -> Result<()> {
self.put(key,"".as_bytes())
}
fn recover(file: &FileObject) -> Self {
pub fn recover(file: &FileObject) -> Self {
todo!()
}

pub fn seq_num(&self) -> u64 {
self.seq
}
}

#[cfg(test)]
mod tests;
21 changes: 11 additions & 10 deletions src/memtable/logger.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
use crate::util::env::FileObject;
use crate::util::env::{logfile_path, FileObject};
use anyhow::Result;
use bytes::Bytes;

pub struct MemLogger {
pub struct MemTableLogger {
seq: u64,
file_obj: FileObject,
}
impl MemLogger {
fn new(seq: u64) -> Self {
todo!()
impl MemTableLogger {
pub fn new(seq: u64) -> Self {
let file_obj = FileObject::create(logfile_path(seq as usize).as_str()).unwrap();
MemTableLogger { seq, file_obj }
}
fn log_and_sync(&self, log_records: &[LoggerRecord]) -> Result<()> {
pub fn log_and_sync(&self, log_records: &[LoggerRecord]) -> Result<()> {
todo!()
}
}
Expand All @@ -29,20 +30,20 @@ impl LoggerRecord {
}
}

enum OperationType {
pub enum OperationType {
PUT,
DELETE,
}

pub struct LogRecordsBuilder {}
impl LogRecordsBuilder {
fn new() -> Self {
pub fn new() -> Self {
todo!()
}
fn add(&mut self, key: &[u8], value: &[u8]) -> Result<()> {
pub fn add(&mut self, opt: OperationType, key: &[u8], value: &[u8]) -> Result<()> {
todo!()
}
fn build() -> Vec<LoggerRecord> {
pub fn build(&self) -> Vec<LoggerRecord> {
todo!()
}
}
47 changes: 47 additions & 0 deletions src/memtable/tests.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
use crate::memtable::MemTable;
use crate::util::env::logfile_path;

struct RAII {
pub seq: u64,
}

impl Drop for RAII {
fn drop(&mut self) {
std::fs::remove_file(logfile_path(self.seq as usize)).expect("Testing expect");
}
}
#[test]
fn test_memtable_put() {
let mut memtable = MemTable::new();
let raii = RAII {
seq: memtable.seq_num(),
};
let ret = memtable.put("key1".as_bytes(), "value1".as_bytes());
assert!(ret.is_ok())
}
#[test]
fn test_memtable_get() {
let mut memtable = MemTable::new();
let raii = RAII {
seq: memtable.seq_num(),
};
let ret = memtable.put("key1".as_bytes(), "value1".as_bytes());
assert!(ret.is_ok());
assert_eq!(memtable.get("key1".as_bytes()),Some("value1".into()));
assert_eq!(memtable.get("key".as_bytes()),None);
}
#[test]
fn test_memtable_remove() {
let mut memtable = MemTable::new();
let raii = RAII {
seq: memtable.seq_num(),
};
let ret = memtable.put("key1".as_bytes(), "value1".as_bytes());
assert!(ret.is_ok());
assert_eq!(memtable.get("key1".as_bytes()),Some("value1".into()));
assert_eq!(memtable.get("key".as_bytes()),None);
let ret = memtable.delete("key1".as_bytes());
assert!(ret.is_ok());
assert_eq!(memtable.get("key1".as_bytes()),None);

}
8 changes: 4 additions & 4 deletions src/sstable.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use std::sync::Arc;
use crate::blocks::iterator::BlockRecordIterator;
use crate::blocks::{Blocks, SIZE_U16};
use crate::iterator::Iterator;
use crate::util::env;
use anyhow::Result;
use bytes::{Buf, BufMut, Bytes, BytesMut};
use std::sync::Arc;

mod iterator;
mod sstable_builder;
Expand All @@ -28,7 +28,7 @@ pub type KVPair = (Bytes, Bytes);
/// index block is basically a data block but the record is consist of a key and a `block pointer`
///
/// index block is of a record sorted. The key of each record in index block is represent the
/// largest key of a data block in current SSTable, the value is the related data `block pointer`.
/// largest key of a data block in current SSTable, the value is the related data `block pointer`
///
/// Records of the index block
/// ``` text
Expand Down Expand Up @@ -85,7 +85,7 @@ impl SSTable {
// read records of each index block pointed by footer
for index_block_pointer in &footer_obj.index_block_pointers {
//read the index block
let buf = file_object.read(index_block_pointer.0 as u64, index_block_pointer.1 )?;
let buf = file_object.read(index_block_pointer.0 as u64, index_block_pointer.1)?;
let index_block_obj = Arc::new(Blocks::decode(buf.as_ref().clone()));
let mut record_iter = BlockRecordIterator::new(index_block_obj);
record_iter.seek_to_first();
Expand Down Expand Up @@ -188,7 +188,7 @@ impl BlockPointer {
BlockPointer(offset, size)
}
}
impl PartialEq for BlockPointer{
impl PartialEq for BlockPointer {
fn eq(&self, other: &Self) -> bool {
self.0 == other.0 && self.1 == other.1
}
Expand Down
4 changes: 2 additions & 2 deletions src/sstable/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,8 @@ fn test_sstable_iterator() {
assert_eq!(sstable_iter.value(), b"value_2".as_slice());
sstable_iter.seek_to_last();
assert!(sstable_iter.is_valid());
assert_eq!(sstable_iter.key(),b"key_100".as_slice());
assert_eq!(sstable_iter.value(),b"value_100".as_slice());
assert_eq!(sstable_iter.key(), b"key_100".as_slice());
assert_eq!(sstable_iter.value(), b"value_100".as_slice());
}
#[test]
fn test_sstable_seek() {
Expand Down
3 changes: 3 additions & 0 deletions src/util/env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,9 @@ impl FileObject {
pub fn sstfile_path(seq: usize) -> String {
format!("/tmp/summer_kv_test/{}.sst", seq)
}
pub fn logfile_path(seq: usize) -> String {
format!("/tmp/summer_kv_test/{}.log", seq)
}
pub fn get_global_sequence_number() -> u64 {
GLOBAL_SEQUENCE_NUMBER.fetch_add(1, Ordering::SeqCst).into()
}
Expand Down

0 comments on commit 433cc89

Please sign in to comment.