~panda-roux/MoonGem

317d9d48619018167a62f71e88aa74b43da10d8b — panda-roux 2 months ago 66f99f0 2.3.1
Adding methods to dump and provide stats for the key/value store
5 files changed, 95 insertions(+), 2 deletions(-)

M README.md
M include/store.h
M src/api.c
M src/script.c
M src/store.c
M README.md => README.md +10 -0
@@ 189,3 189,13 @@ These methods are concerned with handling user-input.
### Key/Value Store

MoonGem implements an in-memory key/value store accessed via the `mg.store` table.  This feature is useful for establishing state that's persistent across multiple requests.

- `#mg.store`
  - Returns the number of stored key/value pairs
- `mg.store.dump([path])`
  - Writes the contents of the data store in a tab-separated format to a file at `path`, or stdout if `path` is ommitted
- `mg.store.get_info()`
  - Returns a table with the following fields:
    - `length`: The number of stored key/value pairs
    - `capacity`: The total number of slots allocated
    - `data_size`: The combined length of all of the stored values, in bytes

M include/store.h => include/store.h +1 -0
@@ 9,6 9,7 @@

typedef struct cell_t {
  uint64_t key;
  size_t length;
  char* data;
  bool deleted;
} cell_t;

M src/api.c => src/api.c +69 -0
@@ 1,5 1,6 @@
#include <lauxlib.h>
#include <lua.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>


@@ 23,6 24,10 @@
#define FLD_CERT_FINGERPRINT "fingerprint"
#define FLD_CERT_EXPIRATION "not_after"

#define FLD_STORE_LENGTH "length"
#define FLD_STORE_CAPACITY "capacity"
#define FLD_STORE_DATA_SIZE "data_size"

static void set_interrupt_response(response_t* response, int status,
                                   const char* meta) {
  response->interrupted = true;


@@ 571,3 576,67 @@ int api_get_store_value(lua_State* L) {

  return 1;
}

int api_dump_store(lua_State* L) {
  lua_settop(L, 1);

  const char* path = lua_tostring(L, 1);

  lua_getfield(L, LUA_REGISTRYINDEX, FLD_STORE);
  store_t* store = lua_touserdata(L, -1);

  FILE* out = path == NULL ? stdout : fopen(path, "w");
  if (out == NULL) {
    luaL_error(L, "Failed to open output stream");
  } else {
    fprintf(out, "position\tkey\tlength\tdata\n");
    for (size_t i = 0; i < store->cell_count; i++) {
      cell_t* cell = &store->cells[i];
      if (cell->key == 0 || cell->deleted) {
        continue;
      }

      fprintf(out, "%zu\t%zu\t%zu\t%s\n", i, cell->key, cell->length,
              cell->data);
    }
  }

  return 0;
}

int api_get_store_length(lua_State* L) {
  lua_getfield(L, LUA_REGISTRYINDEX, FLD_STORE);
  store_t* store = lua_touserdata(L, -1);

  lua_pushinteger(L, store->stored_count);

  return 1;
}

int api_get_store_info(lua_State* L) {
  lua_newtable(L);

  lua_getfield(L, LUA_REGISTRYINDEX, FLD_STORE);
  store_t* store = lua_touserdata(L, -1);

  lua_pushinteger(L, store->stored_count);
  lua_setfield(L, -2, FLD_STORE_LENGTH);

  lua_pushinteger(L, store->cell_count);
  lua_setfield(L, -2, FLD_STORE_CAPACITY);

  size_t total_length = 0;
  for (size_t i = 0; i < store->cell_count; i++) {
    cell_t* cell = &store->cells[i];
    if (cell->key == 0 || cell->deleted) {
      continue;
    }

    total_length += cell->length;
  }

  lua_pushinteger(L, total_length);
  lua_setfield(L, -2, FLD_STORE_DATA_SIZE);

  return 1;
}

M src/script.c => src/script.c +11 -1
@@ 59,6 59,9 @@

#define TBL_STORE "store"

#define FUNC_DUMP "dump"
#define FUNC_INFO "get_info"

#define SCRIPT_BUFFER_SIZE (1 << 16)

static char global_script_buffer[SCRIPT_BUFFER_SIZE];


@@ 119,6 122,9 @@ int api_endblock(lua_State* L);
/* Key/Value Store */
int api_set_store_value(lua_State* L);
int api_get_store_value(lua_State* L);
int api_dump_store(lua_State* L);
int api_get_store_length(lua_State* L);
int api_get_store_info(lua_State* L);

static void set_api_methods(lua_State* L) {
  luaL_Reg methods[] = {{FUNC_SET_PATH, api_set_path},


@@ 167,9 173,13 @@ static void set_api_methods(lua_State* L) {
  luaL_newlib(L, methods);

  // set up a table for the key/value store
  lua_newtable(L);
  luaL_Reg store_methods[] = {{FUNC_DUMP, api_dump_store},
                              {FUNC_INFO, api_get_store_info},
                              {NULL, NULL}};
  luaL_newlib(L, store_methods);
  luaL_Reg store_metamethods[] = {{"__index", api_get_store_value},
                                  {"__newindex", api_set_store_value},
                                  {"__len", api_get_store_length},
                                  {NULL, NULL}};
  luaL_newlib(L, store_metamethods);
  lua_setmetatable(L, -2);

M src/store.c => src/store.c +4 -1
@@ 66,6 66,7 @@ static void insert_by_keyhash(store_t* store, uint64_t key, char* data) {

  cell->key = key;
  cell->data = data;
  cell->length = strlen(data);
  cell->deleted = false;
}



@@ 133,12 134,14 @@ bool delete_from_store(store_t* store, char* key) {
    return false;
  }

  target->deleted = true;
  if (target->data != NULL) {
    free(target->data);
    target->data = NULL;
  }

  target->deleted = true;
  target->length = 0;

  --(store->stored_count);

  return true;