为hash表添加锁

sledge_graph
hwwang 4 months ago
parent 0b1fb6c5d7
commit 702f5de60d

@ -105,7 +105,9 @@
"hashmap.h": "c", "hashmap.h": "c",
"mutex": "cpp", "mutex": "cpp",
"xmalloc.h": "c", "xmalloc.h": "c",
"stddef.h": "c" "stddef.h": "c",
"__mutex_base": "c",
"memory": "c"
}, },
"files.exclude": { "files.exclude": {
"**/.git": true, "**/.git": true,

@ -0,0 +1 @@
10

@ -0,0 +1,46 @@
Summary:
Total: 12.2647 secs
Slowest: 3.3362 secs
Fastest: 0.5028 secs
Average: 2.1634 secs
Requests/sec: 49.5730
Total data: 27968 bytes
Size/request: 46 bytes
Response time histogram:
0.503 [1] |
0.786 [16] |■■■■
1.069 [17] |■■■■
1.353 [17] |■■■■
1.636 [19] |■■■■
1.919 [112] |■■■■■■■■■■■■■■■■■■■■■■■■■
2.203 [176] |■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
2.486 [121] |■■■■■■■■■■■■■■■■■■■■■■■■■■■■
2.769 [22] |■■■■■
3.053 [27] |■■■■■■
3.336 [80] |■■■■■■■■■■■■■■■■■■
Latency distribution:
10% in 1.5052 secs
25% in 1.8882 secs
50% in 2.1174 secs
75% in 2.3524 secs
90% in 3.1907 secs
95% in 3.2670 secs
99% in 3.3261 secs
Details (average, fastest, slowest):
DNS+dialup: 0.0150 secs, 0.5028 secs, 3.3362 secs
DNS-lookup: 0.0000 secs, 0.0000 secs, 0.0000 secs
req write: 0.0057 secs, 0.0000 secs, 0.1496 secs
resp wait: 2.1384 secs, 0.3501 secs, 3.3357 secs
resp read: 0.0002 secs, 0.0000 secs, 0.0169 secs
Status code distribution:
[200] 608 responses

@ -0,0 +1,46 @@
Summary:
Total: 11.2523 secs
Slowest: 2.9288 secs
Fastest: 0.0329 secs
Average: 1.2459 secs
Requests/sec: 90.8258
Total data: 47012 bytes
Size/request: 46 bytes
Response time histogram:
0.033 [1] |
0.322 [18] |■
0.612 [23] |■
0.902 [26] |■
1.191 [127] |■■■■■■■
1.481 [740] |■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
1.770 [59] |■■■
2.060 [17] |■
2.350 [8] |
2.639 [1] |
2.929 [2] |
Latency distribution:
10% in 1.1377 secs
25% in 1.2114 secs
50% in 1.2531 secs
75% in 1.3035 secs
90% in 1.4574 secs
95% in 1.5758 secs
99% in 2.0799 secs
Details (average, fastest, slowest):
DNS+dialup: 0.0004 secs, 0.0329 secs, 2.9288 secs
DNS-lookup: 0.0000 secs, 0.0000 secs, 0.0000 secs
req write: 0.0001 secs, 0.0000 secs, 0.0179 secs
resp wait: 1.2442 secs, 0.0245 secs, 2.9283 secs
resp read: 0.0001 secs, 0.0000 secs, 0.0005 secs
Status code distribution:
[200] 1022 responses

@ -4,10 +4,18 @@
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
#include <pthread.h>
#include "lock.h"
//#include "lock.h"
#include "xmalloc.h" #include "xmalloc.h"
typedef pthread_mutex_t mutex_lock_t;
#define LOCK_INIT_MX(lock) pthread_mutex_init(lock, NULL)
#define LOCK_LOCK_MX(lock) pthread_mutex_lock(lock)
#define LOCK_UNLOCK_MX(lock) pthread_mutex_unlock(lock)
/* Simple K-V store based on The Practice of Programming by Kernighan and Pike */ /* Simple K-V store based on The Practice of Programming by Kernighan and Pike */
/* Bucket count is sized to be a prime that is approximately 20% larger than the desired capacity (6k keys) */ /* Bucket count is sized to be a prime that is approximately 20% larger than the desired capacity (6k keys) */
@ -25,7 +33,7 @@ struct map_node {
}; };
struct map_bucket { struct map_bucket {
lock_t lock; mutex_lock_t lock;
struct map_node *head; struct map_node *head;
}; };
@ -38,7 +46,7 @@ map_init(struct hashmap *restrict map)
{ {
for (int i = 0; i < MAP_BUCKET_COUNT; i++) { for (int i = 0; i < MAP_BUCKET_COUNT; i++) {
map->buckets[i].head = NULL; map->buckets[i].head = NULL;
LOCK_INIT(&map->buckets[i].lock); LOCK_INIT_MX(&map->buckets[i].lock);
} }
} }
@ -68,9 +76,10 @@ map_get(struct hashmap *map, char *key, uint32_t key_len, uint32_t *ret_value_le
struct map_bucket *bucket = &map->buckets[hash % MAP_BUCKET_COUNT]; struct map_bucket *bucket = &map->buckets[hash % MAP_BUCKET_COUNT];
LOCK_LOCK(&bucket->lock); LOCK_LOCK_MX(&bucket->lock);
for (struct map_node *node = bucket->head; node != NULL; node = node->next) { for (struct map_node *node = bucket->head; node != NULL; node = node->next) {
if (node->hash == hash) { if (node->hash == hash && memcmp(node->key, key, key_len) == 0) {
value = node->value; value = node->value;
*ret_value_len = node->value_len; *ret_value_len = node->value_len;
goto DONE; goto DONE;
@ -80,10 +89,13 @@ map_get(struct hashmap *map, char *key, uint32_t key_len, uint32_t *ret_value_le
if (value == NULL) *ret_value_len = 0; if (value == NULL) *ret_value_len = 0;
DONE: DONE:
LOCK_UNLOCK(&bucket->lock); LOCK_UNLOCK_MX(&bucket->lock);
return value; return value;
} }
/**
* @manage_mvalue manage _ mvalue determines whether the hash table or the caller manages value memory, and true is managed by the hash.
*/
static inline bool static inline bool
map_set(struct hashmap *map, char *key, uint32_t key_len, void *value, uint32_t value_len, bool manage_mvalue) map_set(struct hashmap *map, char *key, uint32_t key_len, void *value, uint32_t value_len, bool manage_mvalue)
{ {
@ -92,10 +104,10 @@ map_set(struct hashmap *map, char *key, uint32_t key_len, void *value, uint32_t
uint32_t hash = MAP_HASH(key, key_len); uint32_t hash = MAP_HASH(key, key_len);
struct map_bucket *bucket = &map->buckets[hash % MAP_BUCKET_COUNT]; struct map_bucket *bucket = &map->buckets[hash % MAP_BUCKET_COUNT];
LOCK_LOCK(&bucket->lock); LOCK_LOCK_MX(&bucket->lock);
for (struct map_node *node = bucket->head; node != NULL; node = node->next) { for (struct map_node *node = bucket->head; node != NULL; node = node->next) {
if (node->hash == hash) goto DONE; if (node->hash == hash && memcmp(node->key, key, key_len) == 0) goto DONE;
} }
struct map_node *new_node = (struct map_node *)xmalloc(sizeof(struct map_node)); struct map_node *new_node = (struct map_node *)xmalloc(sizeof(struct map_node));
@ -118,7 +130,7 @@ map_set(struct hashmap *map, char *key, uint32_t key_len, void *value, uint32_t
did_set = true; did_set = true;
DONE: DONE:
LOCK_UNLOCK(&bucket->lock); LOCK_UNLOCK_MX(&bucket->lock);
return did_set; return did_set;
} }
@ -132,33 +144,30 @@ map_delete(struct hashmap *map, char *key, uint32_t key_len)
uint32_t hash = MAP_HASH(key, key_len); uint32_t hash = MAP_HASH(key, key_len);
struct map_bucket *bucket = &map->buckets[hash % MAP_BUCKET_COUNT]; struct map_bucket *bucket = &map->buckets[hash % MAP_BUCKET_COUNT];
LOCK_LOCK(&bucket->lock); LOCK_LOCK_MX(&bucket->lock);
struct map_node *prev = bucket->head; struct map_node *prev = NULL;
if (prev != NULL && prev->hash == hash) { struct map_node *node = bucket->head;
bucket->head = prev->next; while (node != NULL) {
free(prev->key); if (node->hash == hash && memcmp(node->key, key, key_len) == 0) {
if (prev->manage_mvalue) { if (prev == NULL) {
free(prev->value); bucket->head = node->next;
} else {
prev->next = node->next;
}
free(node->key);
free(node);
if (node->manage_mvalue) {
free(node->value);
}
did_delete = true;
break;
} }
free(prev); prev = node;
did_delete = true; node = node->next;
goto DONE; }
}
for (struct map_node *node = prev->next; node != NULL; prev = node, node = node->next) {
prev->next = node->next;
free(node->key);
if (node->manage_mvalue) {
free(node->value);
}
free(node);
did_delete = true;
goto DONE;
}
DONE: LOCK_UNLOCK_MX(&bucket->lock);
LOCK_UNLOCK(&bucket->lock);
return did_delete; return did_delete;
} }
@ -167,23 +176,22 @@ map_upsert(struct hashmap *map, char *key, uint32_t key_len, void *value, uint32
{ {
uint32_t hash = MAP_HASH(key, key_len); uint32_t hash = MAP_HASH(key, key_len);
struct map_bucket *bucket = &map->buckets[hash % MAP_BUCKET_COUNT]; struct map_bucket *bucket = &map->buckets[hash % MAP_BUCKET_COUNT];
LOCK_LOCK(&bucket->lock); LOCK_LOCK_MX(&bucket->lock);
for (struct map_node *node = bucket->head; node != NULL; node = node->next) { for (struct map_node *node = bucket->head; node != NULL; node = node->next) {
if (node->hash == hash) { if (node->hash == hash && memcmp(node->key, key, key_len) == 0) {
node->value_len = value_len; node->value_len = value_len;
node->value = realloc(node->value, value_len); node->value = realloc(node->value, value_len);
//node->value = value;
assert(node->value); assert(node->value);
if (node->manage_mvalue) if (node->manage_mvalue)
{ {
memcpy(node->value, value, value_len); memcpy(node->value, value, value_len);
} }else node->value = value;
goto DONE; goto DONE;
} }
} }
panic("map_upsert: key not found");
struct map_node *new_node = (struct map_node *)xmalloc(sizeof(struct map_node)); /*struct map_node *new_node = (struct map_node *)xmalloc(sizeof(struct map_node));
*(new_node) = (struct map_node){ .hash = hash, *(new_node) = (struct map_node){ .hash = hash,
.key = xmalloc(key_len), .key = xmalloc(key_len),
@ -199,8 +207,37 @@ map_upsert(struct hashmap *map, char *key, uint32_t key_len, void *value, uint32
memcpy(new_node->key, key, key_len); memcpy(new_node->key, key, key_len);
memcpy(new_node->value, value, value_len); memcpy(new_node->value, value, value_len);
bucket->head = new_node; bucket->head = new_node;*/
DONE: DONE:
LOCK_UNLOCK(&bucket->lock); LOCK_UNLOCK_MX(&bucket->lock);
} }
/*static inline void
map_destroy(struct hashmap *map) {
for (int i = 0; i < MAP_BUCKET_COUNT; i++) {
LOCK_LOCK_MX(&map->buckets[i].lock);
struct map_node *current = map->buckets[i].head;
struct map_node *next;
while (current != NULL) {
next = current->next;
free(current->key);
if (current->manage_mvalue && current->value != NULL) {
free(current->value);
}
free(current);
current = next;
}
LOCK_UNLOCK_MX(&map->buckets[i].lock);
pthread_mutex_destroy(&map->buckets[i].lock);
// 确保头指针设置为 NULL
map->buckets[i].head = NULL;
}
// 如果 hashmap 是动态分配的,这里还需要释放 hashmap 结构本身
// free(map);
}*/

@ -3,12 +3,12 @@
#include <stdlib.h> #include <stdlib.h>
#include "likely.h" #include "likely.h"
//#include "panic.h" #include "panic.h"
static inline void * static inline void *
xmalloc(size_t size) xmalloc(size_t size)
{ {
void *allocation = malloc(size); void *allocation = malloc(size);
//if (unlikely(allocation == NULL)) panic("xmalloc failed!\n"); if (unlikely(allocation == NULL)) panic("xmalloc failed!\n");
return allocation; return allocation;
} }

@ -12,6 +12,7 @@
#include "hashmap.h" #include "hashmap.h"
extern uint64_t system_start_timestamp; extern uint64_t system_start_timestamp;
pthread_mutex_t lock;
__thread struct sandbox *worker_thread_current_sandbox = NULL; __thread struct sandbox *worker_thread_current_sandbox = NULL;
@ -142,9 +143,9 @@ current_sandbox_start(void)
} else if (next_module != NULL) { } else if (next_module != NULL) {
assert(next_module_idx); assert(next_module_idx);
assert(next_module); assert(next_module);
size_t next_module_pre_count_flag = next_module[0]->pre_module_count; size_t next_module_pre_count = next_module[0]->pre_module_count;
assert(next_module_pre_count_flag); assert(next_module_pre_count);
if (next_module_idx > 1 || (next_module_idx == 1 && next_module_pre_count_flag == 1)) if (next_module_idx > 1 || (next_module_idx == 1 && next_module_pre_count == 1))
{ {
/* Generate a new request, copy the current sandbox's output to the next request's buffer, and put it to the global queue */ /* Generate a new request, copy the current sandbox's output to the next request's buffer, and put it to the global queue */
ssize_t output_length = sandbox->request_response_data_length - sandbox->request_length; ssize_t output_length = sandbox->request_response_data_length - sandbox->request_length;
@ -200,8 +201,10 @@ current_sandbox_start(void)
sandbox_remove_from_epoll(sandbox); sandbox_remove_from_epoll(sandbox);
} }
sandbox_set_as_returned(sandbox, SANDBOX_RUNNING); sandbox_set_as_returned(sandbox, SANDBOX_RUNNING);
}else if (next_module_idx == 1 && next_module_pre_count_flag > 1) }else if (next_module_idx == 1 && next_module_pre_count > 1)
{ {
pthread_mutex_init(&lock, NULL);
pthread_mutex_lock(&lock);
/*Before each id is put into the hash table, the key needs to add a "module handle"*/ /*Before each id is put into the hash table, the key needs to add a "module handle"*/
struct module * next_module_node = next_module[0]; struct module * next_module_node = next_module[0];
assert(next_module_node); assert(next_module_node);
@ -243,6 +246,7 @@ current_sandbox_start(void)
assert(module_pre_count); assert(module_pre_count);
map_set(sandbox_request_id, cur_request_id, strlen(cur_request_id), &module_pre_count, sizeof(uint32_t), true); map_set(sandbox_request_id, cur_request_id, strlen(cur_request_id), &module_pre_count, sizeof(uint32_t), true);
map_set(sandbox_req_map, cur_request_id, strlen(cur_request_id), sandbox_request, sizeof(struct sandbox_request *), false); map_set(sandbox_req_map, cur_request_id, strlen(cur_request_id), sandbox_request, sizeof(struct sandbox_request *), false);
free(cur_request_id);
}else }else
{ {
uint32_t rest_pre_count = *requet_id; uint32_t rest_pre_count = *requet_id;
@ -253,28 +257,34 @@ current_sandbox_start(void)
// Copy data into pre_func_output // Copy data into pre_func_output
ssize_t output_length = sandbox->request_response_data_length - sandbox->request_length; ssize_t output_length = sandbox->request_response_data_length - sandbox->request_length;
char *pre_func_output = (char *)malloc(output_length); char *pre_func_outputi = (char *)malloc(output_length);
if (!pre_func_output) { if (!pre_func_outputi) {
fprintf(stderr, "Failed to allocate memory for the previous output: %s\n", strerror(errno)); fprintf(stderr, "Failed to allocate memory for the previous output: %s\n", strerror(errno));
goto err; goto err;
} }
memcpy(pre_func_output, sandbox->request_response_data + sandbox->request_length, output_length); memcpy(pre_func_outputi, sandbox->request_response_data + sandbox->request_length, output_length);
uint64_t enqueue_timestamp = __getcycles(); uint64_t enqueue_timestamp = __getcycles();
const char *previous_output = sandbox_request->previous_function_output ? sandbox_request->previous_function_output : ""; const char *previous_output = sandbox_request->previous_function_output ? sandbox_request->previous_function_output : "";
ssize_t new_output_length = sandbox_request->output_length + output_length + 2; ssize_t new_output_length = sandbox_request->output_length + output_length + 2;
char *new_output = (char *)malloc(new_output_length); char *new_output = (char *)malloc(new_output_length);
if (!new_output) { if (!new_output) {
fprintf(stderr, "Failed to allocate memory for the new output: %s\n", strerror(errno)); fprintf(stderr, "Failed to allocate memory for the new output: %s\n", strerror(errno));
free(pre_func_output); free(pre_func_outputi);
goto err; goto err;
} }
snprintf(new_output, new_output_length, "%s&%s", previous_output, pre_func_output); memset(new_output, 0, new_output_length);
free(sandbox_request->previous_function_output); snprintf(new_output, new_output_length, "%s&%s", previous_output, pre_func_outputi);
sandbox_request->previous_function_output = NULL; if(sandbox_request->previous_function_output != NULL)
{
free(sandbox_request->previous_function_output);
sandbox_request->previous_function_output = NULL;
}
assert(new_output);
sandbox_request->previous_function_output = new_output; sandbox_request->previous_function_output = new_output;
free(pre_func_output); free(pre_func_outputi);
pre_func_outputi = NULL;
sandbox_request->output_length = new_output_length; sandbox_request->output_length = new_output_length;
rest_pre_count --; rest_pre_count --;
@ -283,21 +293,24 @@ current_sandbox_start(void)
map_upsert(sandbox_request_id, cur_request_id, strlen(cur_request_id), &rest_pre_count, sizeof(uint32_t)); map_upsert(sandbox_request_id, cur_request_id, strlen(cur_request_id), &rest_pre_count, sizeof(uint32_t));
}else }else
{ {
uint64_t enqueue_timestamp = __getcycles();
sandbox_request->enqueue_timestamp = enqueue_timestamp;
global_request_scheduler_add(sandbox_request); global_request_scheduler_add(sandbox_request);
map_delete(sandbox_req_map, cur_request_id, strlen(cur_request_id)); map_delete(sandbox_req_map, cur_request_id, strlen(cur_request_id));
map_delete(sandbox_request_id, cur_request_id, strlen(cur_request_id)); map_delete(sandbox_request_id, cur_request_id, strlen(cur_request_id));
} }
free(cur_request_id);
} }
if (sandbox->request_from_outside) { if (sandbox->request_from_outside) {
sandbox_remove_from_epoll(sandbox); sandbox_remove_from_epoll(sandbox);
} }
sandbox_set_as_returned(sandbox, SANDBOX_RUNNING); sandbox_set_as_returned(sandbox, SANDBOX_RUNNING);
} }else
else
{ {
error_message = "the strcuture of DAG is not supported\n"; error_message = "the strcuture of DAG is not supported\n";
goto err; goto err;
} }
pthread_mutex_unlock(&lock);
} else { } else {
/* Retrieve the result, construct the HTTP response, and send to client */ /* Retrieve the result, construct the HTTP response, and send to client */
if (sandbox_send_response(sandbox) < 0) { if (sandbox_send_response(sandbox) < 0) {

@ -20,7 +20,6 @@
const int JSON_MAX_ELEMENT_COUNT = 16; const int JSON_MAX_ELEMENT_COUNT = 16;
const int JSON_MAX_ELEMENT_SIZE = 1024; const int JSON_MAX_ELEMENT_SIZE = 1024;
const int PRE_MODULE_COUNT = 4; const int PRE_MODULE_COUNT = 4;
struct module **nodes;
/************************* /*************************
* Private Static Inline * * Private Static Inline *
@ -377,9 +376,9 @@ module_new_from_json(char *file_name)
char *request_headers = NULL; char *request_headers = NULL;
char *reponse_headers = NULL; char *reponse_headers = NULL;
//struct module *tail_module = NULL; //struct module *tail_module = NULL;
nodes = malloc(JSON_MAX_ELEMENT_COUNT * sizeof(struct module*)); struct module **nodes = malloc(JSON_MAX_ELEMENT_COUNT * sizeof(struct module*));
if (nodes == NULL) { if (nodes == NULL) {
fprintf(stderr, "Memory allocation failed for nodes array\n"); panic("Memory allocation failed for nodes array\n");
} }
for (int i = 0; i < total_tokens; i++) { for (int i = 0; i < total_tokens; i++) {
assert(tokens[i].type == JSMN_OBJECT); assert(tokens[i].type == JSMN_OBJECT);
@ -625,24 +624,24 @@ module_new_from_json(char *file_name)
free(request_headers); free(request_headers);
free(reponse_headers); free(reponse_headers);
for (int i = 0; i < next_module_count; i++) { for (int i = 0; i < next_module_count; i++) {
free(next_module_names[i]); // 释放每个字符串的内存 free(next_module_names[i]);
} }
free(next_module_names); // 最后释放指针数组的内存 free(next_module_names);
} }
if (module_count == 0) panic("%s contained no active modules\n", file_name); if (module_count == 0) panic("%s contained no active modules\n", file_name);
for (ssize_t i = 0; i < module_count; i++) { for (int i = 0; i < module_count; i++) {
assert(nodes[i]); assert(nodes[i]);
ssize_t count = nodes[i]->next_module_count; uint32_t count = nodes[i]->next_module_count;
if (count == 0) continue; if (count == 0) continue;
nodes[i]->next_module = (struct module**) malloc(count * sizeof(struct module*)); nodes[i]->next_module = (struct module**) malloc(count * sizeof(struct module*));
if (nodes[i]->next_module == NULL) panic("Failed to allocate memory for next_module"); if (nodes[i]->next_module == NULL) panic("Failed to allocate memory for next_module");
for (size_t j = 0; j < count; j++) { for (int j = 0; j < count; j++) {
for (size_t m = i + 1; m < module_count; m++) { for (int m = i + 1; m < module_count; m++) {
if (strcmp(nodes[i]->next_module_names[j], nodes[m]->name) == 0) { if (strncmp(nodes[i]->next_module_names[j], nodes[m]->name, MODULE_MAX_NAME_LENGTH) == 0) {
assert(nodes[m]); assert(nodes[m]);
uint32_t precount = nodes[m]->pre_module_count; uint32_t precount = nodes[m]->pre_module_count;
if (nodes[m]->pre_module == NULL) { if (nodes[m]->pre_module == NULL) {
@ -661,7 +660,7 @@ module_new_from_json(char *file_name)
} }
} }
} }
//free(nodes); free(nodes);
#ifdef LOG_MODULE_LOADING #ifdef LOG_MODULE_LOADING
debuglog("Loaded %d module%s!\n", module_count, module_count > 1 ? "s" : ""); debuglog("Loaded %d module%s!\n", module_count, module_count > 1 ? "s" : "");
#endif #endif

@ -0,0 +1 @@
threadid,id,function,state,deadline,actual,queued,initializing,runnable,running,blocked,returned,memory

@ -26,3 +26,4 @@ C: 01, T: 0x7ffff7bfdd80, F: module_new>
Stack Size: 524288 Stack Size: 524288
C: 01, T: 0x7ffff7bfdd80, F: module_new> C: 01, T: 0x7ffff7bfdd80, F: module_new>
Stack Size: 524288 Stack Size: 524288
double free or corruption (fasttop)

Loading…
Cancel
Save