301 lines
7.8 KiB
C
301 lines
7.8 KiB
C
|
||
|
||
#include "kvstore.h"
|
||
#include "kvs_rw_tools.h"
|
||
#include "memory/alloc_dispatch.h"
|
||
#include "diskuring/diskuring.h"
|
||
|
||
// singleton
|
||
|
||
kvs_array_t global_array = {0};
|
||
|
||
int kvs_array_create(kvs_array_t *inst) {
|
||
|
||
if (!inst) return -1;
|
||
if (inst->table) {
|
||
printf("table has alloc\n");
|
||
return -1;
|
||
}
|
||
inst->table = kvs_malloc(KVS_ARRAY_SIZE * sizeof(kvs_array_item_t));
|
||
if (!inst->table) {
|
||
return -1;
|
||
}
|
||
|
||
memset(inst->table, 0, (size_t)KVS_ARRAY_SIZE * sizeof(kvs_array_item_t));
|
||
inst->total = 0;
|
||
|
||
return 0;
|
||
}
|
||
|
||
void kvs_array_destroy(kvs_array_t *inst) {
|
||
|
||
if (!inst) return ;
|
||
|
||
if (inst->table) {
|
||
kvs_free(inst->table);
|
||
}
|
||
|
||
}
|
||
|
||
/**
|
||
* return: ==-2 not exist, == -1 error, >= 0 exist idx
|
||
*/
|
||
int kvs_array_find_index(kvs_array_t *inst, const void *key, uint32_t key_len) {
|
||
if (!inst || !inst->table || !key) return -1;
|
||
for (int i = 0; i < inst->total; i++) {
|
||
kvs_array_item_t *it = &inst->table[i];
|
||
if (!it->key) continue;
|
||
if (it->key_len == key_len && memcmp(it->key, key, key_len) == 0) {
|
||
return i;
|
||
}
|
||
}
|
||
return -2; // not found
|
||
}
|
||
|
||
/*
|
||
* @return: <0 error; 0 success; 1 exist
|
||
*/
|
||
int kvs_array_set_bin(kvs_array_t *inst,
|
||
const void *key, uint32_t key_len,
|
||
const void *value, uint32_t value_len) {
|
||
if (!inst || !inst->table || !key || key_len == 0 || !value) return -1;
|
||
if (inst->total >= KVS_ARRAY_SIZE) return -1;
|
||
|
||
int idx = kvs_array_find_index(inst, key, key_len);
|
||
// -2 not exist
|
||
if (idx >= 0) return 1; // exist
|
||
if (idx == -1) return -1; // error
|
||
|
||
uint8_t *kcopy = (uint8_t *)kvs_malloc(key_len);
|
||
if (!kcopy) return -2;
|
||
memcpy(kcopy, key, key_len);
|
||
|
||
uint8_t *vcopy = NULL;
|
||
if (value_len > 0) {
|
||
vcopy = (uint8_t *)kvs_malloc(value_len);
|
||
if (!vcopy) {
|
||
kvs_free(kcopy);
|
||
return -2;
|
||
}
|
||
memcpy(vcopy, value, value_len);
|
||
} else {
|
||
// 允许空 value(长度0),value 指针置 NULL
|
||
vcopy = NULL;
|
||
}
|
||
|
||
int i = 0;
|
||
for (i = 0;i < inst->total;i ++) {
|
||
if (inst->table[i].key == NULL) {
|
||
|
||
inst->table[i].key = kcopy;
|
||
inst->table[i].key_len = key_len;
|
||
inst->table[i].value = vcopy;
|
||
inst->table[i].value_len = value_len;
|
||
inst->total ++;
|
||
|
||
return 0;
|
||
}
|
||
}
|
||
|
||
if (i == inst->total && i < KVS_ARRAY_SIZE) {
|
||
|
||
inst->table[i].key = kcopy;
|
||
inst->table[i].key_len = key_len;
|
||
inst->table[i].value = vcopy;
|
||
inst->table[i].value_len = value_len;
|
||
inst->total ++;
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
/*
|
||
* @return: NULL notexist, NOTNULL exist。out_value_len 是长度。
|
||
*/
|
||
void *kvs_array_get_bin(kvs_array_t *inst, const void *key, uint32_t key_len, uint32_t *out_value_len) {
|
||
if (out_value_len) *out_value_len = 0;
|
||
if (!inst || !inst->table || !key || key_len == 0) return NULL;
|
||
|
||
int idx = kvs_array_find_index(inst, key, key_len);
|
||
if (idx < 0) return NULL;
|
||
|
||
kvs_array_item_t *it = &inst->table[idx];
|
||
if (out_value_len) *out_value_len = it->value_len;
|
||
return it->value; // 注意:由 store 持有
|
||
}
|
||
|
||
/*
|
||
* @return <0 error; =0 success; >0 no exist
|
||
*/
|
||
int kvs_array_del_bin(kvs_array_t *inst, const void *key, uint32_t key_len) {
|
||
if (!inst || !inst->table || !key || key_len == 0) return -1;
|
||
|
||
int idx = kvs_array_find_index(inst, key, key_len);
|
||
if (idx == -2) return 1; // not exist
|
||
if (idx < 0) return -1;
|
||
|
||
kvs_array_item_t *it = &inst->table[idx];
|
||
if (it->key) kvs_free(it->key);
|
||
if (it->value) kvs_free(it->value);
|
||
|
||
// 用末尾元素填洞,保证 total 连续,避免 “total 只增不减” 问题
|
||
int last = inst->total - 1;
|
||
if (idx != last) {
|
||
inst->table[idx] = inst->table[last];
|
||
}
|
||
|
||
// 清理末尾(已被移动或删除)
|
||
memset(&inst->table[last], 0, sizeof(kvs_array_item_t));
|
||
inst->total--;
|
||
|
||
return 0;
|
||
}
|
||
|
||
/*
|
||
* @return < 0 error; =0 success; >0 no exist
|
||
*/
|
||
int kvs_array_mod_bin(kvs_array_t *inst,
|
||
const void *key, uint32_t key_len,
|
||
const void *value, uint32_t value_len) {
|
||
if (!inst || !inst->table || !key || key_len == 0 || !value) return -1;
|
||
|
||
int idx = kvs_array_find_index(inst, key, key_len);
|
||
if (idx == -2) return 1; // not exist
|
||
if (idx < 0) return -1;
|
||
|
||
kvs_array_item_t *it = &inst->table[idx];
|
||
|
||
uint8_t *vcopy = NULL;
|
||
if (value_len > 0) {
|
||
vcopy = (uint8_t *)kvs_malloc(value_len);
|
||
if (!vcopy) return -2;
|
||
memcpy(vcopy, value, value_len);
|
||
} else {
|
||
vcopy = NULL;
|
||
}
|
||
|
||
if (it->value) kvs_free(it->value);
|
||
it->value = vcopy;
|
||
it->value_len = value_len;
|
||
|
||
return 0;
|
||
}
|
||
|
||
/*
|
||
* @return =0 exist, =1 no exist
|
||
*/
|
||
int kvs_array_exist_bin(kvs_array_t *inst, const void *key, uint32_t key_len) {
|
||
if (!inst || !inst->table || !key || key_len == 0) return -1;
|
||
int idx = kvs_array_find_index(inst, key, key_len);
|
||
return (idx >= 0) ? 0 : 1;
|
||
}
|
||
|
||
// return: 0 success, <0 error
|
||
int kvs_array_save(iouring_ctx_t *uring, kvs_array_t *inst, const char* filename){
|
||
if(!uring || !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->total; ++ i){
|
||
kvs_array_item_t *it = &inst->table[i];
|
||
if(!it->key || it->key_len == 0) continue; // 跳过空槽
|
||
if(it->value_len > 0 && !it->value) { close(fd); return -3; }
|
||
|
||
uint32_t klen = htonl(it->key_len);
|
||
uint32_t vlen = htonl(it->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 (it->key_len > 0){
|
||
bufs[count] = it->key;
|
||
lens[count] = it->key_len;
|
||
count++;
|
||
}
|
||
|
||
if (it->value_len > 0) {
|
||
bufs[count] = it->value;
|
||
lens[count] = it->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) { close(fd); return -4; }
|
||
// int res = task_wait(t);
|
||
// task_destroy(t);
|
||
|
||
// if (res < 0) {
|
||
// close(fd);
|
||
// return -5;
|
||
// }
|
||
|
||
current_off += (off_t) total;
|
||
}
|
||
|
||
close(fd);
|
||
return 0;
|
||
}
|
||
|
||
int kvs_array_load(kvs_array_t *inst, const char* filename) {
|
||
if (!inst || !filename) return -1;
|
||
if (!inst->table) return -1;
|
||
|
||
FILE *fp = fopen(filename, "rb");
|
||
if (!fp) return -2;
|
||
|
||
int idx = 0;
|
||
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; }
|
||
|
||
kvs_array_item_t *it = &inst->table[idx];
|
||
memset(it, 0, sizeof(*it));
|
||
|
||
it->key = (uint8_t *)kvs_malloc(klen);
|
||
if (!it->key) { fclose(fp); return -3; }
|
||
it->key_len = klen;
|
||
if (kvs_read_file(fp, it->key, klen) < 0) { fclose(fp); return -3; }
|
||
|
||
if (vlen > 0) {
|
||
it->value = (uint8_t *)kvs_malloc(vlen);
|
||
if (!it->value) { fclose(fp); return -4; }
|
||
it->value_len = vlen;
|
||
|
||
if (kvs_read_file(fp, it->value, vlen) < 0) { fclose(fp); return -3; }
|
||
} else {
|
||
it->value = NULL;
|
||
it->value_len = 0;
|
||
}
|
||
|
||
inst->total ++;
|
||
idx++;
|
||
if(idx >= KVS_ARRAY_SIZE){ break; }
|
||
}
|
||
|
||
fclose(fp);
|
||
return 0;
|
||
}
|