diff --git a/include/lander.h b/include/lander.h index 7b418bc..9ebbdf2 100644 --- a/include/lander.h +++ b/include/lander.h @@ -51,6 +51,8 @@ lnm_http_step_err lander_post_paste_secure(lnm_http_conn *conn); lnm_http_step_err lander_stream_body_to_entry(lnm_http_conn *conn); +lnm_http_step_err lander_commit_entry(lnm_http_conn *conn); + lnm_http_step_err lander_post_redirect_body_to_attr(lnm_http_conn *conn); lnm_http_step_err lander_remove_entry(lnm_http_conn *conn); diff --git a/lsm/include/lsm/store.h b/lsm/include/lsm/store.h index c680c43..e2d7d86 100644 --- a/lsm/include/lsm/store.h +++ b/lsm/include/lsm/store.h @@ -159,6 +159,15 @@ lsm_error lsm_store_open_read(lsm_entry_handle **out, lsm_store *store, lsm_error lsm_store_open_write(lsm_entry_handle **out, lsm_store *store, const lsm_str *key); +/** + * Commit any changes to the persistent storage. Any changes, insertions or + * deletions that occured without a commit are reverted when the handle is + * closed. + * + * @param handle handle to the entry + */ +lsm_error lsm_entry_commit(lsm_entry_handle *handle); + /** * Close an open entry handle. * diff --git a/lsm/src/_include/lsm/store_internal.h b/lsm/src/_include/lsm/store_internal.h index e446a0d..1b84b60 100644 --- a/lsm/src/_include/lsm/store_internal.h +++ b/lsm/src/_include/lsm/store_internal.h @@ -156,4 +156,12 @@ lsm_error lsm_entry_data_open_read(lsm_entry_handle *handle); */ lsm_error lsm_entry_data_open_write(lsm_entry_handle *handle); +/** + * Remove the entry's data file if present and close its handle. Any uncommitted + * changes will be reverted. + * + * @param handle handle to the entry + */ +lsm_error lsm_entry_data_remove(lsm_entry_handle *handle); + #endif diff --git a/lsm/src/store/lsm_store_disk_write.c b/lsm/src/store/lsm_store_disk_write.c index 31f907b..51e9be8 100644 --- a/lsm/src/store/lsm_store_disk_write.c +++ b/lsm/src/store/lsm_store_disk_write.c @@ -153,20 +153,7 @@ lsm_error lsm_entry_disk_remove(lsm_entry_handle *handle) { fflush(store->idx.f); - // Remove data file if present - if (entry->data_len > 0) { - if (handle->f != NULL) { - fclose(handle->f); - handle->f = NULL; - } - - char data_path[lsm_entry_data_path_len(handle) + 1]; - lsm_entry_data_path(data_path, handle); - - if (remove(data_path) != 0) { - return lsm_error_failed_io; - } - } + LSM_RES(lsm_entry_data_remove(handle)); return lsm_error_ok; } diff --git a/lsm/src/store/lsm_store_entry.c b/lsm/src/store/lsm_store_entry.c index 63d90a7..7d33d30 100644 --- a/lsm/src/store/lsm_store_entry.c +++ b/lsm/src/store/lsm_store_entry.c @@ -58,23 +58,45 @@ lsm_error lsm_entry_handle_init(lsm_entry_handle **out) { return lsm_error_ok; } -void lsm_entry_close(lsm_entry_handle *handle) { - if (handle->f != NULL) { - fclose(handle->f); - } +lsm_error lsm_entry_commit(lsm_entry_handle *handle) { + uint8_t state_new = handle->states & lsm_entry_handle_state_new; + uint8_t state_removed = handle->states & lsm_entry_handle_state_removed; - // TODO handle errors here - if ((handle->states & lsm_entry_handle_state_new) && - !(handle->states & lsm_entry_handle_state_removed)) { - lsm_entry_disk_insert(handle); - } else if ((handle->states & lsm_entry_handle_state_removed) && - !(handle->states & lsm_entry_handle_state_new)) { - lsm_entry_disk_remove(handle); + // Clean new entry + if (state_new && !state_removed) { + LSM_RES(lsm_entry_disk_insert(handle)); + } + // Previously stored entry that needs to be removed; should be removed from db + // file as well + else if (state_removed && !state_new) { + LSM_RES(lsm_entry_disk_remove(handle)); + + lsm_entry_free(handle->wrapper->entry); + handle->wrapper->entry = NULL; + } + + // Reset states after committing current changes + handle->states = 0; + + return lsm_error_ok; +} + +void lsm_entry_close(lsm_entry_handle *handle) { + if (handle->f != NULL) { + fclose(handle->f); + handle->f = NULL; + } + + uint8_t state_new = handle->states & lsm_entry_handle_state_new; + /* bool state_updated = handle->states & lsm_entry_handle_state_updated; */ + + // New entries create a wrapper in the trie that should be removed if not + // committed + if (state_new) { + lsm_entry_data_remove(handle); lsm_entry_free(handle->wrapper->entry); handle->wrapper->entry = NULL; - } else if (handle->states & lsm_entry_handle_state_updated) { - /* lsm_entry_disk_update(handle); */ } pthread_rwlock_unlock(&handle->wrapper->lock); @@ -316,3 +338,23 @@ lsm_error lsm_entry_data_open_read(lsm_entry_handle *handle) { return lsm_error_ok; } + +lsm_error lsm_entry_data_remove(lsm_entry_handle *handle) { + const lsm_entry *entry = handle->wrapper->entry; + + if (entry->data_len > 0) { + if (handle->f != NULL) { + fclose(handle->f); + handle->f = NULL; + } + + char data_path[lsm_entry_data_path_len(handle) + 1]; + lsm_entry_data_path(data_path, handle); + + if (remove(data_path) != 0) { + return lsm_error_failed_io; + } + } + + return lsm_error_ok; +} diff --git a/src/lander/lander_steps.c b/src/lander/lander_steps.c index 00c86ba..8e2d702 100644 --- a/src/lander/lander_steps.c +++ b/src/lander/lander_steps.c @@ -1,6 +1,7 @@ #include #include "lnm/http/loop.h" +#include "lnm/log.h" #include "lnm/loop.h" #include "lander.h" @@ -25,3 +26,12 @@ lnm_http_step_err lander_stream_body_to_entry(lnm_http_conn *conn) { ? lnm_http_step_err_done : lnm_http_step_err_io_needed; } + +lnm_http_step_err lander_commit_entry(lnm_http_conn *conn) { + lnm_http_loop_ctx *ctx = conn->ctx; + lander_ctx *c_ctx = ctx->c; + + lsm_entry_commit(c_ctx->entry); + + return lnm_http_step_err_done; +} diff --git a/src/main.c b/src/main.c index f0f8e65..016540f 100644 --- a/src/main.c +++ b/src/main.c @@ -30,54 +30,64 @@ lnm_http_loop *loop_init(lander_gctx *gctx, const char *api_key) { lnm_http_router_add(&route, router, lnm_http_method_delete, "/:key"); lnm_http_route_step_append(route, lnm_http_loop_step_auth, false); lnm_http_route_step_append(route, lander_remove_entry, false); + lnm_http_route_step_append(route, lander_commit_entry, true); lnm_http_router_add(&route, router, lnm_http_method_post, "/s/"); lnm_http_route_step_append(route, lnm_http_loop_step_auth, false); lnm_http_route_step_append(route, lander_post_redirect, false); lnm_http_route_step_append(route, lnm_http_loop_step_body_to_buf, false); lnm_http_route_step_append(route, lander_post_redirect_body_to_attr, false); + lnm_http_route_step_append(route, lander_commit_entry, true); lnm_http_router_add(&route, router, lnm_http_method_post, "/sl/"); lnm_http_route_step_append(route, lnm_http_loop_step_auth, false); lnm_http_route_step_append(route, lander_post_redirect_secure, false); lnm_http_route_step_append(route, lnm_http_loop_step_body_to_buf, false); lnm_http_route_step_append(route, lander_post_redirect_body_to_attr, false); + lnm_http_route_step_append(route, lander_commit_entry, true); lnm_http_router_add(&route, router, lnm_http_method_post, "/s/:key"); lnm_http_route_step_append(route, lnm_http_loop_step_auth, false); lnm_http_route_step_append(route, lander_post_redirect, false); lnm_http_route_step_append(route, lnm_http_loop_step_body_to_buf, false); lnm_http_route_step_append(route, lander_post_redirect_body_to_attr, false); + lnm_http_route_step_append(route, lander_commit_entry, true); lnm_http_router_add(&route, router, lnm_http_method_post, "/p/"); lnm_http_route_step_append(route, lnm_http_loop_step_auth, false); lnm_http_route_step_append(route, lander_post_paste, false); lnm_http_route_step_append(route, lander_stream_body_to_entry, false); + lnm_http_route_step_append(route, lander_commit_entry, true); lnm_http_router_add(&route, router, lnm_http_method_post, "/pl/"); lnm_http_route_step_append(route, lnm_http_loop_step_auth, false); lnm_http_route_step_append(route, lander_post_paste_secure, false); lnm_http_route_step_append(route, lander_stream_body_to_entry, false); + lnm_http_route_step_append(route, lander_commit_entry, true); lnm_http_router_add(&route, router, lnm_http_method_post, "/p/:key"); lnm_http_route_step_append(route, lnm_http_loop_step_auth, false); lnm_http_route_step_append(route, lander_post_paste, false); lnm_http_route_step_append(route, lander_stream_body_to_entry, false); + lnm_http_route_step_append(route, lander_commit_entry, true); lnm_http_router_add(&route, router, lnm_http_method_post, "/f/"); lnm_http_route_step_append(route, lnm_http_loop_step_auth, false); lnm_http_route_step_append(route, lander_post_file, false); lnm_http_route_step_append(route, lander_stream_body_to_entry, false); + lnm_http_route_step_append(route, lander_commit_entry, true); lnm_http_router_add(&route, router, lnm_http_method_post, "/fl/"); lnm_http_route_step_append(route, lnm_http_loop_step_auth, false); lnm_http_route_step_append(route, lander_post_file_secure, false); lnm_http_route_step_append(route, lander_stream_body_to_entry, false); + lnm_http_route_step_append(route, lander_commit_entry, true); lnm_http_router_add(&route, router, lnm_http_method_post, "/f/:key"); lnm_http_route_step_append(route, lnm_http_loop_step_auth, false); lnm_http_route_step_append(route, lander_post_file, false); lnm_http_route_step_append(route, lander_stream_body_to_entry, false); + lnm_http_route_step_append(route, lander_commit_entry, true); lnm_http_loop_router_set(hl, router); @@ -101,7 +111,7 @@ int main() { srand(time(NULL)); lnm_log_init_global(); - lnm_log_register_stdout(lnm_log_level_info); + lnm_log_register_stdout(lnm_log_level_debug); ENV(api_key, "LANDER_API_KEY"); ENV_OPT(port_str, "LANDER_PORT", "18080"); @@ -129,5 +139,5 @@ int main() { lnm_linfo("main", "Store loaded containing %lu entries", lsm_store_size(c_gctx->store)); lnm_http_loop *hl = loop_init(c_gctx, api_key); - lnm_http_loop_run(hl, port, 1, 0); + lnm_http_loop_run(hl, port, 4, 0); }