#include "kvstore.h" #include "kvs_rw_tools.h" #include "memory/alloc_dispatch.h" #include "diskuring/diskuring.h" // Key, Value --> // Modify kvs_hash_t global_hash; //Connection // 'C' + 'o' + 'n' static int _hash(const void *key, uint32_t key_len, int size) { if (!key || size <= 0) return -1; const uint8_t *p = (const uint8_t *)key; uint32_t sum = 0; for (uint32_t i = 0; i < key_len; i++) { sum += p[i]; } return sum % size; } static int _key_equal(const hashnode_t *node, const void *key, uint32_t key_len) { if (!node || !key) return 0; if (!node->key) return 0; if (node->key_len != key_len) return 0; return memcmp(node->key, key, key_len) == 0; } static hashnode_t *_create_node(const void *key, uint32_t key_len, const void *value, uint32_t value_len) { hashnode_t *node = (hashnode_t*)kvs_malloc(sizeof(hashnode_t)); if (!node) return NULL; memset(node, 0, sizeof(*node)); if (key_len > 0) { node->key = (uint8_t*)kvs_malloc(key_len); if (!node->key) { kvs_free(node); return NULL; } memcpy(node->key, key, key_len); node->key_len = key_len; } if (value_len > 0) { node->value = (uint8_t*)kvs_malloc(value_len); if (!node->value) { kvs_free(node->key); kvs_free(node); return NULL; } memcpy(node->value, value, value_len); node->value_len = value_len; } else { node->value = NULL; node->value_len = 0; } 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; memset(hash->nodes, 0, sizeof(hashnode_t*) * MAX_TABLE_SIZE); hash->max_slots = MAX_TABLE_SIZE; hash->count = 0; return 0; } // void kvs_hash_destroy(kvs_hash_t *hash) { if (!hash || !hash->nodes) return; for (int i = 0; i < hash->max_slots; i++) { hashnode_t *node = hash->nodes[i]; while (node != NULL) { hashnode_t *tmp = node; node = node->next; if (tmp->key) kvs_free(tmp->key); if (tmp->value) kvs_free(tmp->value); kvs_free(tmp); } hash->nodes[i] = NULL; } kvs_free(hash->nodes); hash->nodes = NULL; hash->max_slots = 0; hash->count = 0; } // 5 + 2 // mp /* * @return: <0 error; 0 success; 1 exist */ int kvs_hash_set_bin(kvs_hash_t *hash, const void *key, uint32_t key_len, const void *value, uint32_t value_len) { if (!hash || !hash->nodes || !key || key_len == 0) return -1; int idx = _hash(key, key_len, MAX_TABLE_SIZE); if (idx < 0) return -1; hashnode_t *node = hash->nodes[idx]; while (node != NULL) { if (_key_equal(node, key, key_len)) { // exist return 1; } node = node->next; } hashnode_t *new_node = _create_node(key, key_len, value, value_len); if (!new_node) return -2; new_node->next = hash->nodes[idx]; hash->nodes[idx] = new_node; hash->count ++; return 0; } /* * @return: NULL notexist, NOTNULL exist。out_value_len 是长度。 */ void *kvs_hash_get_bin(kvs_hash_t *hash, const void *key, uint32_t key_len, uint32_t *out_value_len) { if (!hash || !hash->nodes || !key || key_len == 0 || !out_value_len) return NULL; *out_value_len = 0; int idx = _hash(key, key_len, MAX_TABLE_SIZE); if (idx < 0) return NULL; hashnode_t *node = hash->nodes[idx]; while (node != NULL) { if (_key_equal(node, key, key_len)) { *out_value_len = node->value_len; return node->value; } node = node->next; } return NULL; } /* * @return <0 error; =0 success; >0 no exist */ int kvs_hash_mod_bin(kvs_hash_t *hash, const void *key, uint32_t key_len, const void *value, uint32_t value_len) { if (!hash || !hash->nodes || !key || key_len == 0 || !value) return -1; int idx = _hash(key, key_len, MAX_TABLE_SIZE); if (idx < 0) return -1; hashnode_t *node = hash->nodes[idx]; while (node != NULL) { if (_key_equal(node, key, key_len)) { break; } node = node->next; } if (node == NULL) { return 1; } // node --> if (node->value) kvs_free(node->value); node->value = NULL; node->value_len = 0; if (value_len > 0) { uint8_t *vcopy = (uint8_t*)kvs_malloc(value_len); if (!vcopy) return -2; memcpy(vcopy, value, value_len); node->value = vcopy; node->value_len = value_len; } return 0; } int kvs_hash_count(kvs_hash_t *hash) { return hash->count; } /* * @return <0 error; =0 success; >0 no exist */ int kvs_hash_del_bin(kvs_hash_t *hash, const void *key, uint32_t key_len) { if (!hash || !key || key_len == 0) return -1; int idx = _hash(key, key_len, MAX_TABLE_SIZE); if (idx < 0) return -1; hashnode_t *head = hash->nodes[idx]; if (head == NULL) return 1; // noexist // head node if (_key_equal(head, key, key_len)) { hashnode_t *tmp = head->next; hash->nodes[idx] = tmp; if (head->key) kvs_free(head->key); if (head->value) kvs_free(head->value); kvs_free(head); hash->count --; return 0; } hashnode_t *cur = head; while (cur->next != NULL) { if (_key_equal(cur->next, key, key_len)) break; // search node cur = cur->next; } if (cur->next == NULL) { return 1; } hashnode_t *tmp = cur->next; cur->next = tmp->next; if (tmp->key) kvs_free(tmp->key); if (tmp->value) kvs_free(tmp->value); kvs_free(tmp); hash->count --; return 0; } /* * @return =0 exist, =1 no exist */ int kvs_hash_exist_bin(kvs_hash_t *hash, const void *key, uint32_t key_len) { uint32_t vlen = 0; void *value = kvs_hash_get_bin(hash, key, key_len, &vlen); return value ? 0 : 1; } // 0 suc, <0 error int kvs_hash_save(iouring_ctx_t *uring, kvs_hash_t *inst, const char* filename){ if(!inst || !filename) return -1; int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0644); if(fd < 0) return -2; off_t current_off = 0; for(int i = 0;i < inst->max_slots; ++ i){ for (hashnode_t *n = inst->nodes[i]; n != NULL; n = n->next) { if (!n->key || n->key_len == 0) continue; if (n->value_len > 0 && !n->value) { goto clean; } uint32_t klen = htonl((uint32_t)n->key_len); uint32_t vlen = htonl((uint32_t)n->value_len); void *bufs[4]; size_t lens[4]; int count = 0; bufs[count] = &klen; lens[count] = sizeof(klen); count++; bufs[count] = &vlen; lens[count] = sizeof(vlen); count++; if (n->key_len > 0){ bufs[count] = n->key; lens[count] = n->key_len; count++; } if (n->value_len > 0) { bufs[count] = n->value; lens[count] = n->value_len; count++; } size_t total = 0; for (int i = 0; i < count; i++) total += lens[i]; task_t *t = submit_write(uring, fd, bufs, lens, count, current_off); if(!t) { perror("task init failed"); goto clean; } cleanup_finished_iouring_tasks(); current_off += (off_t) total; } } clean: while (!uring_task_complete(uring)) { usleep(1000); cleanup_finished_iouring_tasks(); } close(fd); return 0; } int kvs_hash_load(kvs_hash_t *inst, const char* filename){ if (!inst || !filename) return -1; if (!inst->nodes || inst->max_slots <= 0) return -1; FILE *fp = fopen(filename, "rb"); if (!fp) return -2; while(1){ uint32_t klen_n = 0, vlen_n = 0; if (kvs_read_file(fp, &klen_n, 4) < 0) { fclose(fp); return -3; } if (kvs_read_file(fp, &vlen_n, 4) < 0) { fclose(fp); return -3; } uint32_t klen = ntohl(klen_n); uint32_t vlen = ntohl(vlen_n); if (klen == 0) { fclose(fp); return -3; } uint8_t *keybuf = (uint8_t*)kvs_malloc((size_t)klen); if (!keybuf) { fclose(fp); return -4; } if (kvs_read_file(fp, keybuf, (size_t)klen) < 0) { kvs_free(keybuf); fclose(fp); return -3; } uint8_t *valbuf = NULL; if (vlen > 0) { valbuf = (uint8_t*)kvs_malloc((size_t)vlen); if (!valbuf) { kvs_free(keybuf); fclose(fp); return -4; } if (kvs_read_file(fp, valbuf, (size_t)vlen) < 0) { kvs_free(valbuf); kvs_free(keybuf); fclose(fp); return -3; } } int rc = kvs_hash_set_bin(inst, keybuf, klen, valbuf, vlen); kvs_free(keybuf); if (vlen > 0) kvs_free(valbuf); if (rc < 0) { // error fclose(fp); return -5; } } fclose(fp); return 0; }