自实现内存池:按大小分桶,8bit跨度,支持释放。
resp协议pipline测试。
This commit is contained in:
34
Makefile
34
Makefile
@@ -1,15 +1,21 @@
|
|||||||
|
|
||||||
CC = gcc
|
CC = gcc
|
||||||
FLAGS = -g -DJEMALLOC_NO_DEMANGLE -I./NtyCo/core/ -I/usr/include/libxml2 -L ./NtyCo/ -L ./mem_pool/ -L ./diskuring/
|
CFLAGS = -g -DJEMALLOC_NO_DEMANGLE
|
||||||
LDFLAGS = -lntyco -lpthread -luring -ldl -lxml2
|
|
||||||
SRCS = kvstore.c ntyco.c proactor.c reactor.c kvs_array_bin.c kvs_rbtree_bin.c kvs_hash_bin.c kvs_rw_tools.c kvs_protocol_resp.c kvs_oplog.c kvs_slave.c ./mem_pool/mem_pool.c ./common/config.c ./diskuring/diskuring.c
|
NET_SRCS = ntyco.c proactor.c reactor.c kvstore.c
|
||||||
|
KV_SRCS = kvs_array_bin.c kvs_rbtree_bin.c kvs_hash_bin.c kvs_rw_tools.c kvs_protocol_resp.c kvs_oplog.c kvs_slave.c
|
||||||
|
MEM_SRCS = ./memory/mempool.c ./memory/alloc_dispatch.c
|
||||||
|
COMMON_SRCS = ./common/config.c ./diskuring/diskuring.c
|
||||||
|
|
||||||
|
SRCS = $(NET_SRCS) $(KV_SRCS) $(MEM_SRCS) $(COMMON_SRCS)
|
||||||
|
|
||||||
|
INC = -I./NtyCo/core/ -I/usr/include/libxml2
|
||||||
|
LIBDIRS = -L./NtyCo/ -L./memory/ -L./diskuring/
|
||||||
|
LIBS = -lntyco -lpthread -luring -ldl -lxml2 -ljemalloc
|
||||||
|
|
||||||
TARGET = kvstore
|
TARGET = kvstore
|
||||||
SUBDIR = ./NtyCo/
|
SUBDIR = ./NtyCo/
|
||||||
|
|
||||||
TESTCASE = testcase
|
|
||||||
TESTCASE_SRCS = testcase.c
|
|
||||||
TESTCASE2 = ./test/testcase
|
|
||||||
TESTCASE2_SRCS = ./test/testcase.c ./test/test_client.c
|
|
||||||
|
|
||||||
TEST_REDIS = ./test-redis/testcase
|
TEST_REDIS = ./test-redis/testcase
|
||||||
TEST_REDIS_SRCS = ./test-redis/test.c
|
TEST_REDIS_SRCS = ./test-redis/test.c
|
||||||
@@ -18,7 +24,7 @@ TEST_REDIS_LDFLAGS = -lhiredis
|
|||||||
OBJS = $(SRCS:.c=.o)
|
OBJS = $(SRCS:.c=.o)
|
||||||
|
|
||||||
|
|
||||||
all: $(SUBDIR) $(TARGET) $(TESTCASE) $(TESTCASE2) $(TEST_REDIS)
|
all: $(SUBDIR) $(TARGET) $(TEST_REDIS)
|
||||||
|
|
||||||
$(SUBDIR): ECHO
|
$(SUBDIR): ECHO
|
||||||
make -C $@
|
make -C $@
|
||||||
@@ -27,21 +33,15 @@ ECHO:
|
|||||||
@echo $(SUBDIR)
|
@echo $(SUBDIR)
|
||||||
|
|
||||||
$(TARGET): $(OBJS)
|
$(TARGET): $(OBJS)
|
||||||
$(CC) -o $@ $^ $(FLAGS) $(LDFLAGS)
|
$(CC) $(CFLAGS) -o $@ $^ $(LIBDIRS) $(LIBS)
|
||||||
|
|
||||||
$(TESTCASE): $(TESTCASE_SRCS)
|
|
||||||
$(CC) -g -o $@ $^
|
|
||||||
|
|
||||||
$(TESTCASE2): $(TESTCASE2_SRCS)
|
|
||||||
$(CC) -g -o $@ $^
|
|
||||||
|
|
||||||
$(TEST_REDIS): $(TEST_REDIS_SRCS)
|
$(TEST_REDIS): $(TEST_REDIS_SRCS)
|
||||||
$(CC) -g -o $@ $^ $(TEST_REDIS_LDFLAGS)
|
$(CC) -g -o $@ $^ $(TEST_REDIS_LDFLAGS)
|
||||||
|
|
||||||
%.o: %.c
|
%.o: %.c
|
||||||
$(CC) $(FLAGS) -c $^ -g -o $@
|
$(CC) $(CFLAGS) $(INC) -c $^ -g -o $@
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -rf $(OBJS) $(TARGET) $(TESTCASE) $(TESTCASE2) $(TEST_REDIS)
|
rm -rf $(OBJS) $(TARGET) $(TEST_REDIS)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#include "diskuring.h"
|
#include "diskuring.h"
|
||||||
#include "../mem_pool/mem_pool.h"
|
#include "../memory/alloc_dispatch.h"
|
||||||
#include <poll.h>
|
#include <poll.h>
|
||||||
#include <sys/eventfd.h>
|
#include <sys/eventfd.h>
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
#include "kvstore.h"
|
#include "kvstore.h"
|
||||||
#include "kvs_rw_tools.h"
|
#include "kvs_rw_tools.h"
|
||||||
#include "mem_pool/mem_pool.h"
|
#include "memory/alloc_dispatch.h"
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
#include "kvstore.h"
|
#include "kvstore.h"
|
||||||
#include "kvs_rw_tools.h"
|
#include "kvs_rw_tools.h"
|
||||||
#include "mem_pool/mem_pool.h"
|
#include "memory/alloc_dispatch.h"
|
||||||
#include "diskuring/diskuring.h"
|
#include "diskuring/diskuring.h"
|
||||||
|
|
||||||
// singleton
|
// singleton
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
// #include <pthread.h>
|
// #include <pthread.h>
|
||||||
|
|
||||||
|
|
||||||
// #include "mem_pool/mem_pool.h"
|
// #include "memory/alloc_dispatch.h"
|
||||||
// #include "kvstore.h"
|
// #include "kvstore.h"
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
#include "kvstore.h"
|
#include "kvstore.h"
|
||||||
#include "kvs_rw_tools.h"
|
#include "kvs_rw_tools.h"
|
||||||
#include "mem_pool/mem_pool.h"
|
#include "memory/alloc_dispatch.h"
|
||||||
#include "diskuring/diskuring.h"
|
#include "diskuring/diskuring.h"
|
||||||
// Key, Value -->
|
// Key, Value -->
|
||||||
// Modify
|
// Modify
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#include "kvstore.h"
|
#include "kvstore.h"
|
||||||
#include "kvs_rw_tools.h"
|
#include "kvs_rw_tools.h"
|
||||||
#include "mem_pool/mem_pool.h"
|
#include "memory/alloc_dispatch.h"
|
||||||
#include "kvs_protocol_resp.h"
|
#include "kvs_protocol_resp.h"
|
||||||
#include "diskuring/diskuring.h"
|
#include "diskuring/diskuring.h"
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
#include "kvstore.h"
|
#include "kvstore.h"
|
||||||
#include "kvs_rw_tools.h"
|
#include "kvs_rw_tools.h"
|
||||||
#include "mem_pool/mem_pool.h"
|
#include "memory/alloc_dispatch.h"
|
||||||
#include "diskuring/diskuring.h"
|
#include "diskuring/diskuring.h"
|
||||||
|
|
||||||
int kvs_keycmp(const uint8_t *a, uint32_t alen,
|
int kvs_keycmp(const uint8_t *a, uint32_t alen,
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#include "kvs_rw_tools.h"
|
#include "kvs_rw_tools.h"
|
||||||
#include "mem_pool/mem_pool.h"
|
#include "memory/alloc_dispatch.h"
|
||||||
#include "kvs_oplog.h"
|
#include "kvs_oplog.h"
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ int read_full(int fd, void *buf, size_t n);
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// 1MB
|
// 1MB
|
||||||
#define KVS_MAX_RESPONSE (65536)
|
#define KVS_MAX_RESPONSE (4096*2)
|
||||||
#define KVS_MAX_ARGLEN (507)
|
#define KVS_MAX_ARGLEN (507)
|
||||||
#define KVS_MAX_CMD_BYTES (1024)
|
#define KVS_MAX_CMD_BYTES (1024)
|
||||||
#define KVS_MAX_ARGC 3
|
#define KVS_MAX_ARGC 3
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
#include "kvs_rw_tools.h"
|
#include "kvs_rw_tools.h"
|
||||||
#include "kvs_protocol_resp.h"
|
#include "kvs_protocol_resp.h"
|
||||||
#include "kvs_oplog.h"
|
#include "kvs_oplog.h"
|
||||||
#include "mem_pool/mem_pool.h"
|
#include "memory/alloc_dispatch.h"
|
||||||
#include "common/config.h"
|
#include "common/config.h"
|
||||||
#include "diskuring/diskuring.h"
|
#include "diskuring/diskuring.h"
|
||||||
|
|
||||||
@@ -140,13 +140,13 @@ int kvs_protocol(struct conn* conn){
|
|||||||
int cap = KVS_MAX_RESPONSE - out_len;
|
int cap = KVS_MAX_RESPONSE - out_len;
|
||||||
if (cap <= 0) {
|
if (cap <= 0) {
|
||||||
*response_length = out_len;
|
*response_length = out_len;
|
||||||
return -1;
|
return consumed;
|
||||||
}
|
}
|
||||||
|
|
||||||
int resp_len = resp_build_value(&val, response + out_len, (size_t)cap);
|
int resp_len = resp_build_value(&val, response + out_len, (size_t)cap);
|
||||||
if (resp_len < 0) {
|
if (resp_len < 0) {
|
||||||
*response_length = out_len;
|
*response_length = out_len;
|
||||||
return -1;
|
return consumed;
|
||||||
}
|
}
|
||||||
|
|
||||||
out_len += resp_len;
|
out_len += resp_len;
|
||||||
@@ -372,7 +372,7 @@ void dest_kvengine(void) {
|
|||||||
|
|
||||||
void init_memory_pool(void){
|
void init_memory_pool(void){
|
||||||
#if MEMORY_SELECT_MALLOC == MEMORY_USE_MYMALLOC
|
#if MEMORY_SELECT_MALLOC == MEMORY_USE_MYMALLOC
|
||||||
mp_init(&global_mempool);
|
mp_create(&global_mempool);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
3380
kvstore.excalidraw
3380
kvstore.excalidraw
File diff suppressed because one or more lines are too long
7721
kvstore1.excalidraw
7721
kvstore1.excalidraw
File diff suppressed because one or more lines are too long
@@ -1,180 +0,0 @@
|
|||||||
#include "mem_pool.h"
|
|
||||||
#include <stddef.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <jemalloc/jemalloc.h>
|
|
||||||
|
|
||||||
|
|
||||||
void *kvs_malloc(size_t size) {
|
|
||||||
#if MEMORY_SELECT_MALLOC == MEMORY_USE_DEFAULT
|
|
||||||
return malloc(size);
|
|
||||||
#elif MEMORY_SELECT_MALLOC == MEMORY_USE_MYMALLOC
|
|
||||||
return mp_alloc(size);
|
|
||||||
#elif MEMORY_SELECT_MALLOC == MEMORY_USE_JEMALLOC
|
|
||||||
return je_malloc(size);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void kvs_free(void *ptr) {
|
|
||||||
#if MEMORY_SELECT_MALLOC == MEMORY_USE_DEFAULT
|
|
||||||
free(ptr);
|
|
||||||
#elif MEMORY_SELECT_MALLOC == MEMORY_USE_MYMALLOC
|
|
||||||
mp_free(ptr);
|
|
||||||
#elif MEMORY_SELECT_MALLOC == MEMORY_USE_JEMALLOC
|
|
||||||
je_free(ptr);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
#if MEMORY_SELECT_MALLOC == MEMORY_USE_MYMALLOC
|
|
||||||
mp_pool_t global_mempool = {0};
|
|
||||||
|
|
||||||
// >= x 的第一个2^n
|
|
||||||
uint32_t mp_ceil_pow2_u32(uint32_t x) {
|
|
||||||
if (x <= 1) return 1;
|
|
||||||
x--;
|
|
||||||
x |= x >> 1;
|
|
||||||
x |= x >> 2;
|
|
||||||
x |= x >> 4;
|
|
||||||
x |= x >> 8;
|
|
||||||
x |= x >> 16;
|
|
||||||
return x + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// return cid
|
|
||||||
uint16_t mp_class_id_for(size_t size) {
|
|
||||||
if (size < 8) size = 8;
|
|
||||||
if (size > (1u << MP_MAX_SHIFT)) return MP_LARGE_CLASS;
|
|
||||||
|
|
||||||
uint32_t s = (uint32_t)size;
|
|
||||||
uint32_t p2 = mp_ceil_pow2_u32(s); /* 8/16/32... */
|
|
||||||
|
|
||||||
/* 计算 log2(p2) */
|
|
||||||
uint16_t shift = 0;
|
|
||||||
while ((1u << shift) < p2) shift++;
|
|
||||||
|
|
||||||
return (uint16_t)(shift - MP_MIN_SHIFT);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t mp_user_size_from_class(uint16_t cid) {
|
|
||||||
return (size_t)1u << (cid + MP_MIN_SHIFT);
|
|
||||||
}
|
|
||||||
|
|
||||||
int mp_add_page(mp_pool_t* p, void* mem) {
|
|
||||||
mp_page_t* pg = (mp_page_t*)je_malloc(sizeof(mp_page_t));
|
|
||||||
if (!pg) return -1;
|
|
||||||
pg->mem = mem;
|
|
||||||
pg->next = p->pages;
|
|
||||||
p->pages = pg;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int mp_grow(mp_pool_t* p, uint16_t cid) {
|
|
||||||
void* page = je_malloc(MP_PAGE_SIZE);
|
|
||||||
if (!page) return -1;
|
|
||||||
if (mp_add_page(p, page) != 0) { je_free(page); return -1; }
|
|
||||||
|
|
||||||
// cid对应的空间大小
|
|
||||||
const size_t user_sz = mp_user_size_from_class(cid);
|
|
||||||
const size_t block_sz = sizeof(mp_blk_hdr_t) + user_sz;
|
|
||||||
size_t n = MP_PAGE_SIZE / block_sz;
|
|
||||||
if (n == 0) { je_free(page); return -1; }
|
|
||||||
|
|
||||||
uint8_t* cur = (uint8_t*)page;
|
|
||||||
|
|
||||||
mp_blk_hdr_t* first_hdr = (mp_blk_hdr_t*)cur;
|
|
||||||
first_hdr->magic = MP_MAGIC;
|
|
||||||
first_hdr->class_id = cid;
|
|
||||||
|
|
||||||
mp_free_node_t* first_node = (mp_free_node_t*)(first_hdr + 1);
|
|
||||||
mp_free_node_t* head = first_node;
|
|
||||||
mp_free_node_t* tail = first_node;
|
|
||||||
|
|
||||||
cur += block_sz;
|
|
||||||
n--;
|
|
||||||
|
|
||||||
for (size_t i = 0; i < n; ++i) {
|
|
||||||
mp_blk_hdr_t* h = (mp_blk_hdr_t*)cur;
|
|
||||||
h->magic = MP_MAGIC;
|
|
||||||
h->class_id = cid;
|
|
||||||
|
|
||||||
mp_free_node_t* node = (mp_free_node_t*)(h + 1);
|
|
||||||
tail->next = node;
|
|
||||||
tail = node;
|
|
||||||
|
|
||||||
cur += block_sz;
|
|
||||||
}
|
|
||||||
|
|
||||||
tail->next = p->buckets[cid].free_list;
|
|
||||||
p->buckets[cid].free_list = head;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void mp_init(mp_pool_t* p){
|
|
||||||
if (!p) return;
|
|
||||||
for (int i = 0; i < MP_NBUCKETS; ++i) p->buckets[i].free_list = NULL;
|
|
||||||
p->pages = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void mp_destroy(mp_pool_t* p){
|
|
||||||
if (!p) return;
|
|
||||||
mp_page_t* pg = p->pages;
|
|
||||||
while (pg) {
|
|
||||||
mp_page_t* nxt = pg->next;
|
|
||||||
je_free(pg->mem);
|
|
||||||
je_free(pg);
|
|
||||||
pg = nxt;
|
|
||||||
}
|
|
||||||
p->pages = NULL;
|
|
||||||
for (int i = 0; i < MP_NBUCKETS; ++i) p->buckets[i].free_list = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void* mp_alloc(size_t size){
|
|
||||||
mp_pool_t* p = &global_mempool;
|
|
||||||
if (!p) return NULL;
|
|
||||||
if (size == 0) size = 1;
|
|
||||||
|
|
||||||
uint16_t cid = mp_class_id_for(size);
|
|
||||||
if (cid == MP_LARGE_CLASS) {
|
|
||||||
mp_blk_hdr_t* h = (mp_blk_hdr_t*)je_malloc(sizeof(mp_blk_hdr_t) + size);
|
|
||||||
if (!h) return NULL;
|
|
||||||
h->magic = MP_MAGIC;
|
|
||||||
h->class_id = MP_LARGE_CLASS;
|
|
||||||
return (void*)(h + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
mp_free_node_t* node = p->buckets[cid].free_list;
|
|
||||||
if (!node) {
|
|
||||||
if (mp_grow(p, cid) != 0) return NULL;
|
|
||||||
node = p->buckets[cid].free_list;
|
|
||||||
if (!node) return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
p->buckets[cid].free_list = node->next;
|
|
||||||
return (void*)node;
|
|
||||||
}
|
|
||||||
|
|
||||||
void mp_free(void* ptr){
|
|
||||||
mp_pool_t* p = &global_mempool;
|
|
||||||
if (!p || !ptr) return;
|
|
||||||
|
|
||||||
mp_blk_hdr_t* h = ((mp_blk_hdr_t*)ptr) - 1;
|
|
||||||
if (h->magic != MP_MAGIC) {
|
|
||||||
/* 非法指针:极简处理(你也可以 assert/abort) */
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (h->class_id == MP_LARGE_CLASS) {
|
|
||||||
/* 大对象:直接 free 整块(从 header 起) */
|
|
||||||
je_free(h);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!p) return;
|
|
||||||
uint16_t cid = h->class_id;
|
|
||||||
if (cid >= MP_NBUCKETS) return; /* 极简:不做更多校验 */
|
|
||||||
|
|
||||||
mp_free_node_t* node = (mp_free_node_t*)ptr;
|
|
||||||
node->next = p->buckets[cid].free_list;
|
|
||||||
p->buckets[cid].free_list = node;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
#ifndef __MEM_POOL_H__
|
|
||||||
#define __MEM_POOL_H__
|
|
||||||
|
|
||||||
#define MEMORY_USE_DEFAULT 0
|
|
||||||
#define MEMORY_USE_MYMALLOC 1
|
|
||||||
#define MEMORY_USE_JEMALLOC 2
|
|
||||||
|
|
||||||
#define MEMORY_SELECT_MALLOC MEMORY_USE_DEFAULT
|
|
||||||
#include <stddef.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
void *kvs_malloc(size_t size);
|
|
||||||
void kvs_free(void *ptr);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#define MP_PAGE_SIZE (16*1024)
|
|
||||||
#define MP_MIN_SHIFT 3
|
|
||||||
#define MP_MAX_SHIFT 12
|
|
||||||
|
|
||||||
#define MP_NBUCKETS (MP_MAX_SHIFT - MP_MIN_SHIFT + 1)
|
|
||||||
#define MP_MAGIC 0xB10C0A11u
|
|
||||||
#define MP_LARGE_CLASS 0xFFFFu
|
|
||||||
|
|
||||||
typedef struct mp_free_node {
|
|
||||||
struct mp_free_node* next;
|
|
||||||
} mp_free_node_t;
|
|
||||||
|
|
||||||
// (blk_hdr + user_data)
|
|
||||||
typedef struct mp_blk_hdr {
|
|
||||||
uint32_t magic;
|
|
||||||
uint16_t class_id;
|
|
||||||
uint16_t reserved;
|
|
||||||
} mp_blk_hdr_t;
|
|
||||||
|
|
||||||
typedef struct mp_page {
|
|
||||||
void* mem;
|
|
||||||
struct mp_page* next;
|
|
||||||
} mp_page_t;
|
|
||||||
|
|
||||||
typedef struct mp_bucket {
|
|
||||||
mp_free_node_t* free_list; /* 指向用户区 */
|
|
||||||
} mp_bucket_t;
|
|
||||||
|
|
||||||
typedef struct mp_pool {
|
|
||||||
mp_bucket_t buckets[MP_NBUCKETS];
|
|
||||||
mp_page_t* pages; /* 所有申请过的页 */
|
|
||||||
} mp_pool_t;
|
|
||||||
|
|
||||||
/* 初始化/销毁 */
|
|
||||||
void mp_init(mp_pool_t* p);
|
|
||||||
void mp_destroy(mp_pool_t* p);
|
|
||||||
|
|
||||||
/* 分配/释放 */
|
|
||||||
void* mp_alloc(size_t size);
|
|
||||||
void mp_free(void* ptr);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
30
memory/alloc_dispatch.c
Normal file
30
memory/alloc_dispatch.c
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
#include "mempool.h"
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <jemalloc/jemalloc.h>
|
||||||
|
|
||||||
|
mp_pool_t global_mempool;
|
||||||
|
|
||||||
|
void *kvs_malloc(size_t size) {
|
||||||
|
#if MEMORY_SELECT_MALLOC == MEMORY_USE_DEFAULT
|
||||||
|
return malloc(size);
|
||||||
|
#elif MEMORY_SELECT_MALLOC == MEMORY_USE_MYMALLOC
|
||||||
|
return mp_alloc(size);
|
||||||
|
#elif MEMORY_SELECT_MALLOC == MEMORY_USE_JEMALLOC
|
||||||
|
return je_malloc(size);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void kvs_free(void *ptr) {
|
||||||
|
#if MEMORY_SELECT_MALLOC == MEMORY_USE_DEFAULT
|
||||||
|
free(ptr);
|
||||||
|
#elif MEMORY_SELECT_MALLOC == MEMORY_USE_MYMALLOC
|
||||||
|
int ret = mp_free(ptr);
|
||||||
|
if(ret == MEMPOOL_DOUBLE_FREE){
|
||||||
|
printf("double free %p\n", ptr);
|
||||||
|
}
|
||||||
|
#elif MEMORY_SELECT_MALLOC == MEMORY_USE_JEMALLOC
|
||||||
|
je_free(ptr);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
18
memory/alloc_dispatch.h
Normal file
18
memory/alloc_dispatch.h
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
#ifndef __ALLOC_DISPATCH_H__
|
||||||
|
#define __ALLOC_DISPATCH_H__
|
||||||
|
|
||||||
|
#define MEMORY_USE_DEFAULT 0
|
||||||
|
#define MEMORY_USE_MYMALLOC 1
|
||||||
|
#define MEMORY_USE_JEMALLOC 2
|
||||||
|
|
||||||
|
#define MEMORY_SELECT_MALLOC MEMORY_USE_MYMALLOC
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "mempool.h"
|
||||||
|
|
||||||
|
void *kvs_malloc(size_t size);
|
||||||
|
void kvs_free(void *ptr);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
316
memory/mempool.c
Normal file
316
memory/mempool.c
Normal file
@@ -0,0 +1,316 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#include "mempool.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static inline void* page_payload(mp_page_t *pg){
|
||||||
|
return (void*)((char*)pg + sizeof(mp_page_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void* large_page_payload(mp_large_t *large){
|
||||||
|
return (void*)((char*)large + sizeof(mp_large_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline mp_page_t* ptr_to_page(void* p){
|
||||||
|
return (mp_page_t*)((uintptr_t)p & ~(MEMPOOL_PAGE_SIZE - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int size_to_index(size_t size){
|
||||||
|
if(size == 0 || size > MEMPOOL_BLOCK_MAX_SIZE) return -1;
|
||||||
|
|
||||||
|
size_t aligned = (size + 7) & ~7; // 向上8字节对齐
|
||||||
|
return (aligned >> 3) - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// bitmap 操作函数
|
||||||
|
static inline void bitmap_set(uint64_t *bitmap, uint16_t index){
|
||||||
|
bitmap[index / 64] |= (1ULL << (index % 64));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void bitmap_clear(uint64_t *bitmap, uint16_t index){
|
||||||
|
bitmap[index / 64] &= ~(1ULL << (index % 64));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int bitmap_test(uint64_t *bitmap, uint16_t index){
|
||||||
|
return (bitmap[index / 64] & (1ULL << (index % 64))) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void bitmap_clear_all(uint64_t *bitmap, size_t size){
|
||||||
|
memset(bitmap, 0, size * sizeof(uint64_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据指针计算在页中的块索引
|
||||||
|
static inline uint16_t ptr_to_block_index(mp_page_t *pg, void *ptr){
|
||||||
|
char *base = (char*)page_payload(pg);
|
||||||
|
char *p = (char*)ptr;
|
||||||
|
size_t offset = p - base;
|
||||||
|
return (uint16_t)(offset / pg->owner->block_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static mp_page_t* mp_page_create(mp_bucket_t *owner){
|
||||||
|
if(!owner) return NULL;
|
||||||
|
|
||||||
|
void *mem = NULL;
|
||||||
|
mem = aligned_alloc(MEMPOOL_PAGE_SIZE, MEMPOOL_PAGE_SIZE);
|
||||||
|
if(!mem) return NULL;
|
||||||
|
|
||||||
|
mp_page_t *pg = (mp_page_t*) mem;
|
||||||
|
|
||||||
|
size_t usable = MEMPOOL_PAGE_SIZE - sizeof(mp_page_t);
|
||||||
|
uint16_t cap = (uint16_t)(usable / owner->block_size);
|
||||||
|
if(cap == 0) {
|
||||||
|
free(mem);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
pg->owner = owner;
|
||||||
|
pg->capacity = cap;
|
||||||
|
pg->free_count = cap;
|
||||||
|
pg->prev = NULL;
|
||||||
|
pg->next = NULL;
|
||||||
|
|
||||||
|
bitmap_clear_all(pg->bitmap, 8);
|
||||||
|
|
||||||
|
char *p = (char*)page_payload(pg);
|
||||||
|
for(uint16_t i = 0;i < cap - 1; ++ i){
|
||||||
|
*(void**)p = (void*)(p + owner->block_size);
|
||||||
|
p = p + owner->block_size;
|
||||||
|
}
|
||||||
|
*(void**)p = NULL;
|
||||||
|
pg->free_list = page_payload(pg);
|
||||||
|
|
||||||
|
return pg;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *mp_page_alloc(mp_page_t *pg){
|
||||||
|
if(!pg || !pg->free_list || pg->free_count == 0) return NULL;
|
||||||
|
|
||||||
|
void *ret = pg->free_list;
|
||||||
|
pg->free_list = *(void**)ret;
|
||||||
|
pg->free_count --;
|
||||||
|
|
||||||
|
// 标记该块为已分配
|
||||||
|
uint16_t index = ptr_to_block_index(pg, ret);
|
||||||
|
bitmap_set(pg->bitmap, index);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mp_page_free(mp_page_t *pg, void *ptr){
|
||||||
|
if(!pg || !ptr) return MEMPOOL_INVALID_INPUT;
|
||||||
|
|
||||||
|
// 检查是否是 double free
|
||||||
|
uint16_t index = ptr_to_block_index(pg, ptr);
|
||||||
|
if(!bitmap_test(pg->bitmap, index)){
|
||||||
|
// 该块未被分配,可能是 double free
|
||||||
|
return MEMPOOL_DOUBLE_FREE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 标记该块为空闲
|
||||||
|
bitmap_clear(pg->bitmap, index);
|
||||||
|
|
||||||
|
*(void**)ptr = pg->free_list;
|
||||||
|
pg->free_list = ptr;
|
||||||
|
pg->free_count ++;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int mp_create(mp_pool_t *pool){
|
||||||
|
if(!pool) return MEMPOOL_INVALID_INPUT;
|
||||||
|
for(int i = 0;i < MEMPOOL_NUM_CLASSES; ++ i){
|
||||||
|
mp_bucket_t *bucket = &pool->buckets[i];
|
||||||
|
bucket->block_size = (i+1)*MEMPOOL_ALIGNMENT;
|
||||||
|
bucket->page_count = 0;
|
||||||
|
bucket->empty_count = 0;
|
||||||
|
bucket->empty_pages = bucket->partial_pages = bucket->full_pages = NULL;
|
||||||
|
}
|
||||||
|
pool->large_list = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mp_destroy(mp_pool_t *pool){
|
||||||
|
if(!pool) return MEMPOOL_INVALID_INPUT;
|
||||||
|
|
||||||
|
// 释放所有大块内存
|
||||||
|
mp_large_t *large = pool->large_list;
|
||||||
|
while(large){
|
||||||
|
mp_large_t *next = large->next;
|
||||||
|
free(large);
|
||||||
|
large = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 释放所有页面
|
||||||
|
for(int i = 0; i < MEMPOOL_NUM_CLASSES; i++){
|
||||||
|
mp_bucket_t *bucket = &pool->buckets[i];
|
||||||
|
mp_page_t *lists[] = {bucket->empty_pages, bucket->partial_pages, bucket->full_pages};
|
||||||
|
for(int j = 0; j < 3; j++){
|
||||||
|
mp_page_t *pg = lists[j];
|
||||||
|
while(pg){
|
||||||
|
mp_page_t *next = pg->next;
|
||||||
|
free(pg);
|
||||||
|
pg = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *mp_alloc(mp_pool_t *pool, size_t size){
|
||||||
|
if(!pool) return NULL;
|
||||||
|
if(size > MEMPOOL_BLOCK_MAX_SIZE){
|
||||||
|
// large_page
|
||||||
|
void *mem = malloc(size + sizeof(mp_large_t));
|
||||||
|
if(!mem) return NULL;
|
||||||
|
|
||||||
|
mp_large_t *large_page = (mp_large_t*) mem;
|
||||||
|
|
||||||
|
large_page->prev = NULL;
|
||||||
|
large_page->next = pool->large_list;
|
||||||
|
if (pool->large_list) pool->large_list->prev = large_page;
|
||||||
|
pool->large_list = large_page;
|
||||||
|
|
||||||
|
return large_page_payload(large_page);
|
||||||
|
}
|
||||||
|
|
||||||
|
int i = size_to_index(size);
|
||||||
|
if(i == -1) return NULL;
|
||||||
|
|
||||||
|
mp_bucket_t *bucket = &pool->buckets[i];
|
||||||
|
|
||||||
|
if(!bucket->partial_pages){
|
||||||
|
if(!bucket->empty_pages){
|
||||||
|
// 无空页,重新分配
|
||||||
|
mp_page_t *pg = mp_page_create(bucket);
|
||||||
|
if(!pg) return NULL;
|
||||||
|
bucket->partial_pages = pg;
|
||||||
|
bucket->page_count ++;
|
||||||
|
}else{
|
||||||
|
// 有空页,使用空页
|
||||||
|
mp_page_t *epage = bucket->empty_pages;
|
||||||
|
bucket->empty_pages = epage->next;
|
||||||
|
if(bucket->empty_pages) bucket->empty_pages->prev = NULL;
|
||||||
|
epage->next = NULL;
|
||||||
|
epage->prev = NULL;
|
||||||
|
|
||||||
|
bucket->partial_pages = epage;
|
||||||
|
bucket->empty_count --;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mp_page_t *pg = bucket->partial_pages;
|
||||||
|
void *p = mp_page_alloc(pg);
|
||||||
|
if(!p) return NULL;
|
||||||
|
|
||||||
|
if(pg->free_count == 0){
|
||||||
|
// 该页没有空位
|
||||||
|
// 从partial链表中取出
|
||||||
|
if(pg == bucket->partial_pages){
|
||||||
|
bucket->partial_pages = pg->next;
|
||||||
|
}
|
||||||
|
if(pg->prev != NULL) pg->prev->next = pg->next;
|
||||||
|
if(pg->next != NULL) pg->next->prev = pg->prev;
|
||||||
|
pg->prev = NULL;
|
||||||
|
pg->next = NULL;
|
||||||
|
|
||||||
|
// 移入 fullpage
|
||||||
|
if(!bucket->full_pages) {
|
||||||
|
bucket->full_pages = pg;
|
||||||
|
}else{
|
||||||
|
pg->prev = NULL;
|
||||||
|
pg->next = bucket->full_pages;
|
||||||
|
if (bucket->full_pages) bucket->full_pages->prev = pg;
|
||||||
|
bucket->full_pages = pg;
|
||||||
|
}
|
||||||
|
}else {
|
||||||
|
// 不做处理
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mp_free(mp_pool_t *pool, void *ptr){
|
||||||
|
if(!pool || !ptr) return MEMPOOL_INVALID_INPUT;
|
||||||
|
mp_large_t *large = pool->large_list;
|
||||||
|
while(large){
|
||||||
|
if(ptr == large_page_payload(large)){
|
||||||
|
// 从large链表中删除
|
||||||
|
if(large == pool->large_list) pool->large_list = large->next;
|
||||||
|
if(large->prev) large->prev->next = large->next;
|
||||||
|
if(large->next) large->next->prev = large->prev;
|
||||||
|
large->prev = NULL;
|
||||||
|
large->next = NULL;
|
||||||
|
|
||||||
|
free(large);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
large = large->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
mp_page_t *pg = ptr_to_page(ptr);
|
||||||
|
|
||||||
|
uint16_t before = pg->free_count;
|
||||||
|
int ret = mp_page_free(pg, ptr);
|
||||||
|
if(ret != 0){
|
||||||
|
printf("mempool error\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(pg->free_count >= pg->capacity){
|
||||||
|
// free后成为完全空闲页
|
||||||
|
mp_bucket_t *bucket = pg->owner;
|
||||||
|
if(bucket->empty_count > MEMPOOL_CACHE_PAGE){
|
||||||
|
// 空闲页很多
|
||||||
|
// 摘出partial链表
|
||||||
|
if(pg == bucket->partial_pages) bucket->partial_pages = pg->next;
|
||||||
|
if(pg->prev != NULL) pg->prev->next = pg->next;
|
||||||
|
if(pg->next != NULL) pg->next->prev = pg->prev;
|
||||||
|
pg->prev = NULL;
|
||||||
|
pg->next = NULL;
|
||||||
|
// 释放
|
||||||
|
free(pg);
|
||||||
|
bucket->page_count --;
|
||||||
|
}else{
|
||||||
|
// 空闲页并不多
|
||||||
|
// 摘出partial链表
|
||||||
|
if(pg == bucket->partial_pages) bucket->partial_pages = pg->next;
|
||||||
|
if(pg->prev != NULL) pg->prev->next = pg->next;
|
||||||
|
if(pg->next != NULL) pg->next->prev = pg->prev;
|
||||||
|
pg->prev = NULL;
|
||||||
|
pg->next = NULL;
|
||||||
|
// 加入empty链表
|
||||||
|
pg->next = bucket->empty_pages;
|
||||||
|
if(bucket->empty_pages) bucket->empty_pages->prev = pg;
|
||||||
|
bucket->empty_pages = pg;
|
||||||
|
bucket->empty_count ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
}else if(before == 0 && pg->free_count == 1){
|
||||||
|
// free 后需要从full移动到partial
|
||||||
|
mp_bucket_t *bucket = pg->owner;
|
||||||
|
// 移出full链表
|
||||||
|
if(pg == bucket->full_pages) bucket->full_pages = pg->next;
|
||||||
|
if(pg->prev != NULL) pg->prev->next = pg->next;
|
||||||
|
if(pg->next != NULL) pg->next->prev = pg->prev;
|
||||||
|
pg->prev = NULL;
|
||||||
|
pg->next = NULL;
|
||||||
|
|
||||||
|
// 加入partial
|
||||||
|
pg->prev = NULL;
|
||||||
|
pg->next = bucket->partial_pages;
|
||||||
|
if (bucket->partial_pages) bucket->partial_pages->prev = pg;
|
||||||
|
bucket->partial_pages = pg;
|
||||||
|
}else {
|
||||||
|
// 有空余空间的页不做处理
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
67
memory/mempool.h
Normal file
67
memory/mempool.h
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
#ifndef __MEMORY_POOL_H__
|
||||||
|
#define __MEMORY_POOL_H__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define MEMPOOL_PAGE_SIZE 4096
|
||||||
|
#define MEMPOOL_BLOCK_MAX_SIZE 512
|
||||||
|
#define MEMPOOL_ALIGNMENT 8
|
||||||
|
#define MEMPOOL_NUM_CLASSES (MEMPOOL_BLOCK_MAX_SIZE / MEMPOOL_ALIGNMENT)
|
||||||
|
#define MEMPOOL_CACHE_PAGE 2
|
||||||
|
|
||||||
|
typedef struct mp_page_s mp_page_t;
|
||||||
|
typedef struct mp_bucket_s mp_bucket_t;
|
||||||
|
typedef struct mp_pool_s mp_pool_t;
|
||||||
|
typedef struct mp_large_s mp_large_t;
|
||||||
|
|
||||||
|
typedef enum{
|
||||||
|
MEMPOOL_INVALID_INPUT = -1,
|
||||||
|
MEMPOOL_MALLOC_ERROR = -2,
|
||||||
|
MEMPOOL_DOUBLE_FREE = -3,
|
||||||
|
}mp_err_t;
|
||||||
|
|
||||||
|
struct mp_page_s{
|
||||||
|
mp_bucket_t *owner;
|
||||||
|
|
||||||
|
mp_page_t *next;
|
||||||
|
mp_page_t *prev;
|
||||||
|
|
||||||
|
void *free_list;
|
||||||
|
|
||||||
|
uint16_t free_count;
|
||||||
|
uint16_t capacity;
|
||||||
|
|
||||||
|
uint64_t bitmap[8]; // 最多支持 512 个块 (64*8)
|
||||||
|
};
|
||||||
|
|
||||||
|
struct mp_bucket_s{
|
||||||
|
size_t block_size; // 桶中块大小
|
||||||
|
uint32_t page_count; // 桶中页数
|
||||||
|
uint32_t empty_count; // 空闲页数
|
||||||
|
|
||||||
|
mp_page_t *empty_pages; // 完全空闲page
|
||||||
|
mp_page_t *partial_pages; // 空闲page
|
||||||
|
mp_page_t *full_pages; // 满page
|
||||||
|
};
|
||||||
|
|
||||||
|
struct mp_large_s{
|
||||||
|
mp_large_t *next;
|
||||||
|
mp_large_t *prev;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct mp_pool_s{
|
||||||
|
mp_bucket_t buckets[MEMPOOL_NUM_CLASSES];
|
||||||
|
|
||||||
|
mp_large_t *large_list;
|
||||||
|
};
|
||||||
|
|
||||||
|
int mp_create(mp_pool_t *pool);
|
||||||
|
int mp_destroy(mp_pool_t *pool);
|
||||||
|
|
||||||
|
void *mp_alloc(mp_pool_t *pool, size_t size);
|
||||||
|
int mp_free(mp_pool_t *pool, void *ptr);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -103,7 +103,7 @@ int event_register(int fd, int event) {
|
|||||||
memset(conn_list[fd].rbuffer, 0, BUFFER_LENGTH);
|
memset(conn_list[fd].rbuffer, 0, BUFFER_LENGTH);
|
||||||
conn_list[fd].rlength = 0;
|
conn_list[fd].rlength = 0;
|
||||||
|
|
||||||
memset(conn_list[fd].wbuffer, 0, BUFFER_LENGTH);
|
memset(conn_list[fd].wbuffer, 0, BUFFER_LENGTH*2);
|
||||||
conn_list[fd].wlength = 0;
|
conn_list[fd].wlength = 0;
|
||||||
|
|
||||||
conn_list[fd].is_from_master = 0;
|
conn_list[fd].is_from_master = 0;
|
||||||
@@ -407,6 +407,7 @@ int reactor_start(unsigned short port, msg_handler handler, char *m_ip, int m_po
|
|||||||
|
|
||||||
#else
|
#else
|
||||||
if (events[i].events & EPOLLIN) {
|
if (events[i].events & EPOLLIN) {
|
||||||
|
// printf("connlist:%p, r_action:%p, recv_callaback:%p\n", &conn_list[connfd], &conn_list[connfd].r_action, conn_list[connfd].r_action.recv_callback);
|
||||||
conn_list[connfd].r_action.recv_callback(connfd);
|
conn_list[connfd].r_action.recv_callback(connfd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
2
server.h
2
server.h
@@ -23,7 +23,7 @@ struct conn {
|
|||||||
char rbuffer[BUFFER_LENGTH];
|
char rbuffer[BUFFER_LENGTH];
|
||||||
int rlength;
|
int rlength;
|
||||||
|
|
||||||
char wbuffer[BUFFER_LENGTH];
|
char wbuffer[BUFFER_LENGTH*2];
|
||||||
int wlength;
|
int wlength;
|
||||||
|
|
||||||
RCALLBACK send_callback;
|
RCALLBACK send_callback;
|
||||||
|
|||||||
@@ -4,6 +4,9 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <hiredis/hiredis.h>
|
#include <hiredis/hiredis.h>
|
||||||
|
|
||||||
|
#define TIME_SUB_MS(tv1, tv2) ((tv1.tv_sec - tv2.tv_sec) * 1000 + (tv1.tv_usec - tv2.tv_usec) / 1000)
|
||||||
|
|
||||||
|
|
||||||
static void die(redisContext *c, const char *msg) {
|
static void die(redisContext *c, const char *msg) {
|
||||||
fprintf(stderr, "%s: %s\n", msg, c && c->err ? c->errstr : "unknown");
|
fprintf(stderr, "%s: %s\n", msg, c && c->err ? c->errstr : "unknown");
|
||||||
exit(1);
|
exit(1);
|
||||||
@@ -91,9 +94,9 @@ void save(redisContext *c){
|
|||||||
printf("[OK] SAVE\n");
|
printf("[OK] SAVE\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void pipline_set_test(redisContext *c, int start, const char *op){
|
void pipline_set_test(redisContext *c, int start, int countN, const char *op){
|
||||||
/* ---------- 3) Pipeline 批处理测试 ---------- */
|
/* ---------- 3) Pipeline 批处理测试 ---------- */
|
||||||
const int N = 1000;
|
const int N = countN;
|
||||||
|
|
||||||
/* 一次塞 N 个 SET */
|
/* 一次塞 N 个 SET */
|
||||||
int end = start + N;
|
int end = start + N;
|
||||||
@@ -107,6 +110,9 @@ void pipline_set_test(redisContext *c, int start, const char *op){
|
|||||||
vv, (size_t)vn) != REDIS_OK) {
|
vv, (size_t)vn) != REDIS_OK) {
|
||||||
die(c, "redisAppendCommand SET failed");
|
die(c, "redisAppendCommand SET failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(i%10000 == 0) printf("%d\n", i);
|
||||||
|
|
||||||
}
|
}
|
||||||
/* 再一次性把 N 个回复读出来 */
|
/* 再一次性把 N 个回复读出来 */
|
||||||
for (int i = start; i < end; i++) {
|
for (int i = start; i < end; i++) {
|
||||||
@@ -118,8 +124,8 @@ void pipline_set_test(redisContext *c, int start, const char *op){
|
|||||||
printf("[OK] SET pipeline batch %d\n", N);
|
printf("[OK] SET pipeline batch %d\n", N);
|
||||||
}
|
}
|
||||||
|
|
||||||
void pipline_get_test(redisContext *c, int start, const char *op){
|
void pipline_get_test(redisContext *c, int start, int countN, const char *op){
|
||||||
const int N = 1000;
|
const int N = countN;
|
||||||
|
|
||||||
/* pipeline GET + 校验 */
|
/* pipeline GET + 校验 */
|
||||||
int end = start + N;
|
int end = start + N;
|
||||||
@@ -131,6 +137,8 @@ void pipline_get_test(redisContext *c, int start, const char *op){
|
|||||||
kk, (size_t)kn) != REDIS_OK) {
|
kk, (size_t)kn) != REDIS_OK) {
|
||||||
die(c, "redisAppendCommand GET failed");
|
die(c, "redisAppendCommand GET failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(i%10000 == 0) printf("%d\n", i);
|
||||||
}
|
}
|
||||||
for (int i = start; i < end; i++) {
|
for (int i = start; i < end; i++) {
|
||||||
redisReply *r = NULL;
|
redisReply *r = NULL;
|
||||||
@@ -143,12 +151,12 @@ void pipline_get_test(redisContext *c, int start, const char *op){
|
|||||||
printf("[OK] GET pipeline batch %d\n", N);
|
printf("[OK] GET pipeline batch %d\n", N);
|
||||||
}
|
}
|
||||||
|
|
||||||
void pipline_del_test(redisContext *c, int start, const char *op){
|
void pipline_del_test(redisContext *c, int start, int countN, const char *op){
|
||||||
const int N = 1000;
|
const int N = countN;
|
||||||
|
|
||||||
/* cleanup:pipeline DEL */
|
/* cleanup:pipeline DEL */
|
||||||
int end = start + N;
|
int end = start + N;
|
||||||
for (int i = start; i < end; i++) {
|
for (int i = start; i < end; i++) {
|
||||||
char kk[64];
|
char kk[64];
|
||||||
int kn = snprintf(kk, sizeof(kk), "p:%d", i);
|
int kn = snprintf(kk, sizeof(kk), "p:%d", i);
|
||||||
if (redisAppendCommand( c, "%s %b",
|
if (redisAppendCommand( c, "%s %b",
|
||||||
@@ -156,6 +164,8 @@ void pipline_del_test(redisContext *c, int start, const char *op){
|
|||||||
kk, (size_t)kn) != REDIS_OK) {
|
kk, (size_t)kn) != REDIS_OK) {
|
||||||
die(c, "redisAppendCommand DEL failed");
|
die(c, "redisAppendCommand DEL failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(i%10000 == 0) printf("%d\n", i);
|
||||||
}
|
}
|
||||||
for (int i = start; i < end; i++) {
|
for (int i = start; i < end; i++) {
|
||||||
redisReply *r = NULL;
|
redisReply *r = NULL;
|
||||||
@@ -186,27 +196,51 @@ int main(int argc, char **argv) {
|
|||||||
save(c);
|
save(c);
|
||||||
}else if(mode == 1){
|
}else if(mode == 1){
|
||||||
basic_command_test(c);
|
basic_command_test(c);
|
||||||
|
}else if(mode == 3){
|
||||||
|
struct timeval tv_begin, tv_end;
|
||||||
|
gettimeofday(&tv_begin, NULL);
|
||||||
|
long long ops = 100000;
|
||||||
|
|
||||||
|
pipline_set_test(c, 0, ops, "RSET");
|
||||||
|
|
||||||
|
gettimeofday(&tv_end, NULL);
|
||||||
|
int time_used = TIME_SUB_MS(tv_end, tv_begin);
|
||||||
|
long long qps = ops*1000/time_used;
|
||||||
|
printf("BATCH (N=%lld) --> time_used=%d ms, qps=%lld\n",
|
||||||
|
ops, time_used, qps);
|
||||||
|
}else if(mode == 4){
|
||||||
|
struct timeval tv_begin, tv_end;
|
||||||
|
gettimeofday(&tv_begin, NULL);
|
||||||
|
long long ops = 100000;
|
||||||
|
|
||||||
|
pipline_del_test(c, 0, ops, "RDEL");
|
||||||
|
|
||||||
|
gettimeofday(&tv_end, NULL);
|
||||||
|
int time_used = TIME_SUB_MS(tv_end, tv_begin);
|
||||||
|
long long qps = ops*1000/time_used;
|
||||||
|
printf("BATCH (N=%lld) --> time_used=%d ms, qps=%lld\n",
|
||||||
|
ops, time_used, qps);
|
||||||
|
|
||||||
}else if(mode == 10){
|
}else if(mode == 10){
|
||||||
pipline_set_test(c, 0, "SET");
|
pipline_set_test(c, 0, 1000, "SET");
|
||||||
}else if(mode == 11){
|
}else if(mode == 11){
|
||||||
pipline_get_test(c, 0, "GET");
|
pipline_get_test(c, 0, 1000, "GET");
|
||||||
}else if(mode == 12){
|
}else if(mode == 12){
|
||||||
pipline_del_test(c, 0, "DEL");
|
pipline_del_test(c, 0, 1000, "DEL");
|
||||||
|
|
||||||
}else if(mode == 20){
|
}else if(mode == 20){
|
||||||
pipline_set_test(c, 0, "RSET");
|
pipline_set_test(c, 0, 1000, "RSET");
|
||||||
}else if(mode == 21){
|
}else if(mode == 21){
|
||||||
pipline_get_test(c, 0, "RGET");
|
pipline_get_test(c, 0, 1000, "RGET");
|
||||||
}else if(mode == 22){
|
}else if(mode == 22){
|
||||||
pipline_del_test(c, 0, "RDEL");
|
pipline_del_test(c, 0, 1000, "RDEL");
|
||||||
|
|
||||||
}else if(mode == 30){
|
}else if(mode == 30){
|
||||||
pipline_set_test(c, 0, "HSET");
|
pipline_set_test(c, 0, 1000, "HSET");
|
||||||
}else if(mode == 31){
|
}else if(mode == 31){
|
||||||
pipline_get_test(c, 0, "HGET");
|
pipline_get_test(c, 0, 1000, "HGET");
|
||||||
}else if(mode == 32){
|
}else if(mode == 32){
|
||||||
pipline_del_test(c, 0, "HDEL");
|
pipline_del_test(c, 0, 1000, "HDEL");
|
||||||
}
|
}
|
||||||
|
|
||||||
redisFree(c);
|
redisFree(c);
|
||||||
|
|||||||
Reference in New Issue
Block a user