Skip to content

Commit 6bd954e

Browse files
committed
feat: kvctl add and some bugs fixed
1 parent c77b12b commit 6bd954e

File tree

10 files changed

+160
-17
lines changed

10 files changed

+160
-17
lines changed

CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,12 @@ set(server_src "${server_src};${CMAKE_CURRENT_BINARY_DIR}/../log/log.cc")
2323
file(GLOB_RECURSE client_src "${CMAKE_CURRENT_BINARY_DIR}/../client/*.cc")
2424
set(client_src "${client_src};${CMAKE_CURRENT_BINARY_DIR}/../log/log.cc")
2525

26+
set(kvctl_src "${client_src};${CMAKE_CURRENT_BINARY_DIR}/../kvctl/main.cc")
27+
list(REMOVE_ITEM kvctl_src "${CMAKE_CURRENT_BINARY_DIR}/../client/client_main.cc")
28+
2629
add_executable(kvserver ${server_src})
2730
add_executable(kvclient ${client_src})
31+
add_executable(kvctl ${kvctl_src})
2832
target_link_libraries(kvserver grpc_proto ${_REFLECTION} ${_GRPC_GRPCPP} ${_PROTOBUF_LIBPROTOBUF})
2933
target_link_libraries(kvclient grpc_proto ${_REFLECTION} ${_GRPC_GRPCPP} ${_PROTOBUF_LIBPROTOBUF})
34+
target_link_libraries(kvctl grpc_proto gflags ${_REFLECTION} ${_GRPC_GRPCPP} ${_PROTOBUF_LIBPROTOBUF})

Dockerfile

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
FROM grpc/cxx
2+
LABEL maintainer="[email protected]"
3+
ENV PROJECT_DIR=/server
4+
5+
COPY ./ $PROJECT_DIR/
6+
7+
RUN apt-get update && apt-get install -y cmake && apt-get install -y build-essential && apt-get clean
8+
9+
WORKDIR $PROJECT_DIR/build
10+
11+
RUN cmake .. && make && cd ..

README.md

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,49 @@
11
# A KV high-performance mini-database based on memory and C++17
2+
**This project is inspired by Redis source code.**
3+
4+
# Command line tools
5+
Developed command line tool **kvctl**.
6+
value type:string
7+
```shell
8+
yunfei@ubuntu:~/MiniKV/build$ ./kvctl --key qjx --operate set --value hello
9+
yunfei@ubuntu:~/MiniKV/build$ ./kvctl --key qjx --operate get
10+
11+
hello
12+
```
13+
14+
value type:list
15+
```shell
16+
yunfei@ubuntu:~/MiniKV/build$ ./kvctl --key zyf --operate set --value hello --encoding list
17+
yunfei@ubuntu:~/MiniKV/build$ ./kvctl --key zyf --operate set --value world --encoding list
18+
19+
yunfei@ubuntu:~/MiniKV/build$ ./kvctl --key zyf --operate get
20+
21+
world hello
22+
```
23+
224

325
# build
26+
**Dependencies: grpc, protobuf, gflags**
427
In the project dir, do:
528
```shell
629
cd build && cmake .. && make
730
```
8-
then you can get `kvserver` and `kvclient`.
31+
then you can get `kvserver` and `kvclient`.
32+
33+
# run
34+
```shell
35+
./kvserver
36+
```
37+
38+
# About
39+
- This project is based on the gRPC framework to implement the memory-based KV cache middleware, which realizes the client and server respectively. Support list, string type KV cache, data snapshot and progressive Rehash.
40+
41+
- Communication between client and server is realized based on gRPC, and concurrency security is realized based on read-write lock; The client supports the addition, deletion, modification and query of keys.
42+
43+
- Support data snapshot, background thread timing persistence, based on user-defined data frame format; Service start automaticly to read snapshot.
44+
45+
- The underlying storage structure mimics the design of Redis hash table, solves hash conflicts with zipper method, and realizes automatic memory management with intelligent pointer.
46+
47+
- Imitate Redis to implement the expired key based on the expired hash table, and clean up the expired key through lazy deletion.
48+
49+
- Simulate the design of Redis double hash table, and implement progressive rehash after the background thread calculates the load factor regularly.

client/kvclient.cc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ KVClient::KVClient(std::string ip, uint32_t port) : ip_(ip), port_(port) {
77
}
88

99
int KVClient::setKV(std::string key, std::string val, uint32_t encoding) {
10+
if (key.empty()) return MiniKV_KEY_EMPTY;
1011
kv::ReqKV req;
1112
kv::SetKVResponse res;
1213
req.set_key(key);
@@ -22,6 +23,7 @@ int KVClient::setKV(std::string key, std::string val, uint32_t encoding) {
2223
}
2324

2425
int KVClient::delK(std::string key) {
26+
if (key.empty()) return MiniKV_KEY_EMPTY;
2527
kv::ReqK req;
2628
kv::DelKVResponse res;
2729
req.set_key(key);
@@ -35,6 +37,7 @@ int KVClient::delK(std::string key) {
3537
}
3638

3739
GetRes KVClient::getK(std::string key) {
40+
if (key.empty()) return {};
3841
GetRes ans;
3942
kv::ReqK req;
4043
kv::GetKResponse res;
@@ -58,6 +61,7 @@ GetRes KVClient::getK(std::string key) {
5861
}
5962

6063
int KVClient::setExpires(std::string key, uint64_t millisecond) {
64+
if (key.empty()) return MiniKV_KEY_EMPTY;
6165
auto now = std::chrono::system_clock::now();
6266
auto timestamp = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()).count();
6367
uint64_t expires = timestamp + millisecond;

kvctl/main.cc

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
#include "gflags/gflags.h"
2+
#include "../client/kvclient.h"
3+
4+
DEFINE_string(ip, "localhost", "ip for admin node");
5+
DEFINE_int32(port, 6789, "port for admin node");
6+
DEFINE_string(key, "", "key");
7+
DEFINE_string(value, "", "value");
8+
DEFINE_string(encoding, "string", "encoding, see in encoding.h");
9+
DEFINE_string(operate, "set", "operate, e.g. set, del..");
10+
DEFINE_uint64(expires, 5000, "expire time");
11+
12+
13+
DECLARE_string(ip);
14+
DECLARE_int32(port);
15+
DECLARE_string(key);
16+
DECLARE_string(value);
17+
DECLARE_string(encoding);
18+
DECLARE_string(operate);
19+
DECLARE_uint64(expires);
20+
21+
#include <unordered_map>
22+
std::unordered_map<std::string, int> oper {
23+
{"set", KV_SET},
24+
{"del", KV_DEL},
25+
{"get", KV_GET},
26+
{"expire", KV_EXPIRE}
27+
};
28+
29+
std::unordered_map<std::string, int> enMap {
30+
{"string", MiniKV_STRING},
31+
{"list", MiniKV_LIST},
32+
};
33+
34+
int main(int argc, char* argv[]) {
35+
gflags::ParseCommandLineFlags(&argc, &argv, true);
36+
KVClient* kvclient = new KVClient(FLAGS_ip, FLAGS_port);
37+
std::string encoding = FLAGS_encoding;
38+
std::string operation = FLAGS_operate;
39+
std::string key = FLAGS_key;
40+
std::string val = FLAGS_value;
41+
uint64_t expires = FLAGS_expires;
42+
43+
switch (oper[operation]) {
44+
case KV_SET : {
45+
kvclient->setKV(key, val, enMap[encoding]);
46+
break;
47+
}
48+
case KV_DEL : {
49+
kvclient->delK(key);
50+
break;
51+
}
52+
case KV_GET : {
53+
auto res = kvclient->getK(key);
54+
for (int i = 0; i < res.data.size(); ++i) {
55+
std::cout << res.data[i] << " ";
56+
} std::cout << std::endl;
57+
break;
58+
}
59+
case KV_EXPIRE : {
60+
kvclient->setExpires(key, expires);
61+
}
62+
}
63+
64+
return 0;
65+
}

minikv.rdb

-561 Bytes
Binary file not shown.

server/db.cc

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -39,23 +39,30 @@ void MiniKVDB::insert(std::string key, std::string val, uint32_t encoding) {
3939
progressiveRehash(hash2_);
4040
}
4141

42-
void MiniKVDB::get(std::string key, std::vector<std::string>& res) {
43-
// there are 2 cases for empty res:
44-
// 1. exceed the time limit
45-
// 2. no data
42+
bool MiniKVDB::expired(std::string key) {
4643
std::vector<std::string> e;
4744
expires_->get(key, e);
4845
if (!e.empty()) {
4946
uint64_t expires = stoi(e[0]);
5047
auto now = std::chrono::system_clock::now();
5148
auto timestamp = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()).count();
5249
if (timestamp >= expires) {
53-
res = std::vector<std::string>();
54-
hash1_->del(key); // lazy delete mode
55-
expires_->del(key);
56-
return;
50+
return true;
5751
}
5852
}
53+
return false;
54+
}
55+
56+
void MiniKVDB::get(std::string key, std::vector<std::string>& res) {
57+
// there are 2 cases for empty res:
58+
// 1. exceed the time limit
59+
// 2. no data
60+
if (expired(key)) {
61+
res = std::vector<std::string>();
62+
hash1_->del(key); // lazy delete mode
63+
expires_->del(key);
64+
return;
65+
}
5966
if (!rehashFlag_) {
6067
hash1_->get(key, res);
6168
return;
@@ -80,6 +87,7 @@ int MiniKVDB::setExpire(std::string key, uint64_t expires) {
8087
}
8188

8289
void MiniKVDB::rdbSave() {
90+
if (rehashFlag_) return;
8391
// TODO: save the expire time
8492
std::unique_lock<std::shared_mutex> lk(smutex_);
8593
kvlogi("rdb save triggered!");
@@ -91,6 +99,7 @@ void MiniKVDB::rdbSave() {
9199
}
92100
for (auto it = d.begin(); it != d.end(); ++it) {
93101
std::string key = it->get()->key;
102+
if (expired(key)) continue;
94103
uint32_t encoding = it->get()->encoding;
95104
void* data = it->get()->data.get();
96105
saveKVWithEncoding(key, encoding, data);

server/db.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ typedef class MiniKVDB {
5353
void rdbSave();
5454
void rehash();
5555
void progressiveRehash(std::shared_ptr<HashTable> hash2);
56+
bool expired(std::string key);
5657
// void fixedTimeDeleteExpiredKey();
5758
public:
5859
void insert(std::string key, std::string val, uint32_t encoding);

server/hash.h

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -128,14 +128,13 @@ class HashTable {
128128
}
129129
int del(std::string key) {
130130
int slot = hash(key);
131-
bool flag = false;
132-
std::for_each(hash_[slot].begin(), hash_[slot].end(), [&key, &slot, &flag, this](std::shared_ptr<Entry> p) {
133-
if (p.get()->key == key) {
134-
hash_[slot].remove(p);
135-
flag = true;
131+
for (auto it = hash_[slot].begin(); it != hash_[slot].end(); ++it) {
132+
if (it->get()->key == key) {
133+
hash_[slot].remove(*it);
134+
return MiniKV_DEL_SUCCESS;
136135
}
137-
});
138-
return flag ? MiniKV_DEL_SUCCESS : MiniKV_DEL_FAIL;
136+
}
137+
return MiniKV_DEL_FAIL;
139138
}
140139

141140
bool needRehash() {

type/encoding.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,15 @@ enum {
1111
MiniKV_DEL_FAIL,
1212
MiniKV_DEL_SUCCESS,
1313
MiniKV_SET_EXPIRE_SUCCESS,
14-
MiniKV_SET_EXPIRE_FAIL
14+
MiniKV_SET_EXPIRE_FAIL,
15+
MiniKV_KEY_EMPTY
16+
};
17+
18+
enum {
19+
KV_SET = 100,
20+
KV_DEL,
21+
KV_GET,
22+
KV_EXPIRE
1523
};
1624

1725
#endif

0 commit comments

Comments
 (0)