valkey icon indicating copy to clipboard operation
valkey copied to clipboard

[NEW] Make functions static to better enable valkey as an embeddable library

Open jsommr opened this issue 5 months ago • 0 comments

Valkey can be embedded in an application and started in a different thread using pthread_create. This way, valkey can be bundled in a unikernel with the primary application, providing a fast synchronous api. Paired with valkey's replication, one gets shared state across all instances.

A few changes are needed to make valkey easily embeddable, but not much, and I think a good start would be to mark all the internal functions static, so they don't interfere with application functions.

Another thing would be to add support for custom supervisors, that the application can hook into.

Example program

Compilation steps using Tiny C Compiler (https://repo.or.cz/tinycc.git) (forked version required)

Exclude these files by appending .exclude

deps/hiredis/ssl.c.exclude
deps/hiredis/test.c.exclude
deps/lua/src/lua.c.exclude
deps/lua/src/luac.c.exclude
src/ae_evport.c.exclude
src/ae_kqueue.c.exclude
src/ae_select.c.exclude
src/cli_commands.c.exclude
src/redis-benchmark.c.exclude
src/redis-cli.c.exclude
src/serverassert.c.exclude

hdr_atomic.h

+#include <stdatomic.h>
+
 static inline int64_t hdr_atomic_add_fetch_64(volatile int64_t* field, int64_t value)
 {
-    return __sync_add_and_fetch(field, value);
+    return atomic_fetch_add(field, value);
 }

ae_epoll.c

 #include <sys/epoll.h>
+#include <errno.h>
+#include "ae.h"
+#include "zmalloc.h"
 
 static int aeApiPoll(aeEventLoop *eventLoop, struct timeval *tvp) {
             eventLoop->fired[j].mask = mask;
         }
     } else if (retval == -1 && errno != EINTR) {
-        panic("aeApiPoll: epoll_wait, %s", strerror(errno));
+        //panic("aeApiPoll: epoll_wait, %s", strerror(errno));
+        // TODO!
     }
 
     return numevents;
 }

atomicvar.h

-#if !defined(__ATOMIC_VAR_FORCE_SYNC_MACROS) && defined(__STDC_VERSION__) && \
-    (__STDC_VERSION__ >= 201112L) && !defined(__STDC_NO_ATOMICS__)
+//#if !defined(__ATOMIC_VAR_FORCE_SYNC_MACROS) && defined(__STDC_VERSION__) && \
+//    (__STDC_VERSION__ >= 201112L) && !defined(__STDC_NO_ATOMICS__)
+#if 1

release.c

-#include "release.h"
+//#include "release.h"
 #include "crc64.h"
 
+#define REDIS_GIT_SHA1 "x"
+#define REDIS_GIT_DIRTY "x"
+#define REDIS_BUILD_ID_RAW "x"

server.h

+int startRedis(int argc, char **argv);

server.c

-int main(int argc, char **argv) {
+int startRedis(int argc, char **argv) {

Also remove this line:
-    if (server.set_proc_title) redisSetProcTitle(NULL);

add main.c:

#include <time.h>
#include <sys/time.h>
#include <pthread.h>

#include "valkey/src/server.h"
#include "valkey/deps/hiredis/hiredis.h"

void redis_server(void* p) {
    char *args[] = {"./test", NULL};
    startRedis(1, args);
}

int main(int argc, char **argv) {
    pthread_t id;

    int j = 1;
    pthread_create(&id, NULL, redis_server, &j);
    int* ptr;
    sleep(2);

    redisContext *c = redisConnect("127.0.0.1", 6379);
    if (c == NULL || c->err) {
        if (c) {
            printf("Error: %s\n", c->errstr);
        // handle error
        } else {
            printf("Can't allocate redis context\n");
        }
    }

    redisReply *reply = NULL;
    reply = redisCommand(c, "SET foo bar");
    freeReplyObject(reply);

    reply = redisCommand(c, "GET foo");
    printf("reply=%s\n", reply->str);
    freeReplyObject(reply);

    pthread_join(id, (void**)&ptr);
}

compile:

tcc -g -lm -DHAVE_ATOMIC -I valkey/deps/fpconv valkey/deps/fpconv/*.c -I valkey/deps/hiredis valkey/deps/hiredis/*.c -I valkey/deps/lua/src valkey/deps/lua/src/*.c -I valkey/deps/hdr_histogram -DHDR_MALLOC_INCLUDE=\"hdr_redis_malloc.h\" valkey/deps/hdr_histogram/*.c valkey/src/*.c main.c -o test

jsommr avatar Apr 02 '24 18:04 jsommr