Skip to content
This repository has been archived by the owner on Oct 14, 2023. It is now read-only.

Memtable相关修改 #12

Merged
merged 3 commits into from
Jan 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ smallkv 是一个列存的、基于LSM架构的存储引擎。
- [x] SSTable
- [ ] MANIFEST
- [x] WAL模块
- [ ] memtable
- [x] memtable
- [ ] 读流程
- [ ] 写流程
- [ ] Compaction模块
Expand Down
46 changes: 46 additions & 0 deletions src/memtable/memtable.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
//
// Created by qianyy on 2023/1/25.
//
#include "skiplist.h"
#include "memtable.h"
#include "utils/codec.h"
#include "log/log.h"

namespace smallkv {
MemTable::MemTable(std::shared_ptr<FreeListAllocate> alloc) : alloc(std::move(alloc)) {
// todo: 优化点:此处应该使用string_view
ordered_table_ = std::make_shared<SkipList<std::string, std::string>>(alloc);
logger = log::get_logger();
}

void MemTable::Insert(OpType op_type,
const std::string_view &key,
const std::string_view &value) {
if (op_type == OpType::kAdd) {
// 新数据插入
ordered_table_->Insert(key.data(), value.data());
} else if (op_type == OpType::kUpdate) {
// todo: 对于原地更新,最好在skiplist中直接提供接口,而不是采用Del-Add的低效方法。
// 旧数据原地更新
ordered_table_->Delete(key.data());
ordered_table_->Insert(key.data(), value.data());
} else if (op_type == OpType::kDeletion) {
// todo 同理,建议直接在skiplist中提供接口
if (ordered_table_->Contains(key.data())) {
ordered_table_->Delete(key.data());
}
ordered_table_->Insert(key.data(), ""); // value="" 表示删除
} else {
logger->error("Unexpected op_type. op_type={}", op_type);
return;
}
}

bool MemTable::Contains(const std::string_view &key) {
return ordered_table_->Contains(key.data());
}

std::optional<std::string> MemTable::Get(const std::string_view &key) {
return ordered_table_->Get(key.data());
}
}
77 changes: 77 additions & 0 deletions src/memtable/memtable.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
//
// Created by qianyy on 2023/1/25.
//
#include <memory>
#include <string>
#include "memtable_config.h"
#include "op_type.h"
#include "log/log.h"

#ifndef SMALLKV_MEMTABLE_H
#define SMALLKV_MEMTABLE_H

namespace smallkv {
template<typename Key, typename Value>
class SkipList;

class FreeListAllocate;

/*
* Insert逻辑:
* 1. Add key, OpType=kAdd
* 1.1 active memtable中不存在key,正常添加即可;
* 1.2 active memtable中存在key,进行原地更新。
*
* 2. Delete key, OpType=kDeletion
* 2.1 active memtable中不存在key,相当于插入<key, nil>
* 2.2 active memtable中存在key,原地更新为<key, nil>
*
*
* */
class MemTable final {
public:
explicit MemTable(std::shared_ptr<FreeListAllocate> alloc);

~MemTable() = default;

MemTable() = delete;

// 禁用拷贝、赋值。
MemTable(const MemTable &) = delete;

MemTable &operator=(const MemTable &) = delete;

inline void Add(const std::string_view &key,
const std::string_view &value) {
this->Insert(OpType::kAdd, key, value);
}

inline void Update(const std::string_view &key,
const std::string_view &value) {
this->Insert(OpType::kUpdate, key, value);
}

inline void Delete(const std::string_view &key) {
this->Insert(OpType::kDeletion, key, "");
}

bool Contains(const std::string_view &key);

// 如果不存在则返回nullopt
std::optional<std::string> Get(const std::string_view &key);

private:
// Add、Update、Delete都属于Insert
// 如果是Delete,则value=""
// OpType = {kDeletion, kAdd, kUpdate}
void Insert(OpType op_type, const std::string_view &key,
const std::string_view &value);

private:
std::shared_ptr<SkipList<std::string, std::string>> ordered_table_;
std::shared_ptr<FreeListAllocate> alloc;
std::shared_ptr<spdlog::logger> logger;
};
}

#endif //SMALLKV_MEMTABLE_H
14 changes: 14 additions & 0 deletions src/memtable/memtable_config.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
//
// Created by qianyy on 2023/1/25.
//

#ifndef SMALLKV_MEMTABLE_CONFIG_H
#define SMALLKV_MEMTABLE_CONFIG_H
namespace smallkv {
struct MemTableConfig {
MemTableConfig() = delete;

static constexpr int MAX_KEY_NUM = 4096; // 超过4096个Key,就新建一个memtable
};
}
#endif //SMALLKV_MEMTABLE_CONFIG_H
14 changes: 14 additions & 0 deletions src/memtable/op_type.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
//
// Created by qianyy on 2023/1/26.
//

#ifndef SMALLKV_OP_TYPE_H
#define SMALLKV_OP_TYPE_H
namespace smallkv {
enum OpType {
kDeletion = 0x1, // 删除
kAdd = 0x2, // 添加
kUpdate = 0x3, // 更新
};
}
#endif //SMALLKV_OP_TYPE_H
95 changes: 67 additions & 28 deletions src/memtable/skiplist.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@
// Created by qianyy on 2023/1/23.
//
#include <memory>
#include <vector>
#include <cstdlib>
#include <utility>
#include <vector>
#include <iostream>
#include <optional>
#include "log/log.h"
#include "memory/allocate.h"
#include "skiplist_config.h"
Expand All @@ -20,22 +21,25 @@ namespace smallkv {
* 注:线程不安全、不支持重复的key插入
*
* */
template<typename Key>
template<typename Key, typename Value>
class SkipList {
class Node;

public:
explicit SkipList(std::shared_ptr<FreeListAllocate> alloc);

// 插入key
void Insert(const Key &key);
// 插入一个新的key
void Insert(const Key &key, const Value &value);

// 删除key
void Delete(const Key &key);

// 存在key则返回true
bool Contains(const Key &key);

// 注:如果要找的key不存在,则返回nullopt
std::optional<Value> Get(const Key &key);

// 仅用于DEBUG:打印表
void OnlyUsedForDebugging_Print_() {
auto p = head_->next[0];
Expand All @@ -47,6 +51,8 @@ namespace smallkv {
std::cout << "============= DEBUG =============" << std::endl;
}

inline int GetSize() { return size; }

private:
int RandomLevel();

Expand All @@ -55,7 +61,7 @@ namespace smallkv {
// 找到key节点的前缀节点,也就是找到key的待插入位置
void FindPrevNode(const Key &key, std::vector<Node *> &prev);

inline Node *NewNode(const Key &key, int level);
inline Node *NewNode(const Key &key, int level, const Value &value);

private:
Node *head_; // 头结点,高度为SkipListConfig::kMaxHeight,不存数据
Expand All @@ -68,8 +74,38 @@ namespace smallkv {
std::shared_ptr<spdlog::logger> logger = log::get_logger();
};

template<typename Key>
void SkipList<Key>::Delete(const Key &key) {
template<typename Key, typename Value>
std::optional<Value> SkipList<Key, Value>::Get(const Key &key) {
int level = GetCurrentHeight() - 1;
auto cur = head_;
while (true) {
auto next = cur->next[level];
if (next == nullptr) {
if (level == 0) {
// 遍历到这里说明key不存在
return std::nullopt;
} else {
--level;
}
} else {
if (next->key == key) {
return next->value; // 找到了
} else if (next->key < key) {
cur = next;
} else if (next->key > key) {
if (level == 0) {
// 遍历到这里说明key不存在
return std::nullopt;
} else {
--level; // 在非最底层遇到了大于key的数,应该下降
}
}
}
}
}

template<typename Key, typename Value>
void SkipList<Key, Value>::Delete(const Key &key) {
if (Contains(key) == false) {
logger->warn("The value you want to delete does not exist. Key={}", key);
return;
Expand Down Expand Up @@ -114,7 +150,7 @@ namespace smallkv {
}
// assert(level_of_target_node > 0);
// assert(level_of_target_node <= prev.size());
logger->info("level_of_target_node={}", level_of_target_node);
// logger->info("level_of_target_node={}", level_of_target_node);
for (int i = 0; i < level_of_target_node; ++i) {
if (prev[i] != nullptr) {
assert(prev[i]->next[i] != nullptr);
Expand All @@ -123,8 +159,8 @@ namespace smallkv {
}
}

template<typename Key>
bool SkipList<Key>::Contains(const Key &key) { // 存在key则返回true
template<typename Key, typename Value>
bool SkipList<Key, Value>::Contains(const Key &key) { // 存在key则返回true
int level = GetCurrentHeight() - 1;
auto cur = head_;
while (true) {
Expand All @@ -151,8 +187,8 @@ namespace smallkv {
}
}

template<typename Key>
void SkipList<Key>::Insert(const Key &key) {
template<typename Key, typename Value>
void SkipList<Key, Value>::Insert(const Key &key, const Value &value) {
if (Contains(key)) {
logger->warn("A duplicate key was inserted. Key={}", key);
return;
Expand All @@ -168,7 +204,7 @@ namespace smallkv {
FindPrevNode(key, prev);
int level_of_new_node = RandomLevel();
max_level = std::max(level_of_new_node, max_level); // 更新最大高度
auto newNode = NewNode(key, level_of_new_node);
auto newNode = NewNode(key, level_of_new_node, value);

for (int i = 0; i < newNode->GetLevel(); ++i) {
if (prev[i] == nullptr) {
Expand All @@ -181,20 +217,20 @@ namespace smallkv {
}
}

template<typename Key>
int SkipList<Key>::GetCurrentHeight() {
template<typename Key, typename Value>
int SkipList<Key, Value>::GetCurrentHeight() {
return max_level;
}

template<typename Key>
typename SkipList<Key>::Node *SkipList<Key>::NewNode(const Key &key, int level) {
template<typename Key, typename Value>
typename SkipList<Key, Value>::Node *SkipList<Key, Value>::NewNode(const Key &key, int level, const Value &value) {
// todo: 不确定FreeListAllocate实现有没有问题,
// 所以此处先使用系统allocator,稳定了再换。
return new Node(key, level);
return new Node(key, level, value);
}

template<typename Key>
void SkipList<Key>::FindPrevNode(
template<typename Key, typename Value>
void SkipList<Key, Value>::FindPrevNode(
const Key &key, std::vector<Node *> &prev) {
int level = GetCurrentHeight() - 1;
auto cur = head_;
Expand All @@ -213,28 +249,30 @@ namespace smallkv {
}
}

template<typename Key>
int SkipList<Key>::RandomLevel() {
template<typename Key, typename Value>
int SkipList<Key, Value>::RandomLevel() {
int level = 1;
while (level < SkipListConfig::kMaxHeight && rand() & 1) {
++level;
}
return level;
}

template<typename Key>
SkipList<Key>::SkipList(std::shared_ptr<FreeListAllocate> alloc)
template<typename Key, typename Value>
SkipList<Key, Value>::SkipList(std::shared_ptr<FreeListAllocate> alloc)
:alloc(std::move(alloc)) {
srand(time(0));
head_ = NewNode("", SkipListConfig::kMaxHeight);
head_ = NewNode("", SkipListConfig::kMaxHeight, "");
max_level = 1;
size = 0;
}

template<typename Key>
class SkipList<Key>::Node {
template<typename Key, typename Value>
class SkipList<Key, Value>::Node {
public:
Node(const Key &key, int level) : key(key) {
Node() = delete;

Node(const Key &key, int level, const Value &value) : key(key), value(value) {
next.resize(level, nullptr);
}

Expand All @@ -243,6 +281,7 @@ namespace smallkv {
inline int GetLevel() { return next.size(); }

const Key key;
Value value;
std::vector<Node *> next;
};
}
Expand Down
Loading