From 480bccfa04fda7873ca8da89040ff6c2ad3b9c44 Mon Sep 17 00:00:00 2001 From: King <1989wangbojing@163.com> Date: Sat, 25 May 2024 14:23:43 +0000 Subject: [PATCH] add hash/kvs-client --- Makefile | 34 ++++- Makefile.default | 29 ++++ hash.c | 228 +++++++++++++++++++++++++++++ kvs-client/go-kvstore.go | 42 ++++++ kvs-client/javakvstore.java | 37 +++++ kvs-client/js-kvstore.js | 26 ++++ kvs-client/py-kvstore.py | 30 ++++ kvs-client/rust-kvstore.rs | 18 +++ kvs_array.c | 12 +- kvs_hash | Bin 0 -> 16616 bytes kvs_hash.c | 285 ++++++++++++++++++++++++++++++++++++ kvs_rbtree.c | 7 +- kvs_skiptable.c | 140 ++++++++++++++++++ kvstore.c | 71 ++++++++- kvstore.h | 48 +++++- testcase.c | 121 +++++++++++++-- 16 files changed, 1100 insertions(+), 28 deletions(-) create mode 100644 Makefile.default create mode 100755 hash.c create mode 100755 kvs-client/go-kvstore.go create mode 100755 kvs-client/javakvstore.java create mode 100755 kvs-client/js-kvstore.js create mode 100755 kvs-client/py-kvstore.py create mode 100755 kvs-client/rust-kvstore.rs create mode 100755 kvs_hash create mode 100755 kvs_hash.c create mode 100755 kvs_skiptable.c diff --git a/Makefile b/Makefile index dad2cd4..9db46e0 100644 --- a/Makefile +++ b/Makefile @@ -1,15 +1,33 @@ - CC = gcc +FLAGS = -I ./NtyCo/core/ -L ./NtyCo/ -lntyco -lpthread -luring -ldl +SRCS = kvstore.c ntyco.c proactor.c kvs_array.c kvs_rbtree.c kvs_hash.c +TESTCASE_SRCS = testcase.c TARGET = kvstore -SRCS = kvstore.c ntyco.c proactor.c kvs_array.c kvs_rbtree.c -INC = -I ./NtyCo/core/ -LIBS = -L ./NtyCo/ -lntyco -luring +SUBDIR = ./NtyCo/ +TESTCASE = testcase + +OBJS = $(SRCS:.c=.o) -all: - $(CC) -o $(TARGET) $(SRCS) $(INC) $(LIBS) +all: $(SUBDIR) $(TARGET) $(TESTCASE) + +$(SUBDIR): ECHO + make -C $@ + +ECHO: + @echo $(SUBDIR) + +$(TARGET): $(OBJS) + $(CC) -o $@ $^ $(FLAGS) + +$(TESTCASE): $(TESTCASE_SRCS) + $(CC) -o $@ $^ + +%.o: %.c + $(CC) $(FLAGS) -c $^ -o $@ + +clean: + rm -rf $(OBJS) $(TARGET) $(TESTCASE) -clean: - rm -rf kvstore diff --git a/Makefile.default b/Makefile.default new file mode 100644 index 0000000..2b24b49 --- /dev/null +++ b/Makefile.default @@ -0,0 +1,29 @@ + + +CC = gcc +FLAGS = -I ./NtyCo/core/ -L ./NtyCo/ -lntyco -luring +TARGET = kvstore + +SRCS = kvstore.c ntyco.c proactor.c kvs_array.c kvs_rbtree.c +# INC = -I ./NtyCo/core/ +# LIBS = -L ./NtyCo/ -lntyco -luring +# FLAGS = -I ./NtyCo/core/ -L ./NtyCo/ -lntyco -luring + +OBJS = $(SRCS:.c=.o) +TESTCASE = testcase +SUBDIR = ./NtyCo/ + +all: $(SUBDIR) $(TARGET) # $(TESTCASE) + +$(SUBDIR): ECHO + make -C $@ + +ECHO: + @echo $(SUBDIR) + +$(TARGET): $(OBJS) + $(CC) -o $@ $^ $(FLAGS) + +clean: + rm -rf kvstore *.o + diff --git a/hash.c b/hash.c new file mode 100755 index 0000000..1b2e1b7 --- /dev/null +++ b/hash.c @@ -0,0 +1,228 @@ + + + +#include +#include +#include +#include + + + +#define MAX_KEY_LEN 128 +#define MAX_VALUE_LEN 512 +#define MAX_TABLE_SIZE 1024 + + + +typedef struct hashnode_s { + + char key[MAX_KEY_LEN]; + char value[MAX_VALUE_LEN]; + + struct hashnode_s *next; + +} hashnode_t; + + +typedef struct hashtable_s { + + hashnode_t **nodes; //* change **, + + int max_slots; + int count; + + pthread_mutex_t lock; + +} hashtable_t; + +hashtable_t hash; + + +//Connection +// 'C' + 'o' + 'n' +static int _hash(char *key, int size) { + + if (!key) return -1; + + int sum = 0; + int i = 0; + + while (key[i] != 0) { + sum += key[i]; + i ++; + } + + return sum % size; + +} + +hashnode_t *_create_node(char *key, char *value) { + + hashnode_t *node = (hashnode_t*)malloc(sizeof(hashnode_t)); + if (!node) return NULL; + + strncpy(node->key, key, MAX_KEY_LEN); + strncpy(node->value, value, MAX_VALUE_LEN); + node->next = NULL; + + return node; +} + + +// +int init_hashtable(hashtable_t *hash) { + + if (!hash) return -1; + + hash->nodes = (hashnode_t**)malloc(sizeof(hashnode_t*) * MAX_TABLE_SIZE); + if (!hash->nodes) return -1; + + hash->max_slots = MAX_TABLE_SIZE; + hash->count = 0; + + pthread_mutex_init(&hash->lock, NULL); + + return 0; +} + +// +void dest_hashtable(hashtable_t *hash) { + + if (!hash) return; + + int i = 0; + for (i = 0;i < hash->max_slots;i ++) { + hashnode_t *node = hash->nodes[i]; + + while (node != NULL) { // error + + hashnode_t *tmp = node; + node = node->next; + hash->nodes[i] = node; + + free(tmp); + + } + } + + free(hash->nodes); + +} + + + +// mp +int put_kv_hashtable(hashtable_t *hash, char *key, char *value) { + + if (!hash || !key || !value) return -1; + + int idx = _hash(key, MAX_TABLE_SIZE); + + pthread_mutex_lock(&hash->lock); + + hashnode_t *node = hash->nodes[idx]; +#if 1 + while (node != NULL) { + if (strcmp(node->key, key) == 0) { // exist + pthread_mutex_unlock(&hash->lock); + return 1; + } + node = node->next; + } +#endif + + hashnode_t *new_node = _create_node(key, value); + new_node->next = hash->nodes[idx]; + hash->nodes[idx] = new_node; + + hash->count ++; + + pthread_mutex_unlock(&hash->lock); + + return 0; +} + + +char * get_kv_hashtable(hashtable_t *hash, char *key) { + + if (!hash || !key) return NULL; + + int idx = _hash(key, MAX_TABLE_SIZE); + + pthread_mutex_lock(&hash->lock); + hashnode_t *node = hash->nodes[idx]; + + while (node != NULL) { + + if (strcmp(node->key, key) == 0) { + pthread_mutex_unlock(&hash->lock); + return node->value; + } + + node = node->next; + } + + pthread_mutex_unlock(&hash->lock); + + return NULL; + +} + + +int count_kv_hashtable(hashtable_t *hash) { + return hash->count; +} + +int delete_kv_hashtable(hashtable_t *hash, char *key) { + if (!hash || !key) return -2; + + int idx = _hash(key, MAX_TABLE_SIZE); + + pthread_mutex_lock(&hash->lock); + hashnode_t *head = hash->nodes[idx]; + if (head == NULL) return -1; // noexist + // head node + if (strcmp(head->key, key) == 0) { + hashnode_t *tmp = head->next; + hash->nodes[idx] = tmp; + + free(head); + hash->count --; + pthread_mutex_unlock(&hash->lock); + + return 0; + } + + hashnode_t *cur = head; + while (cur->next != NULL) { + if (strcmp(cur->next->key, key) == 0) break; // search node + + cur = cur->next; + } + + if (cur->next == NULL) { + + pthread_mutex_unlock(&hash->lock); + return -1; + } + + hashnode_t *tmp = cur->next; + cur->next = tmp->next; + free(tmp); + hash->count --; + + pthread_mutex_unlock(&hash->lock); + + return 0; +} + + +int exist_kv_hashtable(hashtable_t *hash, char *key) { + + char *value = get_kv_hashtable(hash, key); + if (value) return 1; + else return 0; + +} + + diff --git a/kvs-client/go-kvstore.go b/kvs-client/go-kvstore.go new file mode 100755 index 0000000..1b590c4 --- /dev/null +++ b/kvs-client/go-kvstore.go @@ -0,0 +1,42 @@ + + + +package main + +import ( + "fmt" + "net" + "os" +) + +func main() { + conn, err := net.Dial("tcp", "192.168.243.131:2000") + if err != nil { + fmt.Println("connect failed: ", err) + os.Exit(1) + } + defer conn.Close() + + message := "SET Teacher King" + _, err = conn.Write([]byte(message)) + if err != nil { + fmt.Println("send failed: ", err) + os.Exit(1) + } + + fmt.Printf("send msg: %s\n", message) + + buffer := make([]byte, 1024) + length, err := conn.Read(buffer) + if err != nil { + fmt.Println("recv failed: ", err) + os.Exit(1) + } + + response := string(buffer[:length]) + fmt.Printf("recv msg: %s\n", response) +} + + + + diff --git a/kvs-client/javakvstore.java b/kvs-client/javakvstore.java new file mode 100755 index 0000000..32b161d --- /dev/null +++ b/kvs-client/javakvstore.java @@ -0,0 +1,37 @@ + +import java.io.*; +import java.net.*; + +public class javakvstore { + public static void main(String[] args) { + String serverAddress = "192.168.243.131"; + int serverPort = 2000; + + try { + Socket socket = new Socket(serverAddress, serverPort); + + OutputStream outputStream = socket.getOutputStream(); + InputStream inputStream = socket.getInputStream(); + + String message = "SET T1 KING"; + outputStream.write(message.getBytes()); + + byte[] buffer = new byte[1024]; + int bytesRead = inputStream.read(buffer); + if (bytesRead > 0) { + String response = new String(buffer, 0, bytesRead); + System.out.println("recv: " + response); + } + + inputStream.close(); + outputStream.close(); + socket.close(); + + } catch (IOException e) { + e.printStackTrace(); + } + } +} + + + diff --git a/kvs-client/js-kvstore.js b/kvs-client/js-kvstore.js new file mode 100755 index 0000000..826ca47 --- /dev/null +++ b/kvs-client/js-kvstore.js @@ -0,0 +1,26 @@ + + +const net = require('net'); + +const client = net.createConnection({ port: 2000, host: '192.168.243.131' }, () => { + console.log('connect kvstore'); + + client.write('GET Teacher'); +}); + +client.on('data', (data) => { + console.log(`recv:${data.toString()}`); + + client.end(); +}); + +client.on('error', (err) => { + console.error('connect failed:', err); +}); + +client.on('close', () => { + console.log('close connection'); +}); + + + diff --git a/kvs-client/py-kvstore.py b/kvs-client/py-kvstore.py new file mode 100755 index 0000000..923cd26 --- /dev/null +++ b/kvs-client/py-kvstore.py @@ -0,0 +1,30 @@ + + + +import socket + +def main(): + client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + + server_address = ('192.168.243.131', 2000) + + try: + client_socket.connect(server_address) + + message = "GET Teacher" + client_socket.sendall(message.encode()) + + response = client_socket.recv(1024) + + print("recv:", response.decode()) + + except Exception as e: + print("发生异常:", str(e)) + + finally: + client_socket.close() + +if __name__ == '__main__': + main() + + diff --git a/kvs-client/rust-kvstore.rs b/kvs-client/rust-kvstore.rs new file mode 100755 index 0000000..8b0e014 --- /dev/null +++ b/kvs-client/rust-kvstore.rs @@ -0,0 +1,18 @@ + + +use std::io::{self, Read, Write}; +use std::net::TcpStream; + +fn main() -> io::Result<()> { + let server_address = "192.168.243.131:2000"; + + let mut stream = TcpStream::connect(server_address)?; + + stream.write_all(b"GET Teacher")?; + + let mut buffer = [0; 1024]; + let bytes_read = stream.read(&mut buffer)?; + println!("Received: {}", String::from_utf8_lossy(&buffer[..bytes_read])); + + Ok(()) +} diff --git a/kvs_array.c b/kvs_array.c index 88259c2..f8f9664 100644 --- a/kvs_array.c +++ b/kvs_array.c @@ -118,8 +118,11 @@ int kvs_array_del(kvs_array_t *inst, char *key) { kvs_free(inst->table[i].value); inst->table[i].value = NULL; - - inst->idx = i; +// error: > 1024 + if (inst->total-1 == i) { + inst->total --; + } + return 0; } @@ -136,6 +139,11 @@ int kvs_array_del(kvs_array_t *inst, char *key) { int kvs_array_mod(kvs_array_t *inst, char *key, char *value) { if (inst == NULL || key == NULL || value == NULL) return -1; +// error: > 1024 + if (inst->total == 0) { + return KVS_ARRAY_SIZE; + } + int i = 0; for (i = 0;i < inst->total;i ++) { diff --git a/kvs_hash b/kvs_hash new file mode 100755 index 0000000000000000000000000000000000000000..425a61f11d70259b07301d03a7675d695331bcbc GIT binary patch literal 16616 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 +#include +#include +#include + + +#include "kvstore.h" + + +// Key, Value --> +// Modify + + + +kvs_hash_t global_hash; + + +//Connection +// 'C' + 'o' + 'n' +static int _hash(char *key, int size) { + + if (!key) return -1; + + int sum = 0; + int i = 0; + + while (key[i] != 0) { + sum += key[i]; + i ++; + } + + return sum % size; + +} + +hashnode_t *_create_node(char *key, char *value) { + + hashnode_t *node = (hashnode_t*)kvs_malloc(sizeof(hashnode_t)); + if (!node) return NULL; + +#if ENABLE_KEY_POINTER + char *kcopy = kvs_malloc(strlen(key) + 1); + if (kcopy == NULL) return NULL; + memset(kcopy, 0, strlen(key) + 1); + strncpy(kcopy, key, strlen(key)); + + node->key = kcopy; + + char *kvalue = kvs_malloc(strlen(value) + 1); + if (kvalue == NULL) { + kvs_free(kvalue); + return NULL; + } + memset(kvalue, 0, strlen(value) + 1); + strncpy(kvalue, value, strlen(value)); + + node->value = kvalue; + +#else + strncpy(node->key, key, MAX_KEY_LEN); + strncpy(node->value, value, MAX_VALUE_LEN); +#endif + node->next = NULL; + + return node; +} + + +// +int kvs_hash_create(kvs_hash_t *hash) { + + if (!hash) return -1; + + hash->nodes = (hashnode_t**)kvs_malloc(sizeof(hashnode_t*) * MAX_TABLE_SIZE); + if (!hash->nodes) return -1; + + hash->max_slots = MAX_TABLE_SIZE; + hash->count = 0; + + return 0; +} + +// +void kvs_hash_destory(kvs_hash_t *hash) { + + if (!hash) return; + + int i = 0; + for (i = 0;i < hash->max_slots;i ++) { + hashnode_t *node = hash->nodes[i]; + + while (node != NULL) { // error + + hashnode_t *tmp = node; + node = node->next; + hash->nodes[i] = node; + + kvs_free(tmp); + + } + } + + kvs_free(hash->nodes); + +} + +// 5 + 2 + +// mp +int kvs_hash_set(kvs_hash_t *hash, char *key, char *value) { + + if (!hash || !key || !value) return -1; + + int idx = _hash(key, MAX_TABLE_SIZE); + + hashnode_t *node = hash->nodes[idx]; +#if 1 + while (node != NULL) { + if (strcmp(node->key, key) == 0) { // exist + return 1; + } + node = node->next; + } +#endif + + hashnode_t *new_node = _create_node(key, value); + new_node->next = hash->nodes[idx]; + hash->nodes[idx] = new_node; + + hash->count ++; + + return 0; +} + + +char * kvs_hash_get(kvs_hash_t *hash, char *key) { + + if (!hash || !key) return NULL; + + int idx = _hash(key, MAX_TABLE_SIZE); + + hashnode_t *node = hash->nodes[idx]; + + while (node != NULL) { + + if (strcmp(node->key, key) == 0) { + return node->value; + } + + node = node->next; + } + + return NULL; + +} + + +int kvs_hash_mod(kvs_hash_t *hash, char *key, char *value) { + + if (!hash || !key) return -1; + + int idx = _hash(key, MAX_TABLE_SIZE); + + hashnode_t *node = hash->nodes[idx]; + + while (node != NULL) { + + if (strcmp(node->key, key) == 0) { + break; + } + + node = node->next; + } + + if (node == NULL) { + return 1; + } + + // node --> + kvs_free(node->value); + + char *kvalue = kvs_malloc(strlen(value) + 1); + if (kvalue == NULL) return -2; + memset(kvalue, 0, strlen(value) + 1); + strncpy(kvalue, value, strlen(value)); + + node->value = kvalue; + + return 0; +} + +int kvs_hash_count(kvs_hash_t *hash) { + return hash->count; +} + +int kvs_hash_del(kvs_hash_t *hash, char *key) { + if (!hash || !key) return -2; + + int idx = _hash(key, MAX_TABLE_SIZE); + + hashnode_t *head = hash->nodes[idx]; + if (head == NULL) return -1; // noexist + // head node + if (strcmp(head->key, key) == 0) { + hashnode_t *tmp = head->next; + hash->nodes[idx] = tmp; + + kvs_free(head); + hash->count --; + + return 0; + } + + hashnode_t *cur = head; + while (cur->next != NULL) { + if (strcmp(cur->next->key, key) == 0) break; // search node + + cur = cur->next; + } + + if (cur->next == NULL) { + + return -1; + } + + hashnode_t *tmp = cur->next; + cur->next = tmp->next; +#if ENABLE_KEY_POINTER + kvs_free(tmp->key); + kvs_free(tmp->value); +#endif + kvs_free(tmp); + + hash->count --; + + return 0; +} + + +int kvs_hash_exist(kvs_hash_t *hash, char *key) { + + char *value = kvs_hash_get(hash, key); + if (!value) return 1; + + return 0; + +} + +#if 0 +int main() { + + kvs_hash_create(&hash); + + kvs_hash_set(&hash, "Teacher1", "King"); + kvs_hash_set(&hash, "Teacher2", "Darren"); + kvs_hash_set(&hash, "Teacher3", "Mark"); + kvs_hash_set(&hash, "Teacher4", "Vico"); + kvs_hash_set(&hash, "Teacher5", "Nick"); + + char *value1 = kvs_hash_get(&hash, "Teacher1"); + printf("Teacher1 : %s\n", value1); + + int ret = kvs_hash_mod(&hash, "Teacher1", "King1"); + printf("mode Teacher1 ret : %d\n", ret); + + char *value2 = kvs_hash_get(&hash, "Teacher1"); + printf("Teacher2 : %s\n", value1); + + ret = kvs_hash_del(&hash, "Teacher1"); + printf("delete Teacher1 ret : %d\n", ret); + + ret = kvs_hash_exist(&hash, "Teacher1"); + printf("Exist Teacher1 ret : %d\n", ret); + + kvs_hash_destory(&hash); + + return 0; +} + +#endif + + diff --git a/kvs_rbtree.c b/kvs_rbtree.c index f215e43..4746b70 100755 --- a/kvs_rbtree.c +++ b/kvs_rbtree.c @@ -498,8 +498,9 @@ int kvs_rbtree_set(kvs_rbtree_t *inst, char *key, char *value) { char* kvs_rbtree_get(kvs_rbtree_t *inst, char *key) { if (!inst || !key) return NULL; - rbtree_node *node = rbtree_search(inst, key); + if (!node) return NULL; // no exist + if (node == inst->nil) return NULL; return node->value; @@ -524,7 +525,8 @@ int kvs_rbtree_mod(kvs_rbtree_t *inst, char *key, char *value) { rbtree_node *node = rbtree_search(inst, key); if (!node) return 1; // no exist - + if (node == inst->nil) return 1; + kvs_free(node->value); node->value = kvs_malloc(strlen(value) + 1); @@ -543,6 +545,7 @@ int kvs_rbtree_exist(kvs_rbtree_t *inst, char *key) { rbtree_node *node = rbtree_search(inst, key); if (!node) return 1; // no exist + if (node == inst->nil) return 1; return 0; } diff --git a/kvs_skiptable.c b/kvs_skiptable.c new file mode 100755 index 0000000..e26d3cc --- /dev/null +++ b/kvs_skiptable.c @@ -0,0 +1,140 @@ + + + +#include +#include +#include + +#define MAX_LEVEL 6 + +typedef struct Node { + int key; + int value; + struct Node** forward; +} Node; + +typedef struct SkipList { + int level; + Node* header; +} SkipList; + +Node* createNode(int level, int key, int value) { + Node* newNode = (Node*)malloc(sizeof(Node)); + newNode->key = key; + newNode->value = value; + newNode->forward = (Node**)malloc((level + 1) * sizeof(Node*)); + + return newNode; +} + +SkipList* createSkipList() { + SkipList* skipList = (SkipList*)malloc(sizeof(SkipList)); + skipList->level = 0; + + skipList->header = createNode(MAX_LEVEL, -1, -1); + + for (int i = 0; i <= MAX_LEVEL; ++i) { + skipList->header->forward[i] = NULL; + } + + return skipList; +} + +int randomLevel() { + int level = 0; + while (rand() < RAND_MAX / 2 && level < MAX_LEVEL) + level++; + return level; +} + +bool insert(SkipList* skipList, int key, int value) { + Node* update[MAX_LEVEL + 1]; + Node* current = skipList->header; + + for (int i = skipList->level; i >= 0; --i) { + while (current->forward[i] != NULL && current->forward[i]->key < key) + current = current->forward[i]; + update[i] = current; + } + + current = current->forward[0]; + + if (current == NULL || current->key != key) { + int level = randomLevel(); + + if (level > skipList->level) { + for (int i = skipList->level + 1; i <= level; ++i) + update[i] = skipList->header; + skipList->level = level; + } + + Node* newNode = createNode(level, key, value); + + for (int i = 0; i <= level; ++i) { + newNode->forward[i] = update[i]->forward[i]; + update[i]->forward[i] = newNode; + } + + printf("Inserted key %d\n", key); + + return true; + } else { + printf("Key %d already exists\n", key); + return false; + } +} + +void display(SkipList* skipList) { + printf("Skip List:\n"); + + for (int i = 0; i <= skipList->level; ++i) { + Node* node = skipList->header->forward[i]; + printf("Level %d: ", i); + + while (node != NULL) { + printf("%d ", node->key); + node = node->forward[i]; + } + + printf("\n"); + } +} + +bool search(SkipList* skipList, int key) { + Node* current = skipList->header; + + for (int i = skipList->level; i >= 0; --i) { + while (current->forward[i] != NULL && current->forward[i]->key < key) + current = current->forward[i]; + } + + current = current -> forward[0]; + + if(current && current -> key == key){ + printf("Key %d found with value %d\n", key, current->value); + return true; + }else{ + printf("Key %d not found\n", key); + return false; + } +} + +int main() { + SkipList* skipList = createSkipList(); + + insert(skipList, 3, 30); + insert(skipList, 6, 60); + insert(skipList, 2, 20); + insert(skipList, 4, 40); + + display(skipList); + + search(skipList, 3); + search(skipList, 7); + + return 0; +} + + + + diff --git a/kvstore.c b/kvstore.c index 4d51cc1..47e4a70 100644 --- a/kvstore.c +++ b/kvstore.c @@ -13,7 +13,9 @@ extern kvs_array_t global_array; extern kvs_rbtree_t global_rbtree; #endif - +#if ENABLE_HASH +extern kvs_hash_t global_hash; +#endif void *kvs_malloc(size_t size) { return malloc(size); @@ -26,7 +28,8 @@ void kvs_free(void *ptr) { const char *command[] = { "SET", "GET", "DEL", "MOD", "EXIST", - "RSET", "RGET", "RDEL", "RMOD", "REXIST" + "RSET", "RGET", "RDEL", "RMOD", "REXIST", + "HSET", "HGET", "HDEL", "HMOD", "HEXIST" }; enum { @@ -43,6 +46,12 @@ enum { KVS_CMD_RDEL, KVS_CMD_RMOD, KVS_CMD_REXIST, + // hash + KVS_CMD_HSET, + KVS_CMD_HGET, + KVS_CMD_HDEL, + KVS_CMD_HMOD, + KVS_CMD_HEXIST, KVS_CMD_COUNT, }; @@ -195,6 +204,56 @@ int kvs_filter_protocol(char **tokens, int count, char *response) { } break; #endif +#if ENABLE_HASH + case KVS_CMD_HSET: + ret = kvs_hash_set(&global_hash ,key, value); + if (ret < 0) { + length = sprintf(response, "ERROR\r\n"); + } else if (ret == 0) { + length = sprintf(response, "OK\r\n"); + } else { + length = sprintf(response, "EXIST\r\n"); + } + + break; + case KVS_CMD_HGET: { + char *result = kvs_hash_get(&global_hash, key); + if (result == NULL) { + length = sprintf(response, "NO EXIST\r\n"); + } else { + length = sprintf(response, "%s\r\n", result); + } + break; + } + case KVS_CMD_HDEL: + ret = kvs_hash_del(&global_hash ,key); + if (ret < 0) { + length = sprintf(response, "ERROR\r\n"); + } else if (ret == 0) { + length = sprintf(response, "OK\r\n"); + } else { + length = sprintf(response, "NO EXIST\r\n"); + } + break; + case KVS_CMD_HMOD: + ret = kvs_hash_mod(&global_hash ,key, value); + if (ret < 0) { + length = sprintf(response, "ERROR\r\n"); + } else if (ret == 0) { + length = sprintf(response, "OK\r\n"); + } else { + length = sprintf(response, "NO EXIST\r\n"); + } + break; + case KVS_CMD_HEXIST: + ret = kvs_hash_exist(&global_hash ,key); + if (ret == 0) { + length = sprintf(response, "EXIST\r\n"); + } else { + length = sprintf(response, "NO EXIST\r\n"); + } + break; +#endif default: assert(0); @@ -243,6 +302,11 @@ int init_kvengine(void) { kvs_rbtree_create(&global_rbtree); #endif +#if ENABLE_HASH + memset(&global_hash, 0, sizeof(kvs_hash_t)); + kvs_hash_create(&global_hash); +#endif + return 0; } @@ -253,6 +317,9 @@ void dest_kvengine(void) { #if ENABLE_RBTREE kvs_rbtree_destory(&global_rbtree); #endif +#if ENABLE_HASH + kvs_hash_destory(&global_hash); +#endif } diff --git a/kvstore.h b/kvstore.h index be89820..0971c00 100644 --- a/kvstore.h +++ b/kvstore.h @@ -24,7 +24,7 @@ #define ENABLE_ARRAY 1 #define ENABLE_RBTREE 1 - +#define ENABLE_HASH 1 typedef int (*msg_handler)(char *msg, int length, char *response); @@ -104,6 +104,52 @@ int kvs_rbtree_exist(kvs_rbtree_t *inst, char *key); +#endif + + +#if ENABLE_HASH + +#define MAX_KEY_LEN 128 +#define MAX_VALUE_LEN 512 +#define MAX_TABLE_SIZE 1024 + +#define ENABLE_KEY_POINTER 1 + + +typedef struct hashnode_s { +#if ENABLE_KEY_POINTER + char *key; + char *value; +#else + char key[MAX_KEY_LEN]; + char value[MAX_VALUE_LEN]; +#endif + struct hashnode_s *next; + +} hashnode_t; + + +typedef struct hashtable_s { + + hashnode_t **nodes; //* change **, + + int max_slots; + int count; + +} hashtable_t; + +typedef struct hashtable_s kvs_hash_t; + + +int kvs_hash_create(kvs_hash_t *hash); +void kvs_hash_destory(kvs_hash_t *hash); +int kvs_hash_set(hashtable_t *hash, char *key, char *value); +char * kvs_hash_get(kvs_hash_t *hash, char *key); +int kvs_hash_mod(kvs_hash_t *hash, char *key, char *value); +int kvs_hash_del(kvs_hash_t *hash, char *key); +int kvs_hash_exist(kvs_hash_t *hash, char *key); + + #endif diff --git a/testcase.c b/testcase.c index 69b1a29..c93f873 100755 --- a/testcase.c +++ b/testcase.c @@ -90,9 +90,9 @@ void array_testcase(int connfd) { } -void array_testcase_10w(int connfd) { +void array_testcase_1w(int connfd) { - int count = 1000; + int count = 10000; int i = 0; struct timeval tv_begin; @@ -117,7 +117,7 @@ void array_testcase_10w(int connfd) { int time_used = TIME_SUB_MS(tv_end, tv_begin); // ms - printf("array testcase --> time_used: %d, qps: %d\n", time_used, 9000 * 1000 / time_used); + printf("array testcase --> time_used: %d, qps: %d\n", time_used, 90000 * 1000 / time_used); } @@ -125,34 +125,129 @@ void array_testcase_10w(int connfd) { void rbtree_testcase(int connfd) { testcase(connfd, "RSET Teacher King", "OK\r\n", "RSET-Teacher"); - testcase(connfd, "RGET Teacher", "King\r\n", "RGET-Teacher"); - testcase(connfd, "RMOD Teacher Darren", "OK\r\n", "RMOD-Teacher"); - testcase(connfd, "RGET Teacher", "Darren\r\n", "RGET-Teacher"); - testcase(connfd, "REXIST Teacher", "EXIST\r\n", "RGET-Teacher"); + testcase(connfd, "RGET Teacher", "King\r\n", "RGET-King-Teacher"); + testcase(connfd, "RMOD Teacher Darren", "OK\r\n", "RMOD-D-Teacher"); + testcase(connfd, "RGET Teacher", "Darren\r\n", "RGET-Darren-Teacher"); + testcase(connfd, "REXIST Teacher", "EXIST\r\n", "REXIST-Teacher"); testcase(connfd, "RDEL Teacher", "OK\r\n", "RDEL-Teacher"); - testcase(connfd, "RGET Teacher", "NO EXIST\r\n", "RGET-Teacher"); - testcase(connfd, "RMOD Teacher KING", "NO EXIST\r\n", "RMOD-Teacher"); - testcase(connfd, "REXIST Teacher", "NO EXIST\r\n", "RGET-Teacher"); + testcase(connfd, "RGET Teacher", "NO EXIST\r\n", "RGET-K-Teacher"); + testcase(connfd, "RMOD Teacher KING", "NO EXIST\r\n", "RMOD-K-Teacher"); + testcase(connfd, "REXIST Teacher", "NO EXIST\r\n", "REXIST-Teacher"); } +void rbtree_testcase_1w(int connfd) { + + int count = 10000; + int i = 0; + + struct timeval tv_begin; + gettimeofday(&tv_begin, NULL); + + for (i = 0;i < count;i ++) { + + testcase(connfd, "RSET Teacher King", "OK\r\n", "RSET-Teacher"); + testcase(connfd, "RGET Teacher", "King\r\n", "RGET-King-Teacher"); + testcase(connfd, "RMOD Teacher Darren", "OK\r\n", "RMOD-D-Teacher"); + testcase(connfd, "RGET Teacher", "Darren\r\n", "RGET-Darren-Teacher"); + testcase(connfd, "REXIST Teacher", "EXIST\r\n", "REXIST-Teacher"); + testcase(connfd, "RDEL Teacher", "OK\r\n", "RDEL-Teacher"); + testcase(connfd, "RGET Teacher", "NO EXIST\r\n", "RGET-K-Teacher"); + testcase(connfd, "RMOD Teacher KING", "NO EXIST\r\n", "RMOD-K-Teacher"); + testcase(connfd, "REXIST Teacher", "NO EXIST\r\n", "REXIST-Teacher"); + + } + + struct timeval tv_end; + gettimeofday(&tv_end, NULL); + + int time_used = TIME_SUB_MS(tv_end, tv_begin); // ms + + printf("rbtree testcase --> time_used: %d, qps: %d\n", time_used, 90000 * 1000 / time_used); + +} + + +void rbtree_testcase_3w(int connfd) { + + int count = 10000; + int i = 0; + + struct timeval tv_begin; + gettimeofday(&tv_begin, NULL); + + for (i = 0;i < count;i ++) { + + char cmd[128] = {0}; + snprintf(cmd, 128, "RSET Teacher%d King%d", i, i); + testcase(connfd, cmd, "OK\r\n", "RSET-Teacher"); + } + + for (i = 0;i < count;i ++) { + + char cmd[128] = {0}; + snprintf(cmd, 128, "RGET Teacher%d", i); + + char result[128] = {0}; + snprintf(result, 128, "King%d\r\n", i); + + testcase(connfd, cmd, result, "RGET-King-Teacher"); + } + + for (i = 0;i < count;i ++) { + + char cmd[128] = {0}; + snprintf(cmd, 128, "RMOD Teacher%d King%d", i, i); + testcase(connfd, cmd, "OK\r\n", "RGET-King-Teacher"); + } + + struct timeval tv_end; + gettimeofday(&tv_end, NULL); + + int time_used = TIME_SUB_MS(tv_end, tv_begin); // ms + + printf("rbtree testcase --> time_used: %d, qps: %d\n", time_used, 30000 * 1000 / time_used); + +} + +void hash_testcase(int connfd) { + + testcase(connfd, "HSET Teacher King", "OK\r\n", "HSET-Teacher"); + testcase(connfd, "HGET Teacher", "King\r\n", "HGET-King-Teacher"); + testcase(connfd, "HMOD Teacher Darren", "OK\r\n", "HMOD-D-Teacher"); + testcase(connfd, "HGET Teacher", "Darren\r\n", "HGET-Darren-Teacher"); + testcase(connfd, "HEXIST Teacher", "EXIST\r\n", "HEXIST-Teacher"); + testcase(connfd, "HDEL Teacher", "OK\r\n", "HDEL-Teacher"); + testcase(connfd, "HGET Teacher", "NO EXIST\r\n", "HGET-K-Teacher"); + testcase(connfd, "HMOD Teacher KING", "NO EXIST\r\n", "HMOD-K-Teacher"); + testcase(connfd, "HEXIST Teacher", "NO EXIST\r\n", "HEXIST-Teacher"); + +} // testcase 192.168.243.131 2000 int main(int argc, char *argv[]) { - if (argc != 3) { + if (argc != 4) { printf("arg error\n"); return -1; } char *ip = argv[1]; int port = atoi(argv[2]); + int mode = atoi(argv[3]); int connfd = connect_tcpserver(ip, port); - rbtree_testcase(connfd); - //array_testcase_10w(connfd); + if (mode == 0) { + rbtree_testcase_1w(connfd); + } else if (mode == 1) { + rbtree_testcase_3w(connfd); + } else if (mode == 2) { + array_testcase_1w(connfd); + } else if (mode == 3) { + hash_testcase(connfd); + } return 0;