parent
5b8a585e87
commit
e5b222d83d
@ -1 +1 @@
|
||||
Subproject commit 456edf5cecd7edc36314ba87e2d76ebf8cf1b5db
|
||||
Subproject commit 54de4d27f9a6e1f20b65b7110612a658479e6133
|
@ -0,0 +1,65 @@
|
||||
#include <stdint.h>
|
||||
#include "sledge_abi.h"
|
||||
|
||||
#define INLINE __attribute__((always_inline))
|
||||
|
||||
/**
|
||||
* @param key
|
||||
* @param key_len
|
||||
* @returns value_size at key or 0 if key not present
|
||||
*/
|
||||
INLINE uint32_t
|
||||
scratch_storage_get_size(uint32_t key_offset, uint32_t key_len)
|
||||
{
|
||||
return sledge_abi__scratch_storage_get_size(key_offset, key_len);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param key_offset
|
||||
* @param key_len
|
||||
* @param buf_offset linear memory offset to buffer where value should be copied.
|
||||
* @param buf_len Size of buffer. Assumed to be size returned by sledge_kv_get_value_size.
|
||||
* @returns 0 on success, 1 if key missing, 2 if buffer too small
|
||||
*/
|
||||
INLINE int
|
||||
scratch_storage_get(uint32_t key_offset, uint32_t key_len, uint32_t buf_offset, uint32_t buf_len)
|
||||
{
|
||||
return sledge_abi__scratch_storage_get(key_offset, key_len, buf_offset, buf_len);
|
||||
};
|
||||
|
||||
/**
|
||||
* @param key_offset
|
||||
* @param key_len
|
||||
* @param value_offset
|
||||
* @param value_len
|
||||
* @returns 0 on success, 1 if already present,
|
||||
*/
|
||||
INLINE int
|
||||
scratch_storage_set(uint32_t key_offset, uint32_t key_len, uint32_t value_offset, uint32_t value_len)
|
||||
{
|
||||
return sledge_abi__scratch_storage_set(key_offset, key_len, value_offset, value_len);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param key_offset
|
||||
* @param key_len
|
||||
* @returns 0 on success, 1 if not present
|
||||
*/
|
||||
INLINE int
|
||||
scratch_storage_delete(uint32_t key_offset, uint32_t key_len)
|
||||
{
|
||||
return sledge_abi__scratch_storage_delete(key_offset, key_len);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param key_offset
|
||||
* @param key_len
|
||||
* @param value_offset
|
||||
* @param value_len
|
||||
* @returns 0 on success, 1 if already present,
|
||||
*/
|
||||
INLINE void
|
||||
scratch_storage_upsert(uint32_t key_offset, uint32_t key_len, uint32_t value_offset, uint32_t value_len)
|
||||
{
|
||||
sledge_abi__scratch_storage_upsert(key_offset, key_len, value_offset, value_len);
|
||||
}
|
@ -0,0 +1,183 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "lock.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_LOCK_STRIPES 17
|
||||
|
||||
#define MAP_HASH jenkins_hash
|
||||
|
||||
struct map_node {
|
||||
uint32_t hash;
|
||||
uint8_t *key;
|
||||
uint32_t key_len;
|
||||
uint8_t *value;
|
||||
uint32_t value_len;
|
||||
struct map_node *next;
|
||||
};
|
||||
|
||||
struct map {
|
||||
struct map_node *buckets[MAP_BUCKET_COUNT];
|
||||
lock_t locks[MAP_LOCK_STRIPES];
|
||||
};
|
||||
|
||||
static inline void
|
||||
map_init(struct map *restrict map)
|
||||
{
|
||||
for (int i = 0; i < MAP_BUCKET_COUNT; i++) { map->buckets[i] = NULL; }
|
||||
for (int i = 0; i < MAP_LOCK_STRIPES; i++) { LOCK_INIT(&map->locks[i]); }
|
||||
};
|
||||
|
||||
/* See https://en.wikipedia.org/wiki/Jenkins_hash_function */
|
||||
static inline uint32_t
|
||||
jenkins_hash(uint8_t *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 uint8_t *
|
||||
map_get(struct map *map, uint8_t *key, uint32_t key_len, uint32_t *ret_value_len)
|
||||
{
|
||||
uint8_t *value = NULL;
|
||||
|
||||
uint32_t hash = MAP_HASH(key, key_len);
|
||||
LOCK_LOCK(&map->locks[hash % MAP_LOCK_STRIPES]);
|
||||
for (struct map_node *node = map->buckets[hash % MAP_BUCKET_COUNT]; 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(&map->locks[hash % MAP_LOCK_STRIPES]);
|
||||
return value;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
map_set(struct map *map, uint8_t *key, uint32_t key_len, uint8_t *value, uint32_t value_len)
|
||||
{
|
||||
bool did_set = false;
|
||||
|
||||
uint32_t hash = MAP_HASH(key, key_len);
|
||||
LOCK_LOCK(&map->locks[hash % MAP_LOCK_STRIPES]);
|
||||
for (struct map_node *node = map->buckets[hash % MAP_BUCKET_COUNT]; node != NULL; node = node->next) {
|
||||
if (node->hash == hash) goto DONE;
|
||||
}
|
||||
|
||||
struct map_node *new_node = (struct map_node *)malloc(sizeof(struct map_node));
|
||||
|
||||
*(new_node) = (struct map_node){ .hash = hash,
|
||||
.key = malloc(key_len),
|
||||
.key_len = key_len,
|
||||
.value = malloc(value_len),
|
||||
.value_len = value_len,
|
||||
.next = map->buckets[hash % MAP_BUCKET_COUNT] };
|
||||
|
||||
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);
|
||||
|
||||
map->buckets[hash % MAP_BUCKET_COUNT] = new_node;
|
||||
did_set = true;
|
||||
|
||||
DONE:
|
||||
LOCK_UNLOCK(&map->locks[hash % MAP_LOCK_STRIPES]);
|
||||
return did_set;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns boolean if node was deleted or not
|
||||
*/
|
||||
static inline bool
|
||||
map_delete(struct map *map, uint8_t *key, uint32_t key_len)
|
||||
{
|
||||
bool did_delete = false;
|
||||
|
||||
uint32_t hash = MAP_HASH(key, key_len);
|
||||
LOCK_LOCK(&map->locks[hash % MAP_LOCK_STRIPES]);
|
||||
|
||||
struct map_node *prev = map->buckets[hash % MAP_BUCKET_COUNT];
|
||||
if (prev->hash == hash) {
|
||||
map->buckets[hash % MAP_BUCKET_COUNT] = 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(&map->locks[hash % MAP_LOCK_STRIPES]);
|
||||
return did_delete;
|
||||
}
|
||||
|
||||
static inline void
|
||||
map_upsert(struct map *map, uint8_t *key, uint32_t key_len, uint8_t *value, uint32_t value_len)
|
||||
{
|
||||
uint32_t hash = MAP_HASH(key, key_len);
|
||||
LOCK_LOCK(&map->locks[hash % MAP_LOCK_STRIPES]);
|
||||
for (struct map_node *node = map->buckets[hash % MAP_BUCKET_COUNT]; node != NULL; node = node->next) {
|
||||
if (node->hash == hash) {
|
||||
node->value_len = value_len;
|
||||
node->value = realloc(&node->value, value_len);
|
||||
assert(node->value);
|
||||
memcpy(&node->value, value, value_len);
|
||||
}
|
||||
goto DONE;
|
||||
}
|
||||
|
||||
struct map_node *new_node = (struct map_node *)malloc(sizeof(struct map_node));
|
||||
|
||||
*(new_node) = (struct map_node){ .hash = hash,
|
||||
.key = malloc(key_len),
|
||||
.key_len = key_len,
|
||||
.value = malloc(value_len),
|
||||
.value_len = value_len,
|
||||
.next = map->buckets[hash % MAP_BUCKET_COUNT] };
|
||||
|
||||
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);
|
||||
|
||||
map->buckets[hash % MAP_BUCKET_COUNT] = new_node;
|
||||
|
||||
DONE:
|
||||
LOCK_UNLOCK(&map->locks[hash % MAP_LOCK_STRIPES]);
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
res
|
||||
perf.data
|
||||
perf.data.old
|
@ -0,0 +1,40 @@
|
||||
RUNTIME_DIR=../../runtime/
|
||||
SLEDGE_BINARY_DIR=${RUNTIME_DIR}/bin
|
||||
SLEDGE_TESTS_DIR=${RUNTIME_DIR}/tests
|
||||
HOSTNAME=localhost
|
||||
|
||||
all: run
|
||||
|
||||
clean:
|
||||
make -C ${RUNTIME_DIR} clean
|
||||
make -C ${SLEDGE_TESTS_DIR} clean
|
||||
rm -f ${SLEDGE_BINARY_DIR}/html.wasm.so
|
||||
|
||||
${SLEDGE_BINARY_DIR}/sledgert:
|
||||
make -C ${RUNTIME_DIR} runtime
|
||||
|
||||
.PHONY: sledgert
|
||||
sledgert: ${SLEDGE_BINARY_DIR}/sledgert
|
||||
|
||||
${SLEDGE_BINARY_DIR}/scratch_storage.wasm.so:
|
||||
make -C ../../applications scratch_storage.install
|
||||
|
||||
.PHONY: scratch_storage_get
|
||||
scratch_storage_get: ${SLEDGE_BINARY_DIR}/scratch_storage_get.wasm.so
|
||||
|
||||
.PHONY: scratch_storage_set
|
||||
scratch_storage_set: ${SLEDGE_BINARY_DIR}/scratch_storage_set.wasm.so
|
||||
|
||||
run: sledgert scratch_storage_get scratch_storage_set
|
||||
LD_LIBRARY_PATH=${SLEDGE_BINARY_DIR} ${SLEDGE_BINARY_DIR}/sledgert spec.json
|
||||
|
||||
debug: sledgert scratch_storage_get scratch_storage_set
|
||||
SLEDGE_DISABLE_PREEMPTION=true SLEDGE_NWORKERS=1 \
|
||||
LD_LIBRARY_PATH=${SLEDGE_BINARY_DIR} gdb ${SLEDGE_BINARY_DIR}/sledgert \
|
||||
--eval-command="handle SIGUSR1 noprint nostop" \
|
||||
--eval-command="handle SIGPIPE noprint nostop" \
|
||||
--eval-command="set pagination off" \
|
||||
--eval-command="run spec.json"
|
||||
|
||||
client:
|
||||
http :1337/scratch_storage
|
@ -0,0 +1,2 @@
|
||||
SLEDGE_SCHEDULER=EDF
|
||||
SLEDGE_DISABLE_PREEMPTION=true
|
@ -0,0 +1,3 @@
|
||||
SLEDGE_SCHEDULER=EDF
|
||||
SLEDGE_DISABLE_PREEMPTION=false
|
||||
SLEDGE_SIGALRM_HANDLER=TRIAGED
|
@ -0,0 +1,2 @@
|
||||
SLEDGE_SCHEDULER=FIFO
|
||||
SLEDGE_DISABLE_PREEMPTION=true
|
@ -0,0 +1,2 @@
|
||||
SLEDGE_SCHEDULER=FIFO
|
||||
SLEDGE_DISABLE_PREEMPTION=false
|
@ -0,0 +1,13 @@
|
||||
#!/bin/bash
|
||||
|
||||
if ! command -v hey > /dev/null; then
|
||||
HEY_URL=https://hey-release.s3.us-east-2.amazonaws.com/hey_linux_amd64
|
||||
wget $HEY_URL -O hey
|
||||
chmod +x hey
|
||||
|
||||
if [[ $(whoami) == "root" ]]; then
|
||||
mv hey /usr/bin/hey
|
||||
else
|
||||
sudo mv hey /usr/bin/hey
|
||||
fi
|
||||
fi
|
@ -0,0 +1,26 @@
|
||||
[
|
||||
{
|
||||
"name": "gwu",
|
||||
"port": 1337,
|
||||
"routes": [
|
||||
{
|
||||
"route": "/set",
|
||||
"path": "scratch_storage_set.wasm.so",
|
||||
"expected-execution-us": 10000000,
|
||||
"admissions-percentile": 70,
|
||||
"relative-deadline-us": 20000000,
|
||||
"http-resp-content-type": "text/plain",
|
||||
"http-resp-size": 1024
|
||||
},
|
||||
{
|
||||
"route": "/get",
|
||||
"path": "scratch_storage_get.wasm.so",
|
||||
"expected-execution-us": 10000000,
|
||||
"admissions-percentile": 70,
|
||||
"relative-deadline-us": 20000000,
|
||||
"http-resp-content-type": "text/plain",
|
||||
"http-resp-size": 1024
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
Loading…
Reference in new issue