parent
73da853ad4
commit
70fdbb348c
@ -1,3 +1,3 @@
|
|||||||
LD_LIBRARY_PATH=/home/hai/sledge-serverless-framework/runtime/bin
|
LD_LIBRARY_PATH=/home/hai/sledge-old/runtime/bin
|
||||||
SLEDGE_SCHEDULER=EDF
|
SLEDGE_SCHEDULER=EDF
|
||||||
SLEDGE_SANDBOX_PERF_LOG=/home/hai/sledge-serverless-framework/debuglog.txt
|
SLEDGE_SANDBOX_PERF_LOG=/home/hai/sledge-serverless-framework/debuglog.txt
|
||||||
|
@ -0,0 +1,52 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "hashmap.h"
|
||||||
|
#include "lock.h"
|
||||||
|
#include "xmalloc.h"
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
struct hashmap* map;
|
||||||
|
lock_t lock;
|
||||||
|
}lockhashmap;
|
||||||
|
|
||||||
|
static inline lockhashmap
|
||||||
|
*hashmap_lock_new(
|
||||||
|
size_t elsize, size_t cap, uint64_t seed0,
|
||||||
|
uint64_t seed1,
|
||||||
|
uint64_t (*hash)(const void *item, uint64_t seed0, uint64_t seed1),
|
||||||
|
int (*compare)(const void *a, const void *b, void *udata),
|
||||||
|
void (*elfree)(void *item),
|
||||||
|
void *udata
|
||||||
|
)
|
||||||
|
{
|
||||||
|
lockhashmap* node = (lockhashmap *)xmalloc(sizeof(lockhashmap));
|
||||||
|
node->map = hashmap_new(elsize, cap, seed0, seed1, hash, compare, elfree, udata);
|
||||||
|
LOCK_INIT(&node->lock);
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*void threadsafe_hashmap_free(ThreadSafeHashmap *thm) {
|
||||||
|
if (thm) {
|
||||||
|
spinlock_acquire(&thm->lock);
|
||||||
|
hashmap_free(thm->map);
|
||||||
|
spinlock_release(&thm->lock);
|
||||||
|
spinlock_destroy(&thm->lock);
|
||||||
|
free(thm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool threadsafe_hashmap_set(ThreadSafeHashmap *thm, const void *item) {
|
||||||
|
spinlock_acquire(&thm->lock);
|
||||||
|
const void *result = hashmap_set(thm->map, item);
|
||||||
|
spinlock_release(&thm->lock);
|
||||||
|
return result != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
const void *threadsafe_hashmap_get(ThreadSafeHashmap *thm, const void *item) {
|
||||||
|
spinlock_acquire(&thm->lock);
|
||||||
|
const void *result = hashmap_get(thm->map, item);
|
||||||
|
spinlock_release(&thm->lock);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
*/
|
@ -0,0 +1,193 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "lock.h"
|
||||||
|
#include "xmalloc.h"
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct map_bucket {
|
||||||
|
lock_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(&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_LOCK(&bucket->lock);
|
||||||
|
for (struct map_node *node = bucket->head; node != NULL; node = node->next) {
|
||||||
|
if (node->hash == hash) {
|
||||||
|
value = node->value;
|
||||||
|
*ret_value_len = node->value_len;
|
||||||
|
goto DONE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value == NULL) *ret_value_len = 0;
|
||||||
|
|
||||||
|
DONE:
|
||||||
|
LOCK_UNLOCK(&bucket->lock);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool
|
||||||
|
map_set(struct hashmap *map, char *key, uint32_t key_len, void *value, uint32_t value_len)
|
||||||
|
{
|
||||||
|
bool did_set = false;
|
||||||
|
|
||||||
|
uint32_t hash = MAP_HASH(key, key_len);
|
||||||
|
struct map_bucket *bucket = &map->buckets[hash % MAP_BUCKET_COUNT];
|
||||||
|
LOCK_LOCK(&bucket->lock);
|
||||||
|
for (struct map_node *node = bucket->head; node != NULL; node = node->next) {
|
||||||
|
if (node->hash == hash) 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 = value,
|
||||||
|
.value_len = value_len,
|
||||||
|
.next = bucket->head };
|
||||||
|
|
||||||
|
// Copy Key and Value
|
||||||
|
memcpy(new_node->key, key, key_len);
|
||||||
|
//memcpy(new_node->value, value, value_len);
|
||||||
|
|
||||||
|
bucket->head = new_node;
|
||||||
|
did_set = true;
|
||||||
|
|
||||||
|
DONE:
|
||||||
|
LOCK_UNLOCK(&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_LOCK(&bucket->lock);
|
||||||
|
|
||||||
|
struct map_node *prev = bucket->head;
|
||||||
|
if (prev != NULL && prev->hash == hash) {
|
||||||
|
bucket->head = prev->next;
|
||||||
|
free(prev->key);
|
||||||
|
//free(prev->value);
|
||||||
|
free(prev);
|
||||||
|
did_delete = true;
|
||||||
|
goto DONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (struct map_node *node = prev->next; node != NULL; prev = node, node = node->next) {
|
||||||
|
prev->next = node->next;
|
||||||
|
free(node->key);
|
||||||
|
//free(node->value);
|
||||||
|
free(node);
|
||||||
|
did_delete = true;
|
||||||
|
goto DONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
DONE:
|
||||||
|
LOCK_UNLOCK(&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_LOCK(&bucket->lock);
|
||||||
|
|
||||||
|
for (struct map_node *node = bucket->head; node != NULL; node = node->next) {
|
||||||
|
if (node->hash == hash) {
|
||||||
|
node->value_len = value_len;
|
||||||
|
//node->value = realloc(node->value, value_len);
|
||||||
|
node->value = value;
|
||||||
|
assert(node->value);
|
||||||
|
//memcpy(node->value, value, value_len);
|
||||||
|
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 = 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);
|
||||||
|
new_node->value = value;
|
||||||
|
//memcpy(new_node->value, value, value_len);
|
||||||
|
|
||||||
|
bucket->head = new_node;
|
||||||
|
|
||||||
|
DONE:
|
||||||
|
LOCK_UNLOCK(&bucket->lock);
|
||||||
|
} */
|
@ -0,0 +1,14 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "likely.h"
|
||||||
|
#include "panic.h"
|
||||||
|
|
||||||
|
static inline void *
|
||||||
|
xmalloc(size_t size)
|
||||||
|
{
|
||||||
|
void *allocation = malloc(size);
|
||||||
|
if (unlikely(allocation == NULL)) panic("xmalloc failed!\n");
|
||||||
|
return allocation;
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"active": true,
|
||||||
|
"name": "work",
|
||||||
|
"path": "work_wasm.so",
|
||||||
|
"port": 10000,
|
||||||
|
"relative-deadline-us": 50000,
|
||||||
|
"argsize": 1,
|
||||||
|
"pre_module_count": 0,
|
||||||
|
"next_modules": [],
|
||||||
|
"http-req-headers": [],
|
||||||
|
"http-req-content-type": "text/plain",
|
||||||
|
"http-req-size": 1048776,
|
||||||
|
"http-resp-headers": [],
|
||||||
|
"http-resp-size": 1048776,
|
||||||
|
"http-resp-content-type": "text/plain"
|
||||||
|
}
|
@ -0,0 +1 @@
|
|||||||
|
Subproject commit 1c139923fe08f36143ecc0ba37cd674684f87f9c
|
Binary file not shown.
@ -0,0 +1,77 @@
|
|||||||
|
#include "../include/map.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int id;
|
||||||
|
char name[100];
|
||||||
|
float salary;
|
||||||
|
} Employee;
|
||||||
|
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
// 初始化哈希表
|
||||||
|
struct hashmap myMap;
|
||||||
|
map_init(&myMap);
|
||||||
|
|
||||||
|
// 创建并初始化一些 Employee 结构体
|
||||||
|
Employee *alice = malloc(sizeof(Employee));
|
||||||
|
alice->id = 1;
|
||||||
|
strcpy(alice->name, "Alice");
|
||||||
|
alice->salary = 50000.0;
|
||||||
|
|
||||||
|
Employee *bob = malloc(sizeof(Employee));
|
||||||
|
bob->id = 2;
|
||||||
|
strcpy(bob->name, "Bob");
|
||||||
|
bob->salary = 52000.0;
|
||||||
|
|
||||||
|
// 将 Employee 结构体存入哈希表
|
||||||
|
char *key1 = "employee1";
|
||||||
|
map_set(&myMap, key1, strlen(key1), alice, sizeof(Employee*));
|
||||||
|
|
||||||
|
char *key2 = "employee2";
|
||||||
|
map_set(&myMap, key2, strlen(key2), bob, sizeof(Employee*));
|
||||||
|
|
||||||
|
// 尝试从哈希表中检索 Employee
|
||||||
|
uint32_t ret_value_len;
|
||||||
|
Employee *retrieved_employee = (Employee *)map_get(&myMap, key1, strlen(key1), &ret_value_len);
|
||||||
|
if (retrieved_employee) {
|
||||||
|
printf("Retrieved Employee: %s, ID: %d, Salary: %.2f\n",
|
||||||
|
retrieved_employee->name, retrieved_employee->id, retrieved_employee->salary);
|
||||||
|
} else {
|
||||||
|
printf("Employee not found.\n");
|
||||||
|
}
|
||||||
|
alice->id = 12;
|
||||||
|
char *key3 = "employee1";
|
||||||
|
strcat(alice->name, key3);
|
||||||
|
retrieved_employee = (Employee *)map_get(&myMap, key1, strlen(key1), &ret_value_len);
|
||||||
|
if (retrieved_employee) {
|
||||||
|
printf("Retrieved Employee: %s, ID: %d, Salary: %.2f\n",
|
||||||
|
retrieved_employee->name, retrieved_employee->id, retrieved_employee->salary);
|
||||||
|
} else {
|
||||||
|
printf("Employee not found.\n");
|
||||||
|
}
|
||||||
|
map_delete(&myMap, key1, strlen(key1));
|
||||||
|
retrieved_employee = (Employee *)map_get(&myMap, key1, strlen(key1), &ret_value_len);
|
||||||
|
if (retrieved_employee) {
|
||||||
|
printf("Retrieved Employee: %s, ID: %d, Salary: %.2f\n",
|
||||||
|
retrieved_employee->name, retrieved_employee->id, retrieved_employee->salary);
|
||||||
|
} else {
|
||||||
|
printf("Employee not found.\n");
|
||||||
|
}
|
||||||
|
map_set(&myMap, key1, strlen(key1), alice, sizeof(Employee*));
|
||||||
|
retrieved_employee = (Employee *)map_get(&myMap, key1, strlen(key1), &ret_value_len);
|
||||||
|
if (retrieved_employee) {
|
||||||
|
printf("Retrieved Employee: %s, ID: %d, Salary: %.2f\n",
|
||||||
|
retrieved_employee->name, retrieved_employee->id, retrieved_employee->salary);
|
||||||
|
} else {
|
||||||
|
printf("Employee not found.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 清理
|
||||||
|
free(alice);
|
||||||
|
free(bob);
|
||||||
|
|
||||||
|
// 也许还需要遍历哈希表并释放所有节点,这里假设只是一个简单的示例
|
||||||
|
return 0;
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
Runtime Environment:
|
||||||
|
CPU Speed: 2400 MHz
|
||||||
|
Processor Speed: 2400 MHz
|
||||||
|
RLIMIT_DATA: Infinite
|
||||||
|
RLIMIT_NOFILE: 1048576 (Increased from 8192)
|
||||||
|
Core Count: 8
|
||||||
|
Listener core ID: 1
|
||||||
|
First Worker core ID: 2
|
||||||
|
Worker core count: 6
|
||||||
|
Scheduler Policy: EDF
|
||||||
|
Sigalrm Policy: BROADCAST
|
||||||
|
Preemption: Enabled
|
||||||
|
Quantum: 5000 us
|
||||||
|
Sandbox Performance Log: /home/hai/sledge-serverless-framework/debuglog.txt
|
||||||
|
Starting listener thread
|
||||||
|
Listener core thread: 7ffff7a006c0
|
||||||
|
Starting 6 worker thread(s)
|
||||||
|
C: 01, T: 0x7ffff7bfdd80, F: runtime_start_runtime_worker_threads>
|
||||||
|
Sandboxing environment ready!
|
||||||
|
|
||||||
|
C: 01, T: 0x7ffff7bfdd80, F: module_new>
|
||||||
|
Stack Size: 524288
|
||||||
|
sledgert: src/software_interrupt.c:181: void software_interrupt_handle_signals(int, siginfo_t *, void *): Assertion `TEST_RECORDING_BUFFER_LEN > software_interrupt_SIGALRM_kernel_count + software_interrupt_SIGALRM_thread_count' failed.
|
||||||
|
sledgert: src/software_interrupt.c:181: void software_interrupt_handle_signals(int, siginfo_t *, void *): Assertion `TEST_RECORDING_BUFFER_LEN > software_interrupt_SIGALRM_kernel_count + software_interrupt_SIGALRM_thread_count' failed.
|
Loading…
Reference in new issue