From 4492339b522036bb8d053db29a34501109730e51 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Thu, 2 Jan 2025 12:22:34 +1000 Subject: [PATCH] kv: Support garbage collection from userspace Signed-off-by: Alistair Francis --- examples/tests/kv/kv_unit_tests/Makefile | 4 ++- examples/tests/kv/kv_unit_tests/main.c | 45 ++++++++++++++++++++++++ libtock-sync/storage/kv.c | 12 +++++++ libtock-sync/storage/kv.h | 2 ++ libtock/storage/kv.c | 10 ++++++ libtock/storage/kv.h | 1 + libtock/storage/syscalls/kv_syscalls.c | 6 ++++ libtock/storage/syscalls/kv_syscalls.h | 2 ++ 8 files changed, 81 insertions(+), 1 deletion(-) diff --git a/examples/tests/kv/kv_unit_tests/Makefile b/examples/tests/kv/kv_unit_tests/Makefile index 964886043..e56c885d7 100644 --- a/examples/tests/kv/kv_unit_tests/Makefile +++ b/examples/tests/kv/kv_unit_tests/Makefile @@ -6,7 +6,9 @@ TOCK_USERLAND_BASE_DIR = ../../../.. # Which files to compile. C_SRCS := $(wildcard *.c) -ELF2TAB_ARGS += --write_id 17767 --read_ids 17767 --access_ids 17767 +# Magic numbers that have to allign with what the kernel gives this +# application as a short ID. +ELF2TAB_ARGS += --write_id 1153320202 --read_ids 1153320202 --access_ids 1153320202 # Include userland master makefile. Contains rules and flags for actually # building the application. diff --git a/examples/tests/kv/kv_unit_tests/main.c b/examples/tests/kv/kv_unit_tests/main.c index 30eee13c4..7cddd1c74 100644 --- a/examples/tests/kv/kv_unit_tests/main.c +++ b/examples/tests/kv/kv_unit_tests/main.c @@ -394,6 +394,50 @@ static bool test_set_get_32regions_8(void) { return subtest_set_get_region(28, 32); } +static bool test_garbage_collect(void) { + int ret; + char key[] = "kvtestapp"; + strcpy((char*) key_buf, key); + int num_of_keys = 0; + uint32_t value_len = 500; + + printf("Filling up storage with invalid (deleted) keys\r\n"); + + // Fill up the storage + do { + for (uint32_t i = 0; i < value_len; i++) { + value_buf[i] = num_of_keys; + } + + printf("Setting key %d\r\n", num_of_keys); + ret = libtocksync_kv_set(key_buf, strlen(key), value_buf, value_len); + + if (ret == RETURNCODE_SUCCESS) { + num_of_keys++; + } + } while (ret == RETURNCODE_SUCCESS); + + printf("Wrote %d K/V entries to flash, running garbage collection\n", num_of_keys); + + ret = libtocksync_kv_garbage_collect(); + CHECK(ret == RETURNCODE_SUCCESS); + + printf("Garbage collection finished, trying to re-set the keys\r\n"); + + for (int i = 0; i < num_of_keys; i++) { + printf("Setting key %d\r\n", i); + for (uint32_t j = 0; j < value_len; j++) { + value_buf[j] = i; + } + + CHECK(libtocksync_kv_set(key_buf, strlen(key), value_buf, value_len) == RETURNCODE_SUCCESS); + } + + printf("Set all keys\r\n"); + + return true; +} + int main(void) { unit_test_fun tests[] = { TEST(exists), @@ -419,6 +463,7 @@ int main(void) { TEST(set_get_32regions_6), TEST(set_get_32regions_7), TEST(set_get_32regions_8), + TEST(garbage_collect), }; unit_test_runner(tests, sizeof(tests) / sizeof(unit_test_fun), 2000, "org.tockos.unit_test"); return 0; diff --git a/libtock-sync/storage/kv.c b/libtock-sync/storage/kv.c index b459d3ecd..47f773572 100644 --- a/libtock-sync/storage/kv.c +++ b/libtock-sync/storage/kv.c @@ -78,3 +78,15 @@ returncode_t libtocksync_kv_delete(const uint8_t* key_buffer, uint32_t key_len) yield_for(&result.fired); return result.ret; } + +returncode_t libtocksync_kv_garbage_collect(void) { + returncode_t err; + result.fired = false; + + err = libtock_kv_garbage_collect(kv_cb_done); + if (err != RETURNCODE_SUCCESS) return err; + + // Wait for the callback. + yield_for(&result.fired); + return result.ret; +} diff --git a/libtock-sync/storage/kv.h b/libtock-sync/storage/kv.h index 83d6ab907..336a532a8 100644 --- a/libtock-sync/storage/kv.h +++ b/libtock-sync/storage/kv.h @@ -21,6 +21,8 @@ returncode_t libtocksync_kv_update(const uint8_t* key_buffer, uint32_t key_len, returncode_t libtocksync_kv_delete(const uint8_t* key_buffer, uint32_t key_len); +returncode_t libtocksync_kv_garbage_collect(void); + #ifdef __cplusplus } #endif diff --git a/libtock/storage/kv.c b/libtock/storage/kv.c index 4a154add2..e3a794dca 100644 --- a/libtock/storage/kv.c +++ b/libtock/storage/kv.c @@ -81,3 +81,13 @@ returncode_t libtock_kv_delete(const uint8_t* key_buffer, uint32_t key_len, libt err = libtock_kv_command_delete(); return err; } + +returncode_t libtock_kv_garbage_collect(libtock_kv_callback_done cb) { + returncode_t err; + + err = libtock_kv_set_upcall(kv_upcall_done, cb); + if (err != RETURNCODE_SUCCESS) return err; + + err = libtock_kv_command_garbage_collect(); + return err; +} diff --git a/libtock/storage/kv.h b/libtock/storage/kv.h index f243e6d34..4e9e8e9d3 100644 --- a/libtock/storage/kv.h +++ b/libtock/storage/kv.h @@ -33,6 +33,7 @@ returncode_t libtock_kv_update(const uint8_t* key_buffer, uint32_t key_len, cons returncode_t libtock_kv_delete(const uint8_t* key_buffer, uint32_t key_len, libtock_kv_callback_done cb); +returncode_t libtock_kv_garbage_collect(libtock_kv_callback_done cb); #ifdef __cplusplus } diff --git a/libtock/storage/syscalls/kv_syscalls.c b/libtock/storage/syscalls/kv_syscalls.c index 6c4d48667..815d026b1 100644 --- a/libtock/storage/syscalls/kv_syscalls.c +++ b/libtock/storage/syscalls/kv_syscalls.c @@ -11,6 +11,7 @@ #define TOCK_KV_DELETE 3 #define TOCK_KV_ADD 4 #define TOCK_KV_UPDATE 5 +#define TOCK_KV_GARBAGE_COLLECT 6 bool libtock_kv_exists(void) { return driver_exists(DRIVER_NUM_KV); @@ -51,6 +52,11 @@ returncode_t libtock_kv_command_delete(void) { return tock_command_return_novalue_to_returncode(cval); } +returncode_t libtock_kv_command_garbage_collect(void) { + syscall_return_t cval = command(DRIVER_NUM_KV, TOCK_KV_GARBAGE_COLLECT, 0, 0); + return tock_command_return_novalue_to_returncode(cval); +} + returncode_t libtock_kv_command_add(void) { syscall_return_t cval = command(DRIVER_NUM_KV, TOCK_KV_ADD, 0, 0); return tock_command_return_novalue_to_returncode(cval); diff --git a/libtock/storage/syscalls/kv_syscalls.h b/libtock/storage/syscalls/kv_syscalls.h index bb4c076c0..08e751f11 100644 --- a/libtock/storage/syscalls/kv_syscalls.h +++ b/libtock/storage/syscalls/kv_syscalls.h @@ -24,6 +24,8 @@ returncode_t libtock_kv_command_set(void); returncode_t libtock_kv_command_delete(void); +returncode_t libtock_kv_command_garbage_collect(void); + returncode_t libtock_kv_command_add(void); returncode_t libtock_kv_command_update(void);