diff --git a/CHANGELOG.md b/CHANGELOG.md index 11ae703..388f188 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * LSM * Binary tree iterators * Trie iterators + * Store iterators ## [0.2.0](https://git.rustybever.be/Chewing_Bever/lander/src/tag/0.2.0) diff --git a/lsm/include/lsm/store.h b/lsm/include/lsm/store.h index c680c43..1b632b9 100644 --- a/lsm/include/lsm/store.h +++ b/lsm/include/lsm/store.h @@ -228,4 +228,40 @@ lsm_error lsm_entry_data_read(uint64_t *out, char *buf, */ uint64_t lsm_entry_data_len(lsm_entry_handle *handle); +/** + * Represents an in-flight iterator over an LSM store. + */ +typedef struct lsm_store_iterator lsm_store_iterator; + +/** + * Initialize an iterator to iterate over all entries with keys starting + * with the given prefix. + * + * @param out pointer to store iterator pointer in + * @param trie trie to iterate + * @param prefix prefix of the keys; a zero-length string means iterating over + * the entire trie; NULL is interpreted as a zero-length string + */ +lsm_error lsm_store_iter(lsm_store_iterator **out, lsm_store *store, + const lsm_str *prefix); + +/** + * Advance the iterator, returning a read handle to the next entry. The caller + * is responsible for closing this handle. + */ +lsm_error lsm_store_iter_next_read(lsm_entry_handle **out, + lsm_store_iterator *iter); + +/** + * Advance the iterator, returning a write handle to the next entry. The caller + * is responsible for closing this handle. + */ +/* lsm_error lsm_store_iter_next_write(lsm_entry_handle **out, + * lsm_store_iterator *iter); */ + +/** + * Free the given iterator. + */ +void lsm_store_iter_free(lsm_store_iterator *iter); + #endif diff --git a/lsm/src/_include/lsm/store_internal.h b/lsm/src/_include/lsm/store_internal.h index e446a0d..e853308 100644 --- a/lsm/src/_include/lsm/store_internal.h +++ b/lsm/src/_include/lsm/store_internal.h @@ -34,6 +34,11 @@ typedef struct lsm_entry { uint64_t idx_file_offset; } lsm_entry; +struct lsm_store_iterator { + lsm_trie_iterator *iter; + lsm_store *store; +}; + /** * Allocate and initialize a new lsm_entry object. * diff --git a/lsm/src/store/lsm_store_iter.c b/lsm/src/store/lsm_store_iter.c new file mode 100644 index 0000000..3879d5e --- /dev/null +++ b/lsm/src/store/lsm_store_iter.c @@ -0,0 +1,58 @@ +#include "lsm/store.h" +#include "lsm/store_internal.h" + +lsm_error lsm_store_iter(lsm_store_iterator **out, lsm_store *store, + const lsm_str *prefix) { + lsm_trie_iterator *trie_iter; + LSM_RES(lsm_trie_iter(&trie_iter, store->trie, prefix)); + + lsm_store_iterator *iter = calloc(1, sizeof(lsm_store_iterator)); + + if (iter == NULL) { + lsm_trie_iter_free(trie_iter); + + return lsm_error_failed_alloc; + } + + iter->iter = trie_iter; + iter->store = store; + + *out = iter; + + return lsm_error_ok; +} + +lsm_error lsm_store_iter_next_read(lsm_entry_handle **out, + lsm_store_iterator *iter) { + lsm_entry_wrapper *wrapper = NULL; + + // Traverse through the trie until a node is found with a filled data field + do { + // Exits function if iterator is done + LSM_RES(lsm_trie_iter_next((void **)&wrapper, iter->iter)); + + // TODO error handling? + pthread_rwlock_rdlock(&wrapper->lock); + + if (wrapper->entry == NULL) { + pthread_rwlock_unlock(&wrapper->lock); + + wrapper = NULL; + } + } while (wrapper == NULL); + + lsm_entry_handle *handle; + LSM_RES2(lsm_entry_handle_init(&handle), + pthread_rwlock_unlock(&wrapper->lock)); + + handle->wrapper = wrapper; + handle->store = iter->store; + *out = handle; + + return lsm_error_ok; +} + +void lsm_store_iter_free(lsm_store_iterator *iter) { + lsm_trie_iter_free(iter->iter); + free(iter); +}