diff options
author | Magnus Ahltorp <map@kth.se> | 2016-11-26 02:48:11 +0100 |
---|---|---|
committer | Magnus Ahltorp <map@kth.se> | 2016-11-26 02:48:11 +0100 |
commit | 5fab0fd188242f08431dee0bff62a3028d262b6d (patch) | |
tree | 548ef788ad82776d258ded87d4f4922edff52748 /c_src/permdb.c | |
parent | 8826eb502c73df3a512a2d257f4264d68a10e1c8 (diff) |
Added RO mode to permdb
Diffstat (limited to 'c_src/permdb.c')
-rw-r--r-- | c_src/permdb.c | 107 |
1 files changed, 101 insertions, 6 deletions
diff --git a/c_src/permdb.c b/c_src/permdb.c index a33c43a..f92958d 100644 --- a/c_src/permdb.c +++ b/c_src/permdb.c @@ -37,6 +37,7 @@ struct permdb_object { buffered_file *datafile; buffered_file *indexfile; char *error; + int write_enabled; }; static const node_object nullnode = {{0, 0, 0, 0}}; @@ -447,8 +448,40 @@ rebuild_index_file(permdb_object *state) return committree(state); } +unsigned int +try_reload_database(permdb_object *state) { + if (state->write_enabled) { + errx(1, "try_reload_database called on write enabled database"); + } + + uint64_t oldindexsize = bf_total_length(state->indexfile); + + fprintf(stderr, "reloading database: datafile %llu indexfile %llu\n", + (unsigned long long) bf_total_length(state->datafile), + (unsigned long long) bf_total_length(state->indexfile)); + bf_reload(state->datafile); + bf_reload(state->indexfile); + fprintf(stderr, "reloaded database: datafile %llu indexfile %llu\n", + (unsigned long long) bf_total_length(state->datafile), + (unsigned long long) bf_total_length(state->indexfile)); + + if (bf_total_length(state->indexfile) == oldindexsize) { + return 0; + } else { + if (datafile_verify_file(state->datafile) < 0) { + warnx("data file verification failed"); + } + if (indexfile_verify_file(state->indexfile) < 0) { + warnx("cannot rebuild in readonly mode"); + } + + delete_all_nodes_in_cache(state); + return 1; + } +} + permdb_object * -permdb_alloc(const char *dbpath) +permdb_alloc(const char *dbpath, int lock) { char *idxpath = NULL; if (asprintf(&idxpath, "%s.idx", dbpath) == -1) { @@ -464,14 +497,22 @@ permdb_alloc(const char *dbpath) state->datafile = NULL; state->indexfile = NULL; - state->datafile = bf_open(dbpath, O_RDWR|O_CREAT, "datafile", 1); + state->write_enabled = lock; + + int mode = O_RDONLY; + + if (state->write_enabled) { + mode = O_RDWR|O_CREAT; + } + + state->datafile = bf_open(dbpath, mode, "datafile", state->write_enabled); if (state->datafile == NULL) { permdb_free(state); free(idxpath); return NULL; } - state->indexfile = bf_open(idxpath, O_RDWR|O_CREAT, "indexfile", 1); + state->indexfile = bf_open(idxpath, mode, "indexfile", state->write_enabled); if (state->indexfile == NULL) { permdb_free(state); free(idxpath); @@ -482,12 +523,22 @@ permdb_alloc(const char *dbpath) if (bf_total_length(state->datafile) == 0 && bf_total_length(state->indexfile) == 0) { + if (!state->write_enabled) { + warnx("data and index files are empty: %s", dbpath); + permdb_free(state); + return NULL; + } dprintf(WRITE, (stderr, "writing header\n")); indexfile_add_header(state->indexfile); datafile_add_header(state->datafile); initial_commit(state); } else if (bf_total_length(state->datafile) > 0 && bf_total_length(state->indexfile) == 0) { + if (!state->write_enabled) { + warnx("cannot rebuild in readonly mode: %s", dbpath); + permdb_free(state); + return NULL; + } if (rebuild_index_file(state) < 0) { warnx("index file rebuilding failed: %s", dbpath); permdb_free(state); @@ -500,6 +551,11 @@ permdb_alloc(const char *dbpath) return NULL; } if (indexfile_verify_file(state->indexfile) < 0) { + if (!state->write_enabled) { + warnx("cannot rebuild in readonly mode: %s", dbpath); + permdb_free(state); + return NULL; + } warnx("index file verification failed, rebuilding: %s", dbpath); if (rebuild_index_file(state) < 0) { @@ -933,6 +989,10 @@ addvalue(permdb_object *state, const unsigned char *key, unsigned int keylength, node_entry lastentry = getpath(state, key, nodes); + if (!state->write_enabled) { + return -1; + } + if (lastentry == NODE_ENTRY_ERROR_NODE) { utarray_free(nodes); return -1; @@ -1003,8 +1063,8 @@ addvalue(permdb_object *state, const unsigned char *key, unsigned int keylength, } unsigned char * -getvalue(permdb_object *state, const unsigned char *key, size_t keylength, - size_t *datalen) +getvalue_try(permdb_object *state, const unsigned char *key, size_t keylength, + size_t *datalen) { node_entry entry = getlastnode(state, key); if (entry == 0) { @@ -1028,8 +1088,24 @@ getvalue(permdb_object *state, const unsigned char *key, size_t keylength, return readdata(state, olddataoffset, *datalen); } +unsigned char * +getvalue(permdb_object *state, const unsigned char *key, size_t keylength, + size_t *datalen) +{ + unsigned char *result = getvalue_try(state, key, keylength, datalen); + + if (result == NULL && !state->write_enabled) { + int reloaded = try_reload_database(state); + if (reloaded) { + return getvalue_try(state, key, keylength, datalen); + } + } + + return result; +} + unsigned int -keyexists(permdb_object *state, const unsigned char *key, size_t keylength) +keyexists_try(permdb_object *state, const unsigned char *key, size_t keylength) { node_entry entry = getlastnode(state, key); if (entry == 0) { @@ -1053,6 +1129,21 @@ keyexists(permdb_object *state, const unsigned char *key, size_t keylength) return 1; } +unsigned int +keyexists(permdb_object *state, const unsigned char *key, size_t keylength) +{ + unsigned int result = keyexists_try(state, key, keylength); + + if (result == 0 && !state->write_enabled) { + int reloaded = try_reload_database(state); + if (reloaded) { + return keyexists_try(state, key, keylength); + } + } + + return result; +} + static int string_length_comparison(struct nodecache *a, struct nodecache *b) { size_t a_len = a->key->length; @@ -1081,6 +1172,10 @@ string_length_comparison(struct nodecache *a, struct nodecache *b) { int committree(permdb_object *state) { + if (!state->write_enabled) { + return -1; + } + if (state->dirtynodes == NULL) { return 0; } |