├── .gitignore
├── .gitmodules
├── CMakeLists.txt
├── README.md
├── crash-recover-test
├── CMakeLists.txt
├── test_crash_client.cc
└── test_crash_server.cc
├── documents
└── fast23_FUSEE_Extended_Version.pdf
├── micro-test
├── CMakeLists.txt
├── gen-micro-workload.py
├── latency_test.cc
├── latency_test.h
├── latency_test_client.cc
├── latency_test_client_cr.cc
├── micro_test.cc
├── micro_test.h
├── micro_test_multi_client.cc
└── micro_test_multi_client_cr.cc
├── setup
├── download_gdrive.py
├── download_workload.sh
└── setup-env.sh
├── src
├── CMakeLists.txt
├── client.cc
├── client.h
├── client_cr.cc
├── client_cr.h
├── client_mm.cc
├── client_mm.h
├── hashtable.cc
├── hashtable.h
├── ib.cc
├── ib.h
├── init.cc
├── kv_debug.h
├── kv_utils.cc
├── kv_utils.h
├── nm.cc
├── nm.h
├── server.cc
├── server.h
├── server_mm.cc
├── server_mm.h
└── spinlock.h
├── tests
├── CMakeLists.txt
├── client_config.json
├── client_kv_shell.cc
├── ddckv_test.cc
├── ddckv_test.h
├── server_config.json
├── test_client.h
├── test_client_client.cc
├── test_client_server.cc
├── test_conf.json
├── test_kv_utils.cc
├── test_mm.cc
├── test_mm.h
├── test_nm.cc
├── test_nm.h
├── test_remote_nm.cc
├── test_remote_nm.h
├── test_server.cc
└── test_server.h
└── ycsb-test
├── CMakeLists.txt
├── gen-ycsb-workload.py
├── merge-ycsb-lat.py
├── split-workload.py
├── ycsb_multi_client_cont_tpt.cc
├── ycsb_server_crash_multi_client.cc
├── ycsb_test.cc
├── ycsb_test.h
├── ycsb_test_client.cc
├── ycsb_test_multi_client.cc
├── ycsb_test_server.cc
├── ycsb_wl_loader.cc
└── ycsb_wl_worker.cc
/.gitignore:
--------------------------------------------------------------------------------
1 | build/
2 | .vscode
3 | ycsb-test/workloads/*
4 | micro-test/micro-workloads/*
5 | ycsb-test/upd-workloads/*
6 | *.ipynb
7 | workloads.tgz
8 | micro-workloads.tgz
9 | upd-workload.tgz
10 | setup/workloads
11 | setup/install/
12 | setup/micro-workloads/
13 | setup/upd-workloads.tgz
14 | setup/upd-workloads/
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "ycsb-test/YCSB-C"]
2 | path = ycsb-test/YCSB-C
3 | url = https://gitee.com/bernardshen/YCSB-C.git
4 |
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.16 FATAL_ERROR)
2 |
3 | project(DDCKV LANGUAGES CXX)
4 | set(CMAKE_CXX_STANDARD 11)
5 |
6 | find_package(Boost REQUIRED)
7 |
8 | include_directories(src)
9 | set(CMAKE_BUILD_TYPE Release)
10 |
11 | add_subdirectory(src)
12 |
13 | add_subdirectory(ycsb-test)
14 | add_subdirectory(crash-recover-test)
15 | add_subdirectory(micro-test)
16 |
17 | enable_testing()
18 | add_subdirectory(tests)
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # FUSEE: A Fully Memory-Disaggregated Key-Value Store
2 |
3 |
4 | This is the implementation repository of our FAST'23 paper: **FUSEE: A Fully Memory-Disaggregated Key-Value Store**.
5 |
6 |
7 |
8 | ## Description
9 |
10 | We proposes ***FUSEE***, a FUlly memory-diSaggrEgated KV Stor***E*** that brings disaggregation to metadata management. *FUSEE* replicates metadata, *i.e.*, the index and memory management information, on memory nodes, manages them directly on the client side, and handles complex failures under the DM architecture. To scalably replicate the index on clients, *FUSEE* proposes a client-centric replication protocol that allows clients to concurrently access and modify the replicated index. To efficiently manage disaggregated memory, *FUSEE* adopts a two-level memory management scheme that splits the memory management duty among clients and memory nodes. Finally, to handle the metadata corruption under client failures, *FUSEE* leverages an embedded operation log scheme to repair metadata with low log maintenance overhead.
11 |
12 |
13 | ## Environment
14 |
15 | * For hardware, each machine should be equipped with one **8-core Intel processer**(*e.g.*, Intel Xeon E5-2450), **16GB DRAM** and one **RDMA NIC card** (*e.g.*, Mellanox ConnectX-3). Each RNIC should be connected to an **Infiniband or Ethernet switch** (*e.g.*, Mellanox SX6036G). All machines are separated into memory nodes and compute nodes. At maximum 5 memory nodes and 17 compute nodes are used for the experiments in our paper. If you do not have such testbed, consider using [CloudLab](https://www.cloudlab.us/).
16 |
17 | * For software, **Ubuntu 18.04** is recommended for each machine. In our experiments, **7168 HugePages** of 2MB size in each memory node and **2048** ones in compute nodes is need to be allocated. You can set up this with `echo 7168 > /proc/sys/vm/nr_hugepages` command for memory nodes and `echo 2048 > /proc/sys/vm/nr_hugepages` for compute nodes.
18 |
19 |
20 |
21 | ## Configurations
22 |
23 | Configuration files for servers and clients should be provided to the program. Here are two example configuration files below.
24 |
25 | #### 1. Servers configuration
26 |
27 | For each memory node, you should provide a configuration file `server_config.json` where you can flexibly configure the server:
28 |
29 | ```json
30 | {
31 | "role": "SERVER",
32 | "conn_type": "IB",
33 | "server_id": 0,
34 | "udp_port": 2333,
35 | "memory_num": 3,
36 | "memory_ips": [
37 | "10.10.10.1",
38 | "10.10.10.2",
39 | "10.10.10.3"
40 | ],
41 | "ib_dev_id": 0,
42 | "ib_port_id": 1,
43 | "ib_gid_idx": 0,
44 |
45 | "server_base_addr": "0x10000000",
46 | "server_data_len": 15032385536,
47 | "block_size": 67108864,
48 | "subblock_size": 256,
49 | "client_local_size": 1073741824,
50 |
51 | "num_replication": 3,
52 |
53 | "main_core_id": 0,
54 | "poll_core_id": 1,
55 | "bg_core_id": 2,
56 | "gc_core_id": 3
57 | }
58 | ```
59 |
60 | For briefness, we call each memory node as "server `i`" (`i` = 0, 1, ...).
61 |
62 | #### 2. Clients configuration
63 |
64 | For each compute node, you should provide a configuration file `client_config.json` where you can flexibly configure the client:
65 |
66 | ```json
67 | {
68 | "role": "CLIENT",
69 | "conn_type": "IB",
70 | "server_id": 2,
71 | "udp_port": 2333,
72 | "memory_num": 2,
73 | "memory_ips": [
74 | "128.110.96.102",
75 | "128.110.96.81"
76 | ],
77 | "ib_dev_id": 0,
78 | "ib_port_id": 1,
79 | "ib_gid_idx": 0,
80 |
81 | "server_base_addr": "0x10000000",
82 | "server_data_len": 15032385536,
83 | "block_size": 67108864,
84 | "subblock_size": 1024,
85 | "client_local_size": 1073741824,
86 |
87 | "num_replication": 2,
88 | "num_idx_rep": 1,
89 | "num_coroutines": 10,
90 | "miss_rate_threash": 0.1,
91 | "workload_run_time": 10,
92 | "micro_workload_num": 10000,
93 |
94 | "main_core_id": 0,
95 | "poll_core_id": 1,
96 | "bg_core_id": 2,
97 | "gc_core_id": 3
98 | }
99 | ```
100 |
101 | For briefness, we call each compute node as "client `i`" (`i` = 0, 1, 2, ...).
102 |
103 | It should be noted that, the `server_id` parameter of client `i` should be set to `2+i*8`. For example, the `server_id` of the first three client is 2, 10, 18 respectively.
104 |
105 |
106 |
107 | ## Experiments
108 |
109 | For each node, execute the following commands to compile the entire program:
110 |
111 | ```shell
112 | mkdir build && cd build
113 | cmake ..
114 | make -j
115 | ```
116 |
117 | We test *FUSEE* with **micro-benchmark** and **YCSB benchmarks** respectively. For each experiments, you should put `server_config.json` in directory `./build`, and then use the following command in memory nodes to set up servers:
118 |
119 | ```shell
120 | numactl -N 0 -m 0 ./ycsb-test/ycsb_test_server [SERVER_NUM]
121 | ```
122 |
123 | `[SERVER_NUM]` should be the serial number of this memory node, counting from 0.
124 |
125 |
126 |
127 | #### 1. Micro-benchmark
128 |
129 | * **Latency**
130 |
131 | To evaluate the latency of each operation, we use a single client to iteratively execute each operation (**INSERT**, **DELETE**, **UPDATE**, and **SEARCH**) for 10,000 times.
132 |
133 | Enter `./build/micro-test` and use the following command in client `0`:
134 |
135 | ```shell
136 | numactl -N 0 -m 0 ./latency_test_client [PATH_TO_CLIENT_CONFIG]
137 | ```
138 |
139 | Test results will be saved in `./build/micro-test/results`.
140 |
141 | * **Throughput**
142 |
143 | To evaluate the throughput of each operations, each client first iteratively INSERTs different keys for 0.5 seconds. UPDATE and SEARCH operations are then executed on these keys for 10 seconds. Finally, each client executes DELETE for 0.5 seconds.
144 |
145 | Enter `./build/micro-test` and execute the following command on all client nodes at the same time:
146 |
147 | ```shell
148 | numactl -N 0 -m 0 ./micro_test_multi_client [PATH_TO_CLIENT_CONFIG] 8
149 | ```
150 |
151 | Number `8` indicates there are 8 client threads in each client node. You will need to use the keyboard to simultaneously send space signals to each client node for starting each operation testing synchronously.
152 |
153 | Test results will be displayed on each client terminal.
154 |
155 |
156 |
157 | #### 2. YCSB benchmarks
158 |
159 | * **Workload preparation**
160 |
161 | Firstly, download all the testing workloads using `sh download_workload.sh` in directory `./setup` and unpack the workloads you want to `./build/ycsb-test/workloads`.
162 |
163 | Here is the description of the YCSB workloads:
164 |
165 | | Workload | SEARCH | UPDATE | INSERT |
166 | | -------- | ------ | ------ | ------ |
167 | | A | 0.5 | 0.5 | 0 |
168 | | B | 0.95 | 0.95 | 0 |
169 | | C | 1 | 0 | 0 |
170 | | D | 0.95 | 0 | 0.05 |
171 | | upd[X] | 1-[X]% | [X]% | 0 |
172 |
173 | Then, you should execute the following command in `./build/ycsb-test` to split the workloads into N parts(N is the total number of client threads):
174 |
175 | ```shell
176 | python split-workload.py [N]
177 | ```
178 |
179 | And then we can start testing *FUSEE* using YCSB benchmarks.
180 |
181 | * **Throughput**
182 |
183 | To show the **scalability** of *FUSEE*,we can test the throughput of *FUSEE* with different number of client nodes. Besides, we can evaluate the **read-write performance** of *FUSEE* by testing the throughput of *FUSEE* using workloads with different search-update ratios `X`. Here is the command of testing the throughput of *FUSEE*:
184 |
185 | ```shell
186 | numactl -N 0 -m 0 ./ycsb_test_multi_client [PATH_TO_CLIENT_CONFIG] [WORKLOAD-NAME] 8
187 | ```
188 |
189 | Execute the command on all the client nodes at the same time. `[WORKLOAD-NAME]` can be chosen from `workloada ~ workloadd` or `workloadudp0 ~ workloadudp100` (indicating different search-update ratios) . Number `8` indicates there are 8 client threads in each client node. You will need to use the keyboard to simultaneously send space signals to each client node for starting each operation testing synchronously.
190 |
191 | Test results will be displayed on each client terminal.
192 |
193 |
194 |
--------------------------------------------------------------------------------
/crash-recover-test/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | add_executable(test_crash_client test_crash_client.cc)
2 |
3 | target_link_libraries(test_crash_client
4 | libddckv
5 | pthread
6 | ibverbs
7 | )
--------------------------------------------------------------------------------
/crash-recover-test/test_crash_client.cc:
--------------------------------------------------------------------------------
1 | #include "client.h"
2 |
3 | #define INSERT_NUM 1000
4 | #define UPDATE_NUM 1000
5 |
6 | const char * key = "test-12345-k";
7 | const char * key_template = "test-%d-k";
8 | const char * value_insert_template = "test-%d-v-insert";
9 | const char * value_update_template = "test-12345-v-update-%d";
10 | const char * value_template = "test-12345-v-%s";
11 |
12 | KVReqCtx * prepare_ctx(Client & client, const char * key, const char * value, int req_type) {
13 | uint64_t client_input_buf = (uint64_t)client.get_input_buf();
14 | uint32_t client_input_buf_lkey = client.get_input_buf_lkey();
15 |
16 | memcpy((void *)(client_input_buf + sizeof(KVLogHeader)), key, strlen(key));
17 | memcpy((void *)(client_input_buf + sizeof(KVLogHeader) + strlen(key)), value, strlen(value));
18 | KVLogHeader * header = (KVLogHeader *)client_input_buf;
19 | header->is_valid = true;
20 | header->key_length = strlen(key);
21 | header->value_length = strlen(value);
22 |
23 | KVInfo * kv_info = (KVInfo *)malloc(sizeof(KVInfo));
24 | kv_info->l_addr = (void *)client_input_buf;
25 | kv_info->key_len = strlen(key);
26 | kv_info->value_len = strlen(value);
27 | kv_info->lkey = client_input_buf_lkey;
28 |
29 | KVReqCtx * ctx = new KVReqCtx;
30 | ctx->req_type = req_type;
31 | ctx->use_cache = true;
32 | ctx->kv_info = kv_info;
33 | ctx->lkey = client.get_local_buf_mr()->lkey;
34 |
35 | int num_idx_rep = client.get_num_idx_rep();
36 | int num_replication = client.get_num_rep();
37 | ctx->kv_modify_pr_cas_list.resize(1);
38 | ctx->kv_modify_bk_0_cas_list.resize(num_idx_rep - 1);
39 | ctx->kv_modify_bk_1_cas_list.resize(num_idx_rep - 1);
40 | ctx->log_commit_addr_list.resize(num_replication);
41 | char key_buf[128] = {0};
42 | memcpy(key_buf, (void *)((uint64_t)ctx->kv_info->l_addr + sizeof(KVLogHeader)), ctx->kv_info->key_len);
43 | ctx->key_str = std::string(key_buf);
44 | return ctx;
45 | }
46 |
47 | void init_insert_ctx(Client & client, KVReqCtx * ctx) {
48 | uint64_t client_local_buf = (uint64_t)client.get_local_buf_mr()->addr;
49 | uint32_t client_local_buf_lkey = client.get_local_buf_mr()->lkey;
50 |
51 | ctx->local_bucket_addr = (RaceHashBucket *)client_local_buf;
52 | ctx->local_cas_target_value_addr = (void *)((uint64_t)client_local_buf + 4 * sizeof(RaceHashBucket));
53 | ctx->local_cas_return_value_addr = (void *)((uint64_t)ctx->local_cas_target_value_addr + sizeof(uint64_t));
54 | ctx->op_laddr = (void *)((uint64_t)ctx->local_cas_return_value_addr + sizeof(uint64_t) * MAX_REP_NUM);
55 | ctx->lkey = client_local_buf_lkey;
56 |
57 | KVLogHeader * header = (KVLogHeader *)ctx->kv_info->l_addr;
58 | KVLogTail * tail = (KVLogTail *)((uint64_t)ctx->kv_info->l_addr
59 | + sizeof(KVLogHeader) + header->key_length + header->value_length);
60 | tail->op = KV_OP_INSERT;
61 | }
62 |
63 | void init_update_ctx(Client & client, KVReqCtx * ctx) {
64 | uint64_t client_local_buf = (uint64_t)client.get_local_buf_mr()->addr;
65 | uint32_t client_local_buf_lkey = (uint64_t)client.get_local_buf_mr()->rkey;
66 |
67 | ctx->local_bucket_addr = (RaceHashBucket *)client_local_buf;
68 | ctx->local_kv_addr = (void *)((uint64_t)client_local_buf + 4 * sizeof(RaceHashBucket));
69 | ctx->local_cas_target_value_addr = (void *)((uint64_t)client_local_buf + 4 * sizeof(RaceHashBucket));
70 | ctx->local_cas_return_value_addr = (void *)((uint64_t)ctx->local_cas_target_value_addr + sizeof(uint64_t));
71 | ctx->op_laddr = (void *)((uint64_t)ctx->local_cas_target_value_addr + sizeof(uint64_t) * MAX_REP_NUM);
72 | ctx->local_cache_addr = (void *)((uint64_t)ctx->op_laddr + 2048);
73 | ctx->lkey = client_local_buf_lkey;
74 |
75 | KVLogHeader * header = (KVLogHeader *)ctx->kv_info->l_addr;
76 | KVLogTail * tail = (KVLogTail *)((uint64_t)ctx->kv_info->l_addr
77 | + sizeof(KVLogHeader) + header->key_length + header->value_length);
78 | tail->op = KV_OP_UPDATE;
79 | }
80 |
81 | void init_search_ctx(Client & client, KVReqCtx * ctx) {
82 | uint64_t client_local_buf = (uint64_t)client.get_local_buf_mr()->addr;
83 | uint32_t client_local_buf_lkey = (uint64_t)client.get_local_buf_mr()->rkey;
84 |
85 | ctx->local_bucket_addr = (RaceHashBucket *)client_local_buf;
86 | ctx->local_cache_addr = (void *)((uint64_t)client_local_buf + 4 * sizeof(RaceHashBucket));
87 | ctx->local_kv_addr = (void *)((uint64_t)client_local_buf + 4 * sizeof(RaceHashBucket));
88 | ctx->lkey = client_local_buf_lkey;
89 | }
90 |
91 | void test_crash_update_prepare(Client & client, int crash_point) {
92 | int ret = 0;
93 | // insert a kv
94 | char value_buf[128];
95 | bool should_stop = false;
96 |
97 | sprintf(value_buf, value_insert_template, INSERT_NUM);
98 | KVReqCtx * insert_ctx = prepare_ctx(client, key, value_buf, KV_REQ_INSERT);
99 | init_insert_ctx(client, insert_ctx);
100 | insert_ctx->should_stop = &should_stop;
101 | insert_ctx->coro_id = 100;
102 | ret = client.kv_insert_sync(insert_ctx);
103 | assert(ret == 0);
104 |
105 | // update the kv and crash
106 | for (int i = 0; i < UPDATE_NUM - 1; i ++) {
107 | sprintf(value_buf, value_update_template, i);
108 | KVReqCtx * update_ctx = prepare_ctx(client, key, value_buf, KV_REQ_UPDATE);
109 | init_update_ctx(client, update_ctx);
110 | ret = client.kv_update_sync(update_ctx);
111 | }
112 | sprintf(value_buf, value_update_template, UPDATE_NUM);
113 | KVReqCtx * update_ctx = prepare_ctx(client, key, value_buf, KV_REQ_UPDATE);
114 | init_update_ctx(client, update_ctx);
115 | ret = client.kv_update_w_crash(update_ctx, crash_point);
116 | assert(ret == -1);
117 | }
118 |
119 | void test_crash_insert_prepare(Client & client, int crash_point) {
120 | int ret = 0;
121 | char key_buf[128];
122 | char value_buf[128];
123 | // insert 1000 kv
124 | for (int i = 0; i < INSERT_NUM; i ++) {
125 | sprintf(key_buf, key_template, i);
126 | sprintf(value_buf, value_insert_template, i);
127 | KVReqCtx * insert_ctx = prepare_ctx(client, key_buf, value_buf, KV_REQ_INSERT);
128 | init_insert_ctx(client, insert_ctx);
129 | bool should_stop = false;
130 | insert_ctx->should_stop = &should_stop;
131 | insert_ctx->coro_id = 100;
132 | ret = client.kv_insert_sync(insert_ctx);
133 | if (ret != 0) {
134 | printf("[%s] insert error\n", __FUNCTION__);
135 | exit(1);
136 | }
137 | }
138 |
139 | sprintf(value_buf, value_insert_template, INSERT_NUM);
140 | KVReqCtx * insert_ctx = prepare_ctx(client, key, value_buf, KV_REQ_INSERT);
141 | init_insert_ctx(client, insert_ctx);
142 | bool should_stop = false;
143 | insert_ctx->should_stop = &should_stop;
144 | insert_ctx->coro_id = 100;
145 | ret = client.kv_insert_w_crash(insert_ctx, crash_point);
146 | if (ret != -1) {
147 | printf("[%s] failed to crash\n", __FUNCTION__);
148 | exit(1);
149 | }
150 | }
151 |
152 | void test_crash_recover(Client & client) {
153 | int ret = 0;
154 | void * search_ret;
155 | char new_value_buf[256];
156 | sprintf(new_value_buf, value_template, "update-after-crash");
157 | // recover
158 | KVReqCtx * update_ctx = prepare_ctx(client, key, new_value_buf, KV_REQ_UPDATE);
159 | init_update_ctx(client, update_ctx);
160 | ret = client.kv_update_sync(update_ctx);
161 | if (ret != 0) {
162 | printf("[%s] error update %d\n", __FUNCTION__, ret);
163 | }
164 | // assert(ret == 0);
165 |
166 | KVReqCtx * search_ctx = prepare_ctx(client, key, new_value_buf, KV_REQ_SEARCH);
167 | init_search_ctx(client, search_ctx);
168 | search_ret = client.kv_search_sync(search_ctx);
169 | if (memcmp(search_ret, new_value_buf, strlen(new_value_buf)) != 0) {
170 | printf("recover failed\n");
171 | } else {
172 | printf("recover success!\n");
173 | }
174 | }
175 |
176 | int main(int argc, char ** argv) {
177 | if (argc != 2) {
178 | printf("Usage: %s path-to-config-file\n", argv[0]);
179 | }
180 | int ret = 0;
181 | GlobalConfig config;
182 | ret = load_config(argv[1], &config);
183 | assert(ret == 0);
184 |
185 | config.num_coroutines = 1;
186 | config.is_recovery = false;
187 | Client client(&config);
188 | // pthread_t pollint_tid = client.start_polling_thread();
189 | client.start_gc_fiber();
190 |
191 | if (config.is_recovery == false) {
192 | test_crash_insert_prepare(client, KV_CRASH_UNCOMMITTED_BK_CONSENSUS_0);
193 | printf("crashed\n");
194 | }
195 | client.stop_gc_fiber();
196 |
197 | config.is_recovery = true;
198 | std::vector recover_time_bd;
199 | struct timeval st, et;
200 | gettimeofday(&st, NULL);
201 | Client clientr(&config);
202 | clientr.start_gc_fiber();
203 | gettimeofday(&et, NULL);
204 | clientr.get_recover_time(recover_time_bd);
205 | test_crash_recover(clientr);
206 |
207 | clientr.stop_gc_fiber();
208 |
209 | uint64_t connection_recover_time_us = time_spent_us(&recover_time_bd[0], &recover_time_bd[1]);
210 | uint64_t local_recover_space_reg_time_us = time_spent_us(&recover_time_bd[1], &recover_time_bd[2]);
211 | uint64_t get_meta_addr_time_us = time_spent_us(&recover_time_bd[2], &recover_time_bd[3]);
212 | uint64_t traverse_log_time_us = time_spent_us(&recover_time_bd[3], &recover_time_bd[4]);
213 | uint64_t mm_recover_time_us = time_spent_us(&recover_time_bd[4], &recover_time_bd[5]);
214 | uint64_t local_mr_reg_time_us = time_spent_us(&recover_time_bd[5], &recover_time_bd[6]);
215 | uint64_t kv_ops_recover_time_us = time_spent_us(&recover_time_bd[6], &recover_time_bd[7]);
216 |
217 | printf("0. conn rec: %ld us\n", connection_recover_time_us);
218 | printf("1. rec space reg: %ld us\n", local_recover_space_reg_time_us);
219 | printf("2. get meta addr: %ld us\n", get_meta_addr_time_us);
220 | printf("3. taverse log: %ld us\n", traverse_log_time_us);
221 | printf("4. mm rec: %ld us\n", mm_recover_time_us);
222 | printf("5. local mr reg time: %ld us\n", local_mr_reg_time_us);
223 | printf("6. ops rec: %ld us\n", kv_ops_recover_time_us);
224 | printf("total:%ld us\n", time_spent_us(&st, &et));
225 | }
--------------------------------------------------------------------------------
/crash-recover-test/test_crash_server.cc:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 |
6 | #include "server.h"
7 |
8 | int main(int argc, char ** argv) {
9 | if (argc != 2) {
10 | printf("Usage: %s [server_id]\n", argv[0]);
11 | return -1;
12 | }
13 |
14 | int32_t server_id = atoi(argv[1]);
15 | int32_t ret = 0;
16 | struct GlobalConfig server_conf;
17 | ret = load_config("./server_config.json", &server_conf);
18 | assert(ret == 0);
19 | server_conf.server_id = server_id;
20 |
21 | printf("===== Starting Server %d =====\n", server_conf.server_id);
22 | Server * server = new Server(&server_conf);
23 | pthread_t server_tid;
24 | pthread_create(&server_tid, NULL, server_main, (void *)server);
25 |
26 | printf("press to exit\n");
27 | getchar();
28 | printf("===== Ending Server %d =====\n", server_conf.server_id);
29 |
30 | server->stop();
31 | return 0;
32 | }
--------------------------------------------------------------------------------
/documents/fast23_FUSEE_Extended_Version.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dmemsys/FUSEE/d1e9932a0aad3deffb446511811911cc0f7e82f7/documents/fast23_FUSEE_Extended_Version.pdf
--------------------------------------------------------------------------------
/micro-test/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | add_library(latency_test latency_test.cc)
2 | add_library(micro_test micro_test.cc)
3 | add_executable(latency_test_client latency_test_client.cc)
4 | add_executable(latency_test_client_cr latency_test_client_cr.cc)
5 | add_executable(micro_test_multi_client micro_test_multi_client.cc)
6 | add_executable(micro_test_multi_client_cr micro_test_multi_client_cr.cc)
7 |
8 | target_link_libraries(latency_test
9 | libddckv
10 | ycsb_test
11 | pthread
12 | ibverbs
13 | )
14 |
15 | target_link_libraries(latency_test_client
16 | latency_test
17 | libddckv
18 | pthread
19 | ibverbs
20 | )
21 |
22 | target_link_libraries(latency_test_client_cr
23 | latency_test
24 | libddckv
25 | pthread
26 | ibverbs
27 | )
28 |
29 | target_link_libraries(micro_test
30 | libddckv
31 | pthread
32 | ibverbs
33 | )
34 |
35 | target_link_libraries(micro_test_multi_client
36 | micro_test
37 | libddckv
38 | pthread
39 | ibverbs
40 | )
41 |
42 | target_link_libraries(micro_test_multi_client_cr
43 | micro_test
44 | libddckv
45 | pthread
46 | ibverbs
47 | )
--------------------------------------------------------------------------------
/micro-test/gen-micro-workload.py:
--------------------------------------------------------------------------------
1 | import sys
2 |
3 | insertTemplate = "INSERT usertable {}\n"
4 | updateTemplate = "UPDATE usertable {}\n"
5 | searchTemplate = "READ usertable {}\n"
6 | deleteTemplate = "DELETE usertable {}\n"
7 |
8 | workloadNameTemplate = "workload{}.spec_trans"
9 | workloadNameList = ["ins", "upd", "rea", "del"]
10 | templateDict = {
11 | "ins": insertTemplate,
12 | "upd": updateTemplate,
13 | "rea": searchTemplate,
14 | "del": deleteTemplate
15 | }
16 |
17 | workloadSize = int(sys.argv[1])
18 |
19 | for wl in workloadNameList:
20 | wlName = "micro-workloads/" + workloadNameTemplate.format(wl)
21 | lineTemplate = templateDict[wl]
22 | lineList = []
23 | for key in range(workloadSize):
24 | line = lineTemplate.format(key)
25 | lineList.append(line)
26 | of = open(wlName, "w")
27 | of.writelines(lineList)
28 | of.close()
--------------------------------------------------------------------------------
/micro-test/latency_test.cc:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | #include "client.h"
5 |
6 | #include "latency_test.h"
7 |
8 | #define WORKLOAD_ALL (-1)
9 | // #define WORKLOAD_NUM WORKLOAD_ALL
10 | #define WORKLOAD_NUM 100000
11 |
12 |
13 | static int test_lat(Client & client, char * op_type, const char * out_fname) {
14 | int ret = 0;
15 | ret = client.load_seq_kv_requests(WORKLOAD_NUM, op_type);
16 | assert(ret == 0);
17 |
18 | printf("lat test %s\n", op_type);
19 | uint64_t * lat_list = (uint64_t *)malloc(sizeof(uint64_t) * client.num_local_operations_);
20 | memset(lat_list, 0, sizeof(uint64_t) * client.num_local_operations_);
21 |
22 | uint32_t num_failed = 0;
23 | void * search_addr;
24 | struct timeval st, et;
25 | bool should_stop = false;
26 | client.init_kvreq_space(0, 0, client.num_local_operations_);
27 | for (int i = 0; i < client.num_local_operations_; i ++) {
28 | KVReqCtx * ctx = &client.kv_req_ctx_list_[i];
29 | ctx->coro_id = 0;
30 | ctx->should_stop = &should_stop;
31 | // ctx->use_cache = false;
32 |
33 | switch (ctx->req_type) {
34 | case KV_REQ_SEARCH:
35 | gettimeofday(&st, NULL);
36 | search_addr = client.kv_search_sync(ctx);
37 | gettimeofday(&et, NULL);
38 | if (search_addr == NULL) {
39 | num_failed ++;
40 | }
41 | break;
42 | case KV_REQ_INSERT:
43 | gettimeofday(&st, NULL);
44 | ret = client.kv_insert_sync(ctx);
45 | gettimeofday(&et, NULL);
46 | if (ret == KV_OPS_FAIL_RETURN) {
47 | num_failed ++;
48 | }
49 | break;
50 | case KV_REQ_UPDATE:
51 | gettimeofday(&st, NULL);
52 | ret = client.kv_update_sync(ctx);
53 | if (ret == KV_OPS_FAIL_RETURN) {
54 | num_failed ++;
55 | }
56 | gettimeofday(&et, NULL);
57 | break;
58 | case KV_REQ_DELETE:
59 | gettimeofday(&st, NULL);
60 | ret = client.kv_delete_sync(ctx);
61 | if (ret == KV_OPS_FAIL_RETURN) {
62 | num_failed ++;
63 | }
64 | gettimeofday(&et, NULL);
65 | break;
66 | default:
67 | assert(0);
68 | break;
69 | }
70 |
71 | lat_list[i] = (et.tv_sec - st.tv_sec) * 1000000 + (et.tv_usec - st.tv_usec);
72 | }
73 | printf("Failed: %d\n", num_failed);
74 |
75 | FILE * lat_fp = fopen(out_fname, "w");
76 | assert(lat_fp != NULL);
77 | for (int i = 0; i < client.num_local_operations_; i ++) {
78 | fprintf(lat_fp, "%ld\n", lat_list[i]);
79 | }
80 | fclose(lat_fp);
81 | return 0;
82 | }
83 |
84 | static int test_lat(ClientCR & client, char * op_type, const char * out_fname) {
85 | int ret = 0;
86 | ret = client.load_seq_kv_requests(WORKLOAD_NUM, op_type);
87 | assert(ret == 0);
88 |
89 | printf("lat test %s\n", op_type);
90 | uint64_t * lat_list = (uint64_t *)malloc(sizeof(uint64_t) * client.num_local_operations_);
91 | memset(lat_list, 0, sizeof(uint64_t) * client.num_local_operations_);
92 |
93 | uint32_t num_failed = 0;
94 | void * search_addr;
95 | struct timeval st, et;
96 | bool should_stop = false;
97 | client.init_kvreq_space(0, 0, client.num_local_operations_);
98 | for (int i = 0; i < client.num_local_operations_; i ++) {
99 | KVReqCtx * ctx = &client.kv_req_ctx_list_[i];
100 | ctx->coro_id = 0;
101 | ctx->should_stop = &should_stop;
102 |
103 | switch (ctx->req_type) {
104 | case KV_REQ_SEARCH:
105 | gettimeofday(&st, NULL);
106 | search_addr = client.kv_search_sync(ctx);
107 | gettimeofday(&et, NULL);
108 | if (search_addr == NULL) {
109 | num_failed ++;
110 | }
111 | break;
112 | case KV_REQ_INSERT:
113 | gettimeofday(&st, NULL);
114 | ret = client.kv_insert_sync(ctx);
115 | gettimeofday(&et, NULL);
116 | if (ret == KV_OPS_FAIL_REDO || ret == KV_OPS_FAIL_RETURN) {
117 | num_failed ++;
118 | }
119 | break;
120 | case KV_REQ_UPDATE:
121 | gettimeofday(&st, NULL);
122 | ret = client.kv_update_sync(ctx);
123 | gettimeofday(&et, NULL);
124 | break;
125 | case KV_REQ_DELETE:
126 | gettimeofday(&st, NULL);
127 | ret = client.kv_delete_sync(ctx);
128 | gettimeofday(&et, NULL);
129 | break;
130 | default:
131 | assert(0);
132 | break;
133 | }
134 |
135 | lat_list[i] = (et.tv_sec - st.tv_sec) * 1000000 + (et.tv_usec - st.tv_usec);
136 | }
137 | printf("Failed: %d\n", num_failed);
138 |
139 | FILE * lat_fp = fopen(out_fname, "w");
140 | assert(lat_fp != NULL);
141 | for (int i = 0; i < client.num_local_operations_; i ++) {
142 | fprintf(lat_fp, "%ld\n", lat_list[i]);
143 | }
144 | fclose(lat_fp);
145 | return 0;
146 | }
147 |
148 | int test_insert_lat(Client & client) {
149 | char out_fname[128];
150 | int num_rep = client.get_num_rep();
151 | sprintf(out_fname, "results/insert_lat-%drp.txt", num_rep);
152 | return test_lat(client, "INSERT", out_fname);
153 | }
154 |
155 | int test_search_lat(Client & client) {
156 | char out_fname[128];
157 | int num_rep = client.get_num_rep();
158 | sprintf(out_fname, "results/search_lat-%drp.txt", num_rep);
159 | return test_lat(client, "READ", out_fname);
160 | }
161 |
162 | int test_update_lat(Client & client) {
163 | char out_fname[128];
164 | int num_rep = client.get_num_rep();
165 | sprintf(out_fname, "results/update_lat-%drp.txt", num_rep);
166 | return test_lat(client, "UPDATE", out_fname);
167 | }
168 |
169 | int test_delete_lat(Client & client) {
170 | char out_fname[128];
171 | int num_rep = client.get_num_rep();
172 | sprintf(out_fname, "results/delete_lat-%drp.txt", num_rep);
173 | return test_lat(client, "DELETE", out_fname);
174 | }
175 |
176 | int test_insert_lat(ClientCR & client) {
177 | char out_fname[128];
178 | int num_rep = client.get_num_rep();
179 | sprintf(out_fname, "results/insert_cr_lat-%drp.txt", num_rep);
180 | return test_lat(client, "INSERT", out_fname);
181 | }
182 |
183 | int test_search_lat(ClientCR & client) {
184 | char out_fname[128];
185 | int num_rep = client.get_num_rep();
186 | sprintf(out_fname, "results/search_cr_lat-%drp.txt", num_rep);
187 | return test_lat(client, "READ", out_fname);
188 | }
189 |
190 | int test_update_lat(ClientCR & client) {
191 | char out_fname[128];
192 | int num_rep = client.get_num_rep();
193 | sprintf(out_fname, "results/update_cr_lat-%drp.txt", num_rep);
194 | return test_lat(client, "UPDATE", out_fname);
195 | }
196 |
197 | int test_delete_lat(ClientCR & client) {
198 | char out_fname[128];
199 | int num_rep = client.get_num_rep();
200 | sprintf(out_fname, "results/delete_cr_lat-%drp.txt", num_rep);
201 | return test_lat(client, "DELETE", out_fname);
202 | }
--------------------------------------------------------------------------------
/micro-test/latency_test.h:
--------------------------------------------------------------------------------
1 | #ifndef DDCKV_LATENCY_TEST_H_
2 | #define DDCKV_LATENCY_TEST_H_
3 |
4 | #include "client.h"
5 | #include "client_cr.h"
6 |
7 | int test_insert_lat(Client & client);
8 | int test_search_lat(Client & client);
9 | int test_update_lat(Client & client);
10 | int test_delete_lat(Client & client);
11 |
12 | int test_insert_lat(ClientCR & client);
13 | int test_search_lat(ClientCR & client);
14 | int test_update_lat(ClientCR & client);
15 | int test_delete_lat(ClientCR & client);
16 |
17 | #endif
--------------------------------------------------------------------------------
/micro-test/latency_test_client.cc:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | #include "latency_test.h"
5 |
6 | int main(int argc, char ** argv) {
7 | if (argc != 2) {
8 | printf("Usage: %s path-to-config-file\n", argv[0]);
9 | return 1;
10 | }
11 |
12 | int ret = 0;
13 | GlobalConfig config;
14 | ret = load_config(argv[1], &config);
15 | assert(ret == 0);
16 |
17 | cpu_set_t cpuset;
18 | CPU_ZERO(&cpuset);
19 | CPU_SET(config.main_core_id, &cpuset);
20 | ret = sched_setaffinity(0, sizeof(cpuset), &cpuset);
21 | assert(ret == 0);
22 | ret = sched_getaffinity(0, sizeof(cpuset), &cpuset);
23 | assert(ret == 0);
24 | for (int i = 0; i < sysconf(_SC_NPROCESSORS_CONF); i ++) {
25 | if (CPU_ISSET(i, &cpuset)) {
26 | printf("main process running on core: %d\n", i);
27 | }
28 | }
29 |
30 | Client client(&config);
31 |
32 | ret = test_insert_lat(client);
33 | assert(ret == 0);
34 |
35 | ret = test_search_lat(client);
36 | assert(ret == 0);
37 |
38 | ret = test_update_lat(client);
39 | assert(ret == 0);
40 |
41 | ret = test_delete_lat(client);
42 | assert(ret == 0);
43 | }
--------------------------------------------------------------------------------
/micro-test/latency_test_client_cr.cc:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | #include "latency_test.h"
5 |
6 | int main(int argc, char ** argv) {
7 | if (argc != 2) {
8 | printf("Usage: %s path-to-config-file\n", argv[0]);
9 | return 1;
10 | }
11 |
12 | int ret = 0;
13 | GlobalConfig config;
14 | ret = load_config(argv[1], &config);
15 | assert(ret == 0);
16 |
17 | cpu_set_t cpuset;
18 | CPU_ZERO(&cpuset);
19 | CPU_SET(config.main_core_id, &cpuset);
20 | ret = sched_setaffinity(0, sizeof(cpuset), &cpuset);
21 | assert(ret == 0);
22 | ret = sched_getaffinity(0, sizeof(cpuset), &cpuset);
23 | assert(ret == 0);
24 | for (int i = 0; i < sysconf(_SC_NPROCESSORS_CONF); i ++) {
25 | if (CPU_ISSET(i, &cpuset)) {
26 | printf("main process running on core: %d\n", i);
27 | }
28 | }
29 |
30 | ClientCR client(&config);
31 |
32 | ret = test_insert_lat(client);
33 | assert(ret == 0);
34 |
35 | ret = test_search_lat(client);
36 | assert(ret == 0);
37 |
38 | ret = test_update_lat(client);
39 | assert(ret == 0);
40 |
41 | ret = test_delete_lat(client);
42 | assert(ret == 0);
43 | }
--------------------------------------------------------------------------------
/micro-test/micro_test.cc:
--------------------------------------------------------------------------------
1 | #include "micro_test.h"
2 | #include "client.h"
3 | #include "client_cr.h"
4 |
5 | static void timer_fb_func(volatile bool * should_stop, int seconds) {
6 | boost::this_fiber::sleep_for(std::chrono::seconds(seconds));
7 | *should_stop = true;
8 | // printf("stopped!\n");
9 | }
10 |
11 | static void timer_fb_func_ms(volatile bool * should_stop, int milliseconds) {
12 | boost::this_fiber::sleep_for(std::chrono::milliseconds(milliseconds));
13 | *should_stop = true;
14 | // printf("stopped!\n");
15 | }
16 |
17 | static int micro_test_tpt(Client & client, MicroRunClientArgs * args) {
18 | int ret = 0;
19 | ret = client.load_seq_kv_requests(client.micro_workload_num_, args->op_type);
20 | assert(ret == 0);
21 |
22 | printf("Test phase start\n");
23 | boost::fibers::barrier global_barrier(client.num_coroutines_ + 1);
24 | ClientFiberArgs * fb_args_list = (ClientFiberArgs *)malloc(sizeof(ClientFiberArgs) * client.num_local_operations_);
25 | uint32_t coro_num_ops = client.num_local_operations_ / client.num_coroutines_;
26 | for (int i = 0; i < client.num_coroutines_; i ++) {
27 | fb_args_list[i].client = &client;
28 | fb_args_list[i].coro_id = i;
29 | fb_args_list[i].ops_num = coro_num_ops;
30 | fb_args_list[i].ops_st_idx = coro_num_ops * i;
31 | fb_args_list[i].num_failed = 0;
32 | fb_args_list[i].b = &global_barrier;
33 | fb_args_list[i].should_stop = args->should_stop;
34 | }
35 | fb_args_list[client.num_coroutines_ - 1].ops_num += client.num_local_operations_ % client.num_coroutines_;
36 |
37 | boost::fibers::fiber fb_list[client.num_coroutines_];
38 | for (int i = 0; i < client.num_coroutines_; i ++) {
39 | boost::fibers::fiber fb(client_ops_fb_cnt_ops_micro, &fb_args_list[i]);
40 | fb_list[i] = std::move(fb);
41 | }
42 |
43 | global_barrier.wait();
44 | boost::fibers::fiber timer_fb;
45 | if (args->thread_id == 0) {
46 | printf("%d initializes timer\n", args->thread_id);
47 | pthread_barrier_wait(args->timer_barrier);
48 | boost::fibers::fiber fb(timer_fb_func_ms, args->should_stop, client.workload_run_time_);
49 | timer_fb = std::move(fb);
50 | } else {
51 | printf("%d wait for timer\n", args->thread_id);
52 | pthread_barrier_wait(args->timer_barrier);
53 | }
54 |
55 | printf("%d passed barrier\n", args->thread_id);
56 | if (args->thread_id == 0) {
57 | timer_fb.join();
58 | }
59 | uint32_t ops_cnt = 0;
60 | uint32_t num_failed = 0;
61 | for (int i = 0; i < client.num_coroutines_; i ++) {
62 | fb_list[i].join();
63 | ops_cnt += fb_args_list[i].ops_cnt;
64 | num_failed += fb_args_list[i].num_failed;
65 | printf("fb%d finished\n", fb_args_list[i].coro_id);
66 | }
67 | printf("thread: %d %d ops/s\n", args->thread_id, ops_cnt / 10);
68 | printf("%d failed\n", num_failed);
69 |
70 | // update counter
71 | if (strcmp(args->op_type, "INSERT") == 0) {
72 | args->ret_num_insert_ops = ops_cnt;
73 | args->ret_fail_insert_num = num_failed;
74 | } else if (strcmp(args->op_type, "UPDATE") == 0) {
75 | args->ret_num_update_ops = ops_cnt;
76 | args->ret_fail_update_num = num_failed;
77 | } else if (strcmp(args->op_type, "READ") == 0) {
78 | args->ret_num_search_ops = ops_cnt;
79 | args->ret_fail_search_num = num_failed;
80 | } else {
81 | assert(strcmp(args->op_type, "DELETE") == 0);
82 | args->ret_num_delete_ops = ops_cnt;
83 | args->ret_fail_delete_num = num_failed;
84 | }
85 | free(fb_args_list);
86 | return 0;
87 | }
88 |
89 | static int micro_test_tpt(ClientCR & client, MicroRunClientArgs * args) {
90 | int ret = 0;
91 | ret = client.load_seq_kv_requests(client.micro_workload_num_, args->op_type);
92 | assert(ret == 0);
93 |
94 | printf("Test phase start\n");
95 | boost::fibers::barrier global_barrier(client.num_coroutines_ + 1);
96 | ClientFiberArgs * fb_args_list = (ClientFiberArgs *)malloc(sizeof(ClientFiberArgs) * client.num_local_operations_);
97 | uint32_t coro_num_ops = client.num_local_operations_ / client.num_coroutines_;
98 | for (int i = 0; i < client.num_coroutines_; i ++) {
99 | fb_args_list[i].client_cr = &client;
100 | fb_args_list[i].coro_id = i;
101 | fb_args_list[i].ops_num = coro_num_ops;
102 | fb_args_list[i].ops_st_idx = coro_num_ops * i;
103 | fb_args_list[i].num_failed = 0;
104 | fb_args_list[i].b = &global_barrier;
105 | fb_args_list[i].should_stop = args->should_stop;
106 | }
107 | fb_args_list[client.num_coroutines_ - 1].ops_num += client.num_local_operations_ % client.num_coroutines_;
108 |
109 | boost::fibers::fiber fb_list[client.num_coroutines_];
110 | for (int i = 0; i < client.num_coroutines_; i ++) {
111 | boost::fibers::fiber fb(client_cr_ops_fb_cnt_ops_micro, &fb_args_list[i]);
112 | fb_list[i] = std::move(fb);
113 | }
114 |
115 | global_barrier.wait();
116 | boost::fibers::fiber timer_fb;
117 | if (args->thread_id == 0) {
118 | printf("%d initializes timer\n", args->thread_id);
119 | pthread_barrier_wait(args->timer_barrier);
120 | boost::fibers::fiber fb(timer_fb_func, args->should_stop, client.workload_run_time_);
121 | timer_fb = std::move(fb);
122 | } else {
123 | printf("%d wait for timer\n", args->thread_id);
124 | pthread_barrier_wait(args->timer_barrier);
125 | }
126 |
127 | printf("%d passed barrier\n", args->thread_id);
128 | if (args->thread_id == 0) {
129 | timer_fb.join();
130 | }
131 | uint32_t ops_cnt = 0;
132 | uint32_t num_failed = 0;
133 | for (int i = 0; i < client.num_coroutines_; i ++) {
134 | fb_list[i].join();
135 | ops_cnt += fb_args_list[i].ops_cnt;
136 | num_failed += fb_args_list[i].num_failed;
137 | printf("fb%d finished\n", fb_args_list[i].coro_id);
138 | }
139 | printf("thread: %d %d ops/s\n", args->thread_id, ops_cnt / 10);
140 | printf("%d failed\n", num_failed);
141 |
142 | // update counter
143 | if (strcmp(args->op_type, "INSERT") == 0) {
144 | args->ret_num_insert_ops = ops_cnt;
145 | args->ret_fail_insert_num = num_failed;
146 | } else if (strcmp(args->op_type, "UPDATE") == 0) {
147 | args->ret_num_update_ops = ops_cnt;
148 | args->ret_fail_update_num = num_failed;
149 | } else if (strcmp(args->op_type, "READ") == 0) {
150 | args->ret_num_search_ops = ops_cnt;
151 | args->ret_fail_search_num = num_failed;
152 | } else {
153 | assert(strcmp(args->op_type, "DELETE") == 0);
154 | args->ret_num_delete_ops = ops_cnt;
155 | args->ret_fail_delete_num = num_failed;
156 | }
157 | free(fb_args_list);
158 | return 0;
159 | }
160 |
161 | void * run_client(void * _args) {
162 | MicroRunClientArgs * args = (MicroRunClientArgs *)_args;
163 |
164 | int ret = 0;
165 | GlobalConfig config;
166 | ret = load_config(args->config_file, &config);
167 | assert(ret == 0);
168 |
169 | config.main_core_id = args->main_core_id;
170 | config.poll_core_id = args->poll_core_id;
171 | config.server_id += args->thread_id;
172 |
173 | cpu_set_t cpuset;
174 | CPU_ZERO(&cpuset);
175 | CPU_SET(config.main_core_id, &cpuset);
176 | pthread_t this_tid = pthread_self();
177 | ret = pthread_setaffinity_np(this_tid, sizeof(cpuset), &cpuset);
178 | // assert(ret == 0);
179 | ret = pthread_getaffinity_np(this_tid, sizeof(cpuset), &cpuset);
180 | for (int i = 0; i < sysconf(_SC_NPROCESSORS_CONF); i ++) {
181 | if (CPU_ISSET(i, &cpuset)) {
182 | printf("client %d main process running on core: %d\n", args->thread_id, i);
183 | }
184 | }
185 |
186 | Client client(&config);
187 |
188 | pthread_t polling_tid = client.start_polling_thread();
189 |
190 | args->op_type = "INSERT";
191 | client.workload_run_time_ = 500;
192 | if (args->thread_id == 0) {
193 | printf("press to sync start %s\n", args->op_type);
194 | getchar();
195 | }
196 | pthread_barrier_wait(args->insert_start_barrier);
197 |
198 | // insert
199 | printf("%d start %s\n", args->thread_id, args->op_type);
200 | ret = micro_test_tpt(client, args);
201 | assert(ret == 0);
202 | printf("%d %s finished\n", args->thread_id, args->op_type);
203 | pthread_barrier_wait(args->insert_finish_barrier);
204 |
205 | args->op_type = "READ";
206 | client.workload_run_time_ = 5000;
207 | if (args->thread_id == 0) {
208 | pthread_barrier_init(args->timer_barrier, NULL, args->num_threads);
209 | *args->should_stop = false;
210 | printf("press to sync start %s\n", args->op_type);
211 | getchar();
212 | }
213 | pthread_barrier_wait(args->search_start_barrier);
214 |
215 | printf("%d start %s\n", args->thread_id, args->op_type);
216 | ret = micro_test_tpt(client, args);
217 | assert(ret == 0);
218 | printf("%d %s finished\n", args->thread_id, args->op_type);
219 | pthread_barrier_wait(args->search_finish_barrier);
220 |
221 | args->op_type = "UPDATE";
222 | client.workload_run_time_ = 5000;
223 | if (args->thread_id == 0) {
224 | pthread_barrier_init(args->timer_barrier, NULL, args->num_threads);
225 | *args->should_stop = false;
226 | printf("press to sync start %s\n", args->op_type);
227 | getchar();
228 | }
229 | pthread_barrier_wait(args->update_start_barrier);
230 |
231 | printf("%d start %s\n", args->thread_id, args->op_type);
232 | ret = micro_test_tpt(client, args);
233 | assert(ret == 0);
234 | printf("%d %s finished\n", args->thread_id, args->op_type);
235 | pthread_barrier_wait(args->update_finish_barrier);
236 |
237 | args->op_type = "DELETE";
238 | client.workload_run_time_ = 500;
239 | if (args->thread_id == 0) {
240 | pthread_barrier_init(args->timer_barrier, NULL, args->num_threads);
241 | *args->should_stop = false;
242 | printf("press to sync start %s\n", args->op_type);
243 | getchar();
244 | }
245 | pthread_barrier_wait(args->delete_start_barrier);
246 |
247 | printf("%d start %s\n", args->thread_id, args->op_type);
248 | ret = micro_test_tpt(client, args);
249 | assert(ret == 0);
250 | printf("%d %s finished\n", args->thread_id, args->op_type);
251 | pthread_barrier_wait(args->delete_finish_barrier);
252 |
253 | client.stop_polling_thread();
254 | pthread_join(polling_tid, NULL);
255 | return 0;
256 | }
257 |
258 | void * run_client_cr(void * _args) {
259 | MicroRunClientArgs * args = (MicroRunClientArgs *)_args;
260 |
261 | int ret = 0;
262 | GlobalConfig config;
263 | ret = load_config(args->config_file, &config);
264 | assert(ret == 0);
265 |
266 | config.main_core_id = args->main_core_id;
267 | config.poll_core_id = args->poll_core_id;
268 | config.server_id += args->thread_id;
269 |
270 | cpu_set_t cpuset;
271 | CPU_ZERO(&cpuset);
272 | CPU_SET(config.main_core_id, &cpuset);
273 | pthread_t this_tid = pthread_self();
274 | ret = pthread_setaffinity_np(this_tid, sizeof(cpuset), &cpuset);
275 | // assert(ret == 0);
276 | ret = pthread_getaffinity_np(this_tid, sizeof(cpuset), &cpuset);
277 | for (int i = 0; i < sysconf(_SC_NPROCESSORS_CONF); i ++) {
278 | if (CPU_ISSET(i, &cpuset)) {
279 | printf("client %d main process running on core: %d\n", args->thread_id, i);
280 | }
281 | }
282 |
283 | ClientCR client(&config);
284 |
285 | pthread_t polling_tid = client.start_polling_thread();
286 |
287 | args->op_type = "INSERT";
288 | if (args->thread_id == 0) {
289 | printf("press to sync start %s\n", args->op_type);
290 | getchar();
291 | }
292 | pthread_barrier_wait(args->insert_start_barrier);
293 |
294 | // insert
295 | printf("%d start %s\n", args->thread_id, args->op_type);
296 | ret = micro_test_tpt(client, args);
297 | assert(ret == 0);
298 | printf("%d %s finished\n", args->thread_id, args->op_type);
299 | pthread_barrier_wait(args->insert_finish_barrier);
300 |
301 | args->op_type = "UPDATE";
302 | if (args->thread_id == 0) {
303 | pthread_barrier_init(args->timer_barrier, NULL, args->num_threads);
304 | *args->should_stop = false;
305 | printf("press to sync start %s\n", args->op_type);
306 | getchar();
307 | }
308 | pthread_barrier_wait(args->update_start_barrier);
309 |
310 | printf("%d start %s\n", args->thread_id, args->op_type);
311 | ret = micro_test_tpt(client, args);
312 | assert(ret == 0);
313 | printf("%d %s finished\n", args->thread_id, args->op_type);
314 | pthread_barrier_wait(args->update_finish_barrier);
315 |
316 | args->op_type = "READ";
317 | if (args->thread_id == 0) {
318 | pthread_barrier_init(args->timer_barrier, NULL, args->num_threads);
319 | *args->should_stop = false;
320 | printf("press to sync start %s\n", args->op_type);
321 | getchar();
322 | }
323 | pthread_barrier_wait(args->search_start_barrier);
324 |
325 | printf("%d start %s\n", args->thread_id, args->op_type);
326 | ret = micro_test_tpt(client, args);
327 | assert(ret == 0);
328 | printf("%d %s finished\n", args->thread_id, args->op_type);
329 | pthread_barrier_wait(args->search_finish_barrier);
330 |
331 | args->op_type = "DELETE";
332 | if (args->thread_id == 0) {
333 | pthread_barrier_init(args->timer_barrier, NULL, args->num_threads);
334 | *args->should_stop = false;
335 | printf("press to sync start %s\n", args->op_type);
336 | getchar();
337 | }
338 | pthread_barrier_wait(args->delete_start_barrier);
339 |
340 | printf("%d start %s\n", args->thread_id, args->op_type);
341 | ret = micro_test_tpt(client, args);
342 | assert(ret == 0);
343 | printf("%d %s finished\n", args->thread_id, args->op_type);
344 | pthread_barrier_wait(args->delete_finish_barrier);
345 |
346 | client.stop_polling_thread();
347 | pthread_join(polling_tid, NULL);
348 | return 0;
349 | }
--------------------------------------------------------------------------------
/micro-test/micro_test.h:
--------------------------------------------------------------------------------
1 | #ifndef DDCKV_MICRO_TEST_H_
2 | #define DDCKV_MICRO_TEST_H_
3 |
4 | #include
5 | #include
6 |
7 | #include "client.h"
8 |
9 | typedef struct TagMicroRunClientArgs {
10 | int thread_id;
11 | int main_core_id;
12 | int poll_core_id;
13 | char * workload_name;
14 | char * config_file;
15 | pthread_barrier_t * insert_start_barrier;
16 | pthread_barrier_t * insert_finish_barrier;
17 | pthread_barrier_t * update_start_barrier;
18 | pthread_barrier_t * update_finish_barrier;
19 | pthread_barrier_t * search_start_barrier;
20 | pthread_barrier_t * search_finish_barrier;
21 | pthread_barrier_t * delete_start_barrier;
22 | pthread_barrier_t * delete_finish_barrier;
23 | volatile bool * should_stop;
24 | // bool * timer_is_ready;
25 | pthread_barrier_t * timer_barrier;
26 |
27 | uint32_t ret_num_insert_ops;
28 | uint32_t ret_num_update_ops;
29 | uint32_t ret_num_search_ops;
30 | uint32_t ret_num_delete_ops;
31 | uint32_t ret_fail_insert_num;
32 | uint32_t ret_fail_update_num;
33 | uint32_t ret_fail_search_num;
34 | uint32_t ret_fail_delete_num;
35 |
36 | uint32_t client_id;
37 | uint32_t num_threads;
38 | char * op_type;
39 | Client * client;
40 | } MicroRunClientArgs;
41 |
42 | void * run_client(void * _args);
43 | void * run_client_cr(void * _args);
44 |
45 | #endif
--------------------------------------------------------------------------------
/micro-test/micro_test_multi_client.cc:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | #include
5 | #include
6 |
7 | #include
8 |
9 | #include "client.h"
10 | #include "micro_test.h"
11 |
12 | static void start_client_threads(char * op_type, int num_clients, GlobalConfig * config,
13 | char * config_fname) {
14 | MicroRunClientArgs * client_args_list = (MicroRunClientArgs *)malloc(sizeof(MicroRunClientArgs) * num_clients);
15 | pthread_barrier_t insert_start_barrier;
16 | pthread_barrier_t insert_finish_barrier;
17 | pthread_barrier_t update_start_barrier;
18 | pthread_barrier_t update_finish_barrier;
19 | pthread_barrier_t search_start_barrier;
20 | pthread_barrier_t search_finish_barrier;
21 | pthread_barrier_t delete_start_barrier;
22 | pthread_barrier_t delete_finish_barrier;
23 | pthread_barrier_t global_timer_barrier;
24 | pthread_barrier_init(&insert_start_barrier, NULL, num_clients);
25 | pthread_barrier_init(&insert_finish_barrier, NULL, num_clients);
26 | pthread_barrier_init(&update_start_barrier, NULL, num_clients);
27 | pthread_barrier_init(&update_finish_barrier, NULL, num_clients);
28 | pthread_barrier_init(&search_start_barrier, NULL, num_clients);
29 | pthread_barrier_init(&search_finish_barrier, NULL, num_clients);
30 | pthread_barrier_init(&delete_start_barrier, NULL, num_clients);
31 | pthread_barrier_init(&delete_finish_barrier, NULL, num_clients);
32 | pthread_barrier_init(&global_timer_barrier, NULL, num_clients);
33 | volatile bool should_stop = false;
34 |
35 | pthread_t tid_list[num_clients];
36 | for (int i = 0; i < num_clients; i ++) {
37 | client_args_list[i].client_id = config->server_id - config->memory_num;
38 | client_args_list[i].thread_id = i;
39 | client_args_list[i].num_threads = num_clients;
40 | client_args_list[i].main_core_id = config->main_core_id + i * 2;
41 | client_args_list[i].poll_core_id = config->poll_core_id + i * 2;
42 | client_args_list[i].config_file = config_fname;
43 | client_args_list[i].insert_start_barrier= &insert_start_barrier;
44 | client_args_list[i].insert_finish_barrier= &insert_finish_barrier;
45 | client_args_list[i].update_start_barrier= &update_start_barrier;
46 | client_args_list[i].update_finish_barrier= &update_finish_barrier;
47 | client_args_list[i].search_start_barrier= &search_start_barrier;
48 | client_args_list[i].search_finish_barrier= &search_finish_barrier;
49 | client_args_list[i].delete_start_barrier= &delete_start_barrier;
50 | client_args_list[i].delete_finish_barrier= &delete_finish_barrier;
51 | client_args_list[i].timer_barrier = &global_timer_barrier;
52 | client_args_list[i].should_stop = &should_stop;
53 | client_args_list[i].ret_num_insert_ops = 0;
54 | client_args_list[i].ret_num_update_ops = 0;
55 | client_args_list[i].ret_num_search_ops = 0;
56 | client_args_list[i].ret_num_delete_ops = 0;
57 | client_args_list[i].ret_fail_insert_num = 0;
58 | client_args_list[i].ret_fail_update_num = 0;
59 | client_args_list[i].ret_fail_search_num = 0;
60 | client_args_list[i].ret_fail_delete_num = 0;
61 | client_args_list[i].op_type = op_type;
62 | pthread_t tid;
63 | pthread_create(&tid, NULL, run_client, &client_args_list[i]);
64 | tid_list[i] = tid;
65 | }
66 |
67 | uint32_t total_insert_tpt = 0;
68 | uint32_t total_insert_failed = 0;
69 | uint32_t total_update_tpt = 0;
70 | uint32_t total_update_failed = 0;
71 | uint32_t total_search_tpt = 0;
72 | uint32_t total_search_failed = 0;
73 | uint32_t total_delete_tpt = 0;
74 | uint32_t total_delete_failed = 0;
75 | for (int i = 0; i < num_clients; i ++) {
76 | pthread_join(tid_list[i], NULL);
77 | total_insert_tpt += client_args_list[i].ret_num_insert_ops;
78 | total_update_tpt += client_args_list[i].ret_num_update_ops;
79 | total_search_tpt += client_args_list[i].ret_num_search_ops;
80 | total_delete_tpt += client_args_list[i].ret_num_delete_ops;
81 | total_insert_failed += client_args_list[i].ret_fail_insert_num;
82 | total_update_failed += client_args_list[i].ret_fail_update_num;
83 | total_search_failed += client_args_list[i].ret_fail_search_num;
84 | total_delete_failed += client_args_list[i].ret_fail_delete_num;
85 | }
86 | printf("insert total: %d ops\n", total_insert_tpt);
87 | printf("insert failed: %d ops\n", total_insert_failed);
88 | printf("insert tpt: %d ops/s\n", (total_insert_tpt - total_insert_failed) * 1000 / 500);
89 | printf("update total: %d ops\n", total_update_tpt);
90 | printf("update failed: %d ops\n", total_update_failed);
91 | printf("update tpt: %d ops/s\n", (total_update_tpt - total_update_failed) * 1000 / 5000);
92 | printf("search total: %d ops\n", total_search_tpt);
93 | printf("search failed: %d ops\n", total_search_failed);
94 | printf("search tpt: %d ops/s\n", (total_search_tpt - total_search_failed) * 1000 / 5000);
95 | printf("delete total: %d ops\n", total_delete_tpt);
96 | printf("delete failed: %d ops\n", total_delete_failed);
97 | printf("delete tpt: %d ops/s\n", (total_delete_tpt - total_delete_failed) * 1000 / 500);
98 | free(client_args_list);
99 | }
100 |
101 | int main(int argc, char ** argv) {
102 | if (argc != 3) {
103 | printf("Usage: %s path-to-config-file num-clients\n", argv[0]);
104 | return 1;
105 | }
106 |
107 | int num_clients = atoi(argv[2]);
108 |
109 | GlobalConfig config;
110 | int ret = load_config(argv[1], &config);
111 | assert(ret == 0);
112 |
113 | start_client_threads("INSERT", num_clients, &config, argv[1]);
114 | }
--------------------------------------------------------------------------------
/micro-test/micro_test_multi_client_cr.cc:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | #include
5 | #include
6 |
7 | #include
8 |
9 | #include "client.h"
10 | #include "micro_test.h"
11 |
12 | static void start_client_threads(char * op_type, int num_clients, GlobalConfig * config,
13 | char * config_fname) {
14 | MicroRunClientArgs * client_args_list = (MicroRunClientArgs *)malloc(sizeof(MicroRunClientArgs) * num_clients);
15 | pthread_barrier_t insert_start_barrier;
16 | pthread_barrier_t insert_finish_barrier;
17 | pthread_barrier_t update_start_barrier;
18 | pthread_barrier_t update_finish_barrier;
19 | pthread_barrier_t search_start_barrier;
20 | pthread_barrier_t search_finish_barrier;
21 | pthread_barrier_t delete_start_barrier;
22 | pthread_barrier_t delete_finish_barrier;
23 | pthread_barrier_t global_timer_barrier;
24 | pthread_barrier_init(&insert_start_barrier, NULL, num_clients);
25 | pthread_barrier_init(&insert_finish_barrier, NULL, num_clients);
26 | pthread_barrier_init(&update_start_barrier, NULL, num_clients);
27 | pthread_barrier_init(&update_finish_barrier, NULL, num_clients);
28 | pthread_barrier_init(&search_start_barrier, NULL, num_clients);
29 | pthread_barrier_init(&search_finish_barrier, NULL, num_clients);
30 | pthread_barrier_init(&delete_start_barrier, NULL, num_clients);
31 | pthread_barrier_init(&delete_finish_barrier, NULL, num_clients);
32 | pthread_barrier_init(&global_timer_barrier, NULL, num_clients);
33 | volatile bool should_stop = false;
34 |
35 | pthread_t tid_list[num_clients];
36 | for (int i = 0; i < num_clients; i ++) {
37 | client_args_list[i].client_id = config->server_id - config->memory_num;
38 | client_args_list[i].thread_id = i;
39 | client_args_list[i].num_threads = num_clients;
40 | client_args_list[i].main_core_id = config->main_core_id + i * 2;
41 | client_args_list[i].poll_core_id = config->poll_core_id + i * 2;
42 | client_args_list[i].config_file = config_fname;
43 | client_args_list[i].insert_start_barrier= &insert_start_barrier;
44 | client_args_list[i].insert_finish_barrier= &insert_finish_barrier;
45 | client_args_list[i].update_start_barrier= &update_start_barrier;
46 | client_args_list[i].update_finish_barrier= &update_finish_barrier;
47 | client_args_list[i].search_start_barrier= &search_start_barrier;
48 | client_args_list[i].search_finish_barrier= &search_finish_barrier;
49 | client_args_list[i].delete_start_barrier= &delete_start_barrier;
50 | client_args_list[i].delete_finish_barrier= &delete_finish_barrier;
51 | client_args_list[i].timer_barrier = &global_timer_barrier;
52 | client_args_list[i].should_stop = &should_stop;
53 | client_args_list[i].ret_num_insert_ops = 0;
54 | client_args_list[i].ret_num_update_ops = 0;
55 | client_args_list[i].ret_num_search_ops = 0;
56 | client_args_list[i].ret_num_delete_ops = 0;
57 | client_args_list[i].ret_fail_insert_num = 0;
58 | client_args_list[i].ret_fail_update_num = 0;
59 | client_args_list[i].ret_fail_search_num = 0;
60 | client_args_list[i].ret_fail_delete_num = 0;
61 | client_args_list[i].op_type = op_type;
62 | pthread_t tid;
63 | pthread_create(&tid, NULL, run_client_cr, &client_args_list[i]);
64 | tid_list[i] = tid;
65 | }
66 |
67 | uint32_t total_insert_tpt = 0;
68 | uint32_t total_insert_failed = 0;
69 | uint32_t total_update_tpt = 0;
70 | uint32_t total_update_failed = 0;
71 | uint32_t total_search_tpt = 0;
72 | uint32_t total_search_failed = 0;
73 | uint32_t total_delete_tpt = 0;
74 | uint32_t total_delete_failed = 0;
75 | for (int i = 0; i < num_clients; i ++) {
76 | pthread_join(tid_list[i], NULL);
77 | total_insert_tpt += client_args_list[i].ret_num_insert_ops;
78 | total_update_tpt += client_args_list[i].ret_num_update_ops;
79 | total_search_tpt += client_args_list[i].ret_num_search_ops;
80 | total_delete_tpt += client_args_list[i].ret_num_delete_ops;
81 | total_insert_failed += client_args_list[i].ret_fail_insert_num;
82 | total_update_failed += client_args_list[i].ret_fail_update_num;
83 | total_search_failed += client_args_list[i].ret_fail_search_num;
84 | total_delete_failed += client_args_list[i].ret_fail_delete_num;
85 | }
86 | printf("insert total: %d ops\n", total_insert_tpt);
87 | printf("insert failed: %d ops\n", total_insert_failed);
88 | printf("insert tpt: %d ops/s\n", (total_insert_tpt - total_insert_failed) / config->workload_run_time);
89 | printf("update total: %d ops\n", total_update_tpt);
90 | printf("update failed: %d ops\n", total_update_failed);
91 | printf("update tpt: %d ops/s\n", (total_update_tpt - total_update_failed) / config->workload_run_time);
92 | printf("search total: %d ops\n", total_search_tpt);
93 | printf("search failed: %d ops\n", total_search_failed);
94 | printf("search tpt: %d ops/s\n", (total_search_tpt - total_search_failed) / config->workload_run_time);
95 | printf("delete total: %d ops\n", total_delete_tpt);
96 | printf("delete failed: %d ops\n", total_delete_failed);
97 | printf("delete tpt: %d ops/s\n", (total_delete_tpt - total_delete_failed) / config->workload_run_time);
98 | free(client_args_list);
99 | }
100 |
101 | int main(int argc, char ** argv) {
102 | if (argc != 3) {
103 | printf("Usage: %s path-to-config-file num-clients\n", argv[0]);
104 | return 1;
105 | }
106 |
107 | int num_clients = atoi(argv[2]);
108 |
109 | GlobalConfig config;
110 | int ret = load_config(argv[1], &config);
111 | assert(ret == 0);
112 |
113 | start_client_threads("INSERT", num_clients, &config, argv[1]);
114 | }
--------------------------------------------------------------------------------
/setup/download_gdrive.py:
--------------------------------------------------------------------------------
1 | import gdown
2 | import sys
3 |
4 | fid = sys.argv[1]
5 | output = sys.argv[2]
6 |
7 | url = "https://drive.google.com/uc?id={}&export=download".format(fid)
8 |
9 | gdown.download(url, output, quiet=False)
--------------------------------------------------------------------------------
/setup/download_workload.sh:
--------------------------------------------------------------------------------
1 | # install python and gdown
2 | sudo apt install python3-pip -y
3 | pip3 install gdown
4 |
5 | # download workload
6 | echo "downloading workloads.tgz"
7 | if [ ! -d "./workloads.tgz" ]; then
8 | python3 ./download_gdrive.py 1Ifd8AwQ5e6EMcm3l9yYn8tgI3qMwhRpb workloads.tgz
9 | fi
10 |
11 | echo "downloading micro-workloads.tgz"
12 | if [ ! -d "./micro-workloads.tgz" ]; then
13 | python3 ./download_gdrive.py 1727S-g5j568BEgqMjc4zghT2_pz0EZhf micro-workloads.tgz
14 | fi
15 |
16 | # decompress upd-workload
17 | echo "downloading upd-workloads"
18 | if [ ! -d "./upd-workloads" ]; then
19 | python3 ./download_gdrive.py 1CJjkswX08XqoF2RaxXBiKgWapjyMrXdi upd-workloads.tgz
20 | fi
21 |
22 | # decompress workload
23 | echo "decompressing workload files"
24 | if [ ! -d "./workloads" ]; then
25 | tar zxvf workloads.tgz
26 | fi
27 |
28 | if [ ! -d "./micro-workloads" ]; then
29 | tar zxvf micro-workloads.tgz
30 | fi
31 |
32 | if [ ! -d "./upd-workloads" ]; then
33 | tar zxvf upd-workloads.tgz
34 | fi
--------------------------------------------------------------------------------
/setup/setup-env.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | #!/bin/bash
3 |
4 | mode="$1"
5 | ubuntu_version=$(lsb_release -r -s)
6 |
7 | if [ $ubuntu_version == "18.04" ]; then
8 | wget https://content.mellanox.com/ofed/MLNX_OFED-4.9-5.1.0.0/MLNX_OFED_LINUX-4.9-5.1.0.0-ubuntu18.04-x86_64.tgz
9 | mv MLNX_OFED_LINUX-4.9-5.1.0.0-ubuntu18.04-x86_64.tgz ofed.tgz
10 | elif [ $ubuntu_version == "20.04" ]; then
11 | wget https://content.mellanox.com/ofed/MLNX_OFED-4.9-5.1.0.0/MLNX_OFED_LINUX-4.9-5.1.0.0-ubuntu20.04-x86_64.tgz
12 | mv MLNX_OFED_LINUX-4.9-5.1.0.0-ubuntu20.04-x86_64.tgz ofed.tgz
13 | else
14 | echo "Wrong ubuntu distribution for $mode!"
15 | exit 0
16 | fi
17 | echo $mode $ubuntu_version $ofed_fid
18 |
19 | sudo apt update -y
20 |
21 | # install anaconda
22 | mkdir install
23 | mv ofed.tgz install
24 |
25 | cd install
26 | if [ ! -f "./anaconda-install.sh" ]; then
27 | wget https://repo.anaconda.com/archive/Anaconda3-2022.05-Linux-x86_64.sh -O anaconda-install.sh
28 | fi
29 | if [ ! -d "$HOME/anaconda3" ]; then
30 | chmod +x anaconda-install.sh
31 | ./anaconda-install.sh -b
32 | export PATH=$PATH:$HOME/anaconda3/bin
33 | # add conda to path
34 | echo PATH=$PATH:$HOME/anaconda3/bin >> $HOME/.bashrc
35 | conda init
36 | source ~/.bashrc
37 | # activate base
38 | fi
39 | conda activate base
40 | cd ..
41 |
42 | pip install gdown
43 | sudo apt install memcached -y
44 | sudo apt install libtbb-dev libboost-all-dev -y
45 |
46 | # install ofed
47 | cd install
48 | if [ ! -d "./ofed" ]; then
49 | tar zxf ofed.tgz
50 | mv MLNX* ofed
51 | fi
52 | cd ofed
53 | sudo ./mlnxofedinstall --force
54 | if [ $mode == "scalestore" ]; then
55 | sudo /etc/init.d/openibd restart
56 | fi
57 | cd ..
58 |
59 | # install cmake
60 | cd install
61 | if [ ! -f cmake-3.16.8.tar.gz ]; then
62 | wget https://cmake.org/files/v3.16/cmake-3.16.8.tar.gz
63 | fi
64 | if [ ! -d "./cmake-3.16.8" ]; then
65 | tar zxf cmake-3.16.8.tar.gz
66 | cd cmake-3.16.8 && ./configure && make -j 4 && sudo make install
67 | fi
68 | cd ..
69 |
70 | # install gtest
71 | if [ ! -d "/usr/src/gtest" ]; then
72 | sudo apt install -y libgtest-dev
73 | fi
74 | cd /usr/src/gtest
75 | sudo cmake .
76 | sudo make
77 | sudo make install
--------------------------------------------------------------------------------
/src/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | list(APPEND source_ddckv
2 | nm.cc
3 | ib.cc
4 | server_mm.cc
5 | server.cc
6 | kv_utils.cc
7 | hashtable.cc
8 | client_mm.cc
9 | client.cc
10 | client_cr.cc)
11 |
12 | add_library(libddckv STATIC ${source_ddckv})
13 |
14 | target_compile_options(
15 | libddckv
16 | PRIVATE
17 | "-O2"
18 | # ${CMAKE_CXX_FLAGS_DEBUG}
19 | "-g"
20 | # "-D_DEBUG"
21 | )
22 |
23 | target_link_libraries(libddckv ${Boost_LIBRARIES} boost_context boost_fiber tbb)
24 |
25 |
--------------------------------------------------------------------------------
/src/client_cr.h:
--------------------------------------------------------------------------------
1 | #ifndef DDCKV_CLIENT_CR_H_
2 | #define DDCKV_CLIENT_CR_H_
3 |
4 | #include