修改hash表和sandbox_request的互斥锁为读写锁,但现在觉得map不加锁可能会有隐患

newsch
hwwang 4 months ago
parent 1854297530
commit 5711145b3b

@ -6,16 +6,8 @@
#include <stdlib.h>
#include <pthread.h>
//#include "lock.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 */
/* Bucket count is sized to be a prime that is approximately 20% larger than the desired capacity (6k keys) */
@ -33,7 +25,6 @@ struct map_node {
};
struct map_bucket {
mutex_lock_t lock;
struct map_node *head;
};
@ -46,7 +37,6 @@ map_init(struct hashmap *restrict map)
{
for (int i = 0; i < MAP_BUCKET_COUNT; i++) {
map->buckets[i].head = NULL;
LOCK_INIT_MX(&map->buckets[i].lock);
}
}
@ -76,7 +66,6 @@ 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];
LOCK_LOCK_MX(&bucket->lock);
for (struct map_node *node = bucket->head; node != NULL; node = node->next) {
if (node->hash == hash && memcmp(node->key, key, key_len) == 0) {
@ -89,7 +78,6 @@ map_get(struct hashmap *map, char *key, uint32_t key_len, uint32_t *ret_value_le
if (value == NULL) *ret_value_len = 0;
DONE:
LOCK_UNLOCK_MX(&bucket->lock);
return value;
}
@ -104,7 +92,6 @@ map_set(struct hashmap *map, char *key, uint32_t key_len, void *value, uint32_t
uint32_t hash = MAP_HASH(key, key_len);
struct map_bucket *bucket = &map->buckets[hash % MAP_BUCKET_COUNT];
LOCK_LOCK_MX(&bucket->lock);
for (struct map_node *node = bucket->head; node != NULL; node = node->next) {
if (node->hash == hash && memcmp(node->key, key, key_len) == 0) goto DONE;
@ -130,7 +117,6 @@ map_set(struct hashmap *map, char *key, uint32_t key_len, void *value, uint32_t
did_set = true;
DONE:
LOCK_UNLOCK_MX(&bucket->lock);
return did_set;
}
@ -144,7 +130,6 @@ map_delete(struct hashmap *map, char *key, uint32_t key_len)
uint32_t hash = MAP_HASH(key, key_len);
struct map_bucket *bucket = &map->buckets[hash % MAP_BUCKET_COUNT];
LOCK_LOCK_MX(&bucket->lock);
struct map_node *prev = NULL;
struct map_node *node = bucket->head;
@ -170,7 +155,6 @@ map_delete(struct hashmap *map, char *key, uint32_t key_len)
node = node->next;
}
LOCK_UNLOCK_MX(&bucket->lock);
return did_delete;
}
@ -179,7 +163,6 @@ map_upsert(struct hashmap *map, char *key, uint32_t key_len, void *value, uint32
{
uint32_t hash = MAP_HASH(key, key_len);
struct map_bucket *bucket = &map->buckets[hash % MAP_BUCKET_COUNT];
LOCK_LOCK_MX(&bucket->lock);
for (struct map_node *node = bucket->head; node != NULL; node = node->next) {
if (node->hash == hash && memcmp(node->key, key, key_len) == 0) {
@ -189,58 +172,9 @@ map_upsert(struct hashmap *map, char *key, uint32_t key_len, void *value, uint32
if (node->manage_mvalue)
{
memcpy(node->value, value, value_len);
}else node->value = value;
goto DONE;
}else node->value = value;
return;
}
}
panic("map_upsert: key not found");
/*struct map_node *new_node = (struct map_node *)xmalloc(sizeof(struct map_node));
*(new_node) = (struct map_node){ .hash = hash,
.key = xmalloc(key_len),
.key_len = key_len,
.value = xmalloc(value_len),
.value_len = value_len,
.next = bucket->head };
assert(new_node->key);
assert(new_node->value);
// Copy Key and Value
memcpy(new_node->key, key, key_len);
memcpy(new_node->value, value, value_len);
bucket->head = new_node;*/
DONE:
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);
}*/

@ -0,0 +1,246 @@
#pragma once
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <pthread.h>
//#include "lock.h"
#include "xmalloc.h"
typedef pthread_rwlock_t rwlock_t;
#define LOCK_INIT_RW(lock) pthread_rwlock_init(lock, NULL)
#define LOCK_RDLOCK_RW(lock) pthread_rwlock_rdlock(lock)
#define LOCK_WRLOCK_RW(lock) pthread_rwlock_wrlock(lock)
#define LOCK_UNLOCK_RW(lock) pthread_rwlock_unlock(lock)
/* 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) */
#define MAP_BUCKET_COUNT 7907
#define MAP_HASH jenkins_hash
struct map_node {
struct map_node *next;
char *key;
void *value;
uint32_t key_len;
uint32_t value_len;
uint32_t hash;
bool manage_mvalue;
};
struct map_bucket {
rwlock_t lock;
struct map_node *head;
};
struct hashmap {
struct map_bucket buckets[MAP_BUCKET_COUNT];
};
static inline void
map_init(struct hashmap *restrict map)
{
for (int i = 0; i < MAP_BUCKET_COUNT; i++) {
map->buckets[i].head = NULL;
LOCK_INIT_RW(&map->buckets[i].lock);
}
}
/* See https://en.wikipedia.org/wiki/Jenkins_hash_function */
static inline uint32_t
jenkins_hash(char *key, uint32_t key_len)
{
uint32_t i = 0;
uint32_t hash = 0;
while (i != key_len) {
hash += key[i++];
hash += hash << 10;
hash ^= hash >> 6;
}
hash += hash << 3;
hash ^= hash >> 11;
hash += hash << 15;
return hash;
}
static inline void *
map_get(struct hashmap *map, char *key, uint32_t key_len, uint32_t *ret_value_len)
{
void *value = NULL;
uint32_t hash = MAP_HASH(key, key_len);
struct map_bucket *bucket = &map->buckets[hash % MAP_BUCKET_COUNT];
LOCK_RDLOCK_RW(&bucket->lock);
for (struct map_node *node = bucket->head; node != NULL; node = node->next) {
if (node->hash == hash && memcmp(node->key, key, key_len) == 0) {
value = node->value;
*ret_value_len = node->value_len;
goto DONE;
}
}
if (value == NULL) *ret_value_len = 0;
DONE:
LOCK_UNLOCK_RW(&bucket->lock);
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
map_set(struct hashmap *map, char *key, uint32_t key_len, void *value, uint32_t value_len, bool manage_mvalue)
{
bool did_set = false;
uint32_t hash = MAP_HASH(key, key_len);
struct map_bucket *bucket = &map->buckets[hash % MAP_BUCKET_COUNT];
LOCK_WRLOCK_RW(&bucket->lock);
for (struct map_node *node = bucket->head; node != NULL; node = node->next) {
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));
*(new_node) = (struct map_node){ .hash = hash,
.key = xmalloc(key_len),
.key_len = key_len,
.value_len = value_len,
.next = bucket->head };
// Copy Key and Value
memcpy(new_node->key, key, key_len);
if (manage_mvalue) {
new_node->value = xmalloc(value_len);
memcpy(new_node->value, value, value_len);
} else {
new_node->value = value;
}
new_node->manage_mvalue = manage_mvalue;
bucket->head = new_node;
did_set = true;
DONE:
LOCK_UNLOCK_RW(&bucket->lock);
return did_set;
}
/**
* @returns boolean if node was deleted or not
*/
static inline bool
map_delete(struct hashmap *map, char *key, uint32_t key_len)
{
bool did_delete = false;
uint32_t hash = MAP_HASH(key, key_len);
struct map_bucket *bucket = &map->buckets[hash % MAP_BUCKET_COUNT];
LOCK_WRLOCK_RW(&bucket->lock);
struct map_node *prev = NULL;
struct map_node *node = bucket->head;
while (node != NULL) {
if (node->hash == hash && memcmp(node->key, key, key_len) == 0) {
if (prev == NULL) {
bucket->head = node->next;
} else {
prev->next = node->next;
}
free(node->key);
node->key = NULL;
if (node->manage_mvalue) {
free(node->value);
node->value = NULL;
}
free(node);
node = NULL;
did_delete = true;
break;
}
prev = node;
node = node->next;
}
LOCK_UNLOCK_RW(&bucket->lock);
return did_delete;
}
static inline void
map_upsert(struct hashmap *map, char *key, uint32_t key_len, void *value, uint32_t value_len)
{
uint32_t hash = MAP_HASH(key, key_len);
struct map_bucket *bucket = &map->buckets[hash % MAP_BUCKET_COUNT];
LOCK_WRLOCK_RW(&bucket->lock);
for (struct map_node *node = bucket->head; node != NULL; node = node->next) {
if (node->hash == hash && memcmp(node->key, key, key_len) == 0) {
node->value_len = value_len;
node->value = realloc(node->value, value_len);
assert(node->value);
if (node->manage_mvalue)
{
memcpy(node->value, value, value_len);
}else node->value = value;
goto DONE;
}
}
panic("map_upsert: key not found");
/*struct map_node *new_node = (struct map_node *)xmalloc(sizeof(struct map_node));
*(new_node) = (struct map_node){ .hash = hash,
.key = xmalloc(key_len),
.key_len = key_len,
.value = xmalloc(value_len),
.value_len = value_len,
.next = bucket->head };
assert(new_node->key);
assert(new_node->value);
// Copy Key and Value
memcpy(new_node->key, key, key_len);
memcpy(new_node->value, value, value_len);
bucket->head = new_node;*/
DONE:
LOCK_UNLOCK_RW(&bucket->lock);
}
/*static inline void
map_destroy(struct hashmap *map) {
for (int i = 0; i < MAP_BUCKET_COUNT; i++) {
LOCK_LOCK_RW(&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_RW(&map->buckets[i].lock);
pthread_mutex_destroy(&map->buckets[i].lock);
// 确保头指针设置为 NULL
map->buckets[i].head = NULL;
}
// 如果 hashmap 是动态分配的,这里还需要释放 hashmap 结构本身
// free(map);
}*/

@ -194,14 +194,14 @@ concatenate_outputs(struct sandbox_request *request) {
current = request->pre_functions_output;
while (current != NULL) {
size_t copy_length = current->output_length;
if (current->next) {
size_t copy_length = current->output_length;
if (current->next) {
memcpy(copy_dest, current->previous_function_output, copy_length - 1);
copy_dest[copy_length - 1] = '&';
copy_dest += copy_length;
} else {
memcpy(copy_dest, current->previous_function_output, copy_length);
copy_dest += copy_length;
break;
}
current = current->next;
}
@ -209,6 +209,7 @@ concatenate_outputs(struct sandbox_request *request) {
if (request->previous_function_output != NULL) {
free(request->previous_function_output);
request->previous_function_output = NULL;
}
request->output_length = total_length;
request->previous_function_output = concatenated_output;

@ -259,8 +259,8 @@ current_sandbox_start(void)
uint32_t module_pre_count = next_module_pre_count;
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_req_map, cur_request_id, strlen(cur_request_id), sandbox_request, sizeof(struct sandbox_request *), false);
if(!map_set(sandbox_request_id, cur_request_id, strlen(cur_request_id), &module_pre_count, sizeof(uint32_t), true)) panic("the map of sandbox_request_id is NULL\n");
if(!map_set(sandbox_req_map, cur_request_id, strlen(cur_request_id), sandbox_request, sizeof(struct sandbox_request *), false)) panic("the map of sandbox_request is NULL\n");
mapflag = true;
}
LOCK_UNLOCK(&lock);

File diff suppressed because one or more lines are too long
Loading…
Cancel
Save