#ifndef LSM_STORE_INTERNAL #define LSM_STORE_INTERNAL #include #include #include "lsm/store.h" #include "lsm/str_internal.h" #include "lsm/trie.h" #define LSM_DB_FILE_NAME "lsm.db" #define LSM_IDX_FILE_NAME "lsm.idx" #define LSM_DATA_FILE_SUFFIX ".data" typedef struct lsm_attr { uint8_t type; lsm_str *str; } lsm_attr; /** * An entry inside an LSM store. * * Each entry consists of the key it's stored behind, zero or more attributes * (metadata) and a data file. */ typedef struct lsm_entry { lsm_str *key; struct { uint64_t bitmap[4]; uint8_t count; lsm_attr *items; } attrs; uint64_t data_len; 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. * * @param ptr where to store newly allocated pointer */ lsm_error lsm_entry_init(lsm_entry **ptr); /** * Deallocate an existing entry * * @param entry pointer to entry */ void lsm_entry_free(lsm_entry *entry); /** * Deallocate an existing lsm_entry object. * * @param entry object to deallocate */ void lsm_entry_free(lsm_entry *entry); typedef struct lsm_entry_wrapper { pthread_rwlock_t lock; lsm_entry *entry; } lsm_entry_wrapper; lsm_error lsm_entry_wrapper_init(lsm_entry_wrapper **ptr); void lsm_entry_wrapper_free(lsm_entry_wrapper *wrapper); typedef enum lsm_entry_handle_state : uint8_t { lsm_entry_handle_state_new = 1 << 0, lsm_entry_handle_state_updated = 1 << 1, lsm_entry_handle_state_removed = 1 << 2, } lsm_entry_handle_state; struct lsm_entry_handle { lsm_entry_wrapper *wrapper; lsm_store *store; // Either read or append, depending on how it was opened FILE *f; // Current position in the file pointer uint64_t pos; // Required to determine in what way the database files need to be synced uint64_t states; }; lsm_error lsm_entry_handle_init(lsm_entry_handle **out); struct lsm_store { lsm_trie *trie; lsm_str *data_path; struct { FILE *f; uint64_t size; pthread_mutex_t lock; } db; struct { FILE *f; uint64_t size; uint64_t block_count; pthread_mutex_t lock; } idx; }; /** * Read in the database and construct the in-memory trie index. This function * assumes the provided store is a newly initialized empty store with the * database files opened. * * @param store store to read */ lsm_error lsm_store_load_db(lsm_store *store); /** * Write a new insert to the database. * * @param handle handle to added entry */ lsm_error lsm_entry_disk_insert(lsm_entry_handle *handle); /** * Remove an entry from the database. * * @param handle handle to the removed entry */ lsm_error lsm_entry_disk_remove(lsm_entry_handle *handle); /** * Update an existing entry already in the store. * * @param handle to updated entry */ lsm_error lsm_entry_disk_update(lsm_entry_handle *handle); /** * Return the length of the path to this entry's data file */ uint64_t lsm_entry_data_path_len(const lsm_entry_handle *handle); /** * Fill in the entry's data file path in the provided buffer. Use * `lsm_entry_data_path_len` to allocate an appropriately-sized buffer */ void lsm_entry_data_path(char *buf, const lsm_entry_handle *handle); /** * Open the entry's data file for reading * * @param handle handle to the entry */ lsm_error lsm_entry_data_open_read(lsm_entry_handle *handle); /** * Open the entry's data file for writing. The file and all subdirectories in * the data dir are created as needed. * * @param handle handle to the entry */ lsm_error lsm_entry_data_open_write(lsm_entry_handle *handle); #endif