Commit 012f68a0 authored by Rusty Russell's avatar Rusty Russell

tdb2: rework io functions to return enum TDB_ERROR.

We have a series of I/O functions which change depending on whether we're
inside a transaction or not.  This makes them return enum TDB_ERROR instead
of int.
parent 2a585ebc
......@@ -416,6 +416,8 @@ static bool check_free(struct tdb_context *tdb,
tdb_off_t prev, unsigned int ftable,
unsigned int bucket)
{
enum TDB_ERROR ecode;
if (frec_magic(frec) != TDB_FREE_MAGIC) {
tdb_logerr(tdb, TDB_ERR_CORRUPT, TDB_LOG_ERROR,
"tdb_check: offset %llu bad magic 0x%llx",
......@@ -429,10 +431,14 @@ static bool check_free(struct tdb_context *tdb,
return false;
}
if (tdb->methods->oob(tdb, off
+ frec_len(frec) + sizeof(struct tdb_used_record),
false))
ecode = tdb->methods->oob(tdb, off
+ frec_len(frec)
+ sizeof(struct tdb_used_record),
false);
if (ecode != TDB_SUCCESS) {
tdb->ecode = ecode;
return false;
}
if (size_to_bucket(frec_len(frec)) != bucket) {
tdb_logerr(tdb, TDB_ERR_CORRUPT, TDB_LOG_ERROR,
"tdb_check: offset %llu in wrong bucket %u vs %u",
......@@ -509,11 +515,15 @@ static bool check_free_table(struct tdb_context *tdb,
size_t dead_space(struct tdb_context *tdb, tdb_off_t off)
{
size_t len;
enum TDB_ERROR ecode;
for (len = 0; off + len < tdb->map_size; len++) {
char c;
if (tdb->methods->tread(tdb, off, &c, 1))
ecode = tdb->methods->tread(tdb, off, &c, 1);
if (ecode != TDB_SUCCESS) {
tdb->ecode = ecode;
return 0;
}
if (c != 0 && c != 0x43)
break;
}
......
......@@ -625,7 +625,9 @@ static int tdb_expand(struct tdb_context *tdb, tdb_len_t size)
return 0;
}
if (tdb->methods->expand_file(tdb, wanted) == -1) {
ecode = tdb->methods->expand_file(tdb, wanted);
if (ecode != TDB_SUCCESS) {
tdb->ecode = ecode;
tdb_unlock_expand(tdb, F_WRLCK);
return -1;
}
......
......@@ -67,7 +67,8 @@ void tdb_mmap(struct tdb_context *tdb)
if necessary
note that "len" is the minimum length needed for the db
*/
static int tdb_oob(struct tdb_context *tdb, tdb_off_t len, bool probe)
static enum TDB_ERROR tdb_oob(struct tdb_context *tdb, tdb_off_t len,
bool probe)
{
struct stat st;
enum TDB_ERROR ecode;
......@@ -87,20 +88,19 @@ static int tdb_oob(struct tdb_context *tdb, tdb_off_t len, bool probe)
(long long)len,
(long long)tdb->map_size);
}
return -1;
return TDB_ERR_IO;
}
ecode = tdb_lock_expand(tdb, F_RDLCK);
if (ecode != TDB_SUCCESS) {
tdb->ecode = ecode;
return -1;
return ecode;
}
if (fstat(tdb->fd, &st) != 0) {
tdb_logerr(tdb, TDB_ERR_IO, TDB_LOG_ERROR,
"Failed to fstat file: %s", strerror(errno));
tdb_unlock_expand(tdb, F_RDLCK);
return -1;
return TDB_ERR_IO;
}
tdb_unlock_expand(tdb, F_RDLCK);
......@@ -111,7 +111,7 @@ static int tdb_oob(struct tdb_context *tdb, tdb_off_t len, bool probe)
"tdb_oob len %zu beyond eof at %zu",
(size_t)len, st.st_size);
}
return -1;
return TDB_ERR_IO;
}
/* Unmap, update size, remap */
......@@ -119,7 +119,7 @@ static int tdb_oob(struct tdb_context *tdb, tdb_off_t len, bool probe)
tdb->map_size = st.st_size;
tdb_mmap(tdb);
return 0;
return TDB_SUCCESS;
}
/* Endian conversion: we only ever deal with 8 byte quantities */
......@@ -178,6 +178,7 @@ int zero_out(struct tdb_context *tdb, tdb_off_t off, tdb_len_t len)
{
char buf[8192] = { 0 };
void *p = tdb->methods->direct(tdb, off, len, true);
enum TDB_ERROR ecode;
assert(!tdb->read_only);
if (p) {
......@@ -186,8 +187,11 @@ int zero_out(struct tdb_context *tdb, tdb_off_t off, tdb_len_t len)
}
while (len) {
unsigned todo = len < sizeof(buf) ? len : sizeof(buf);
if (tdb->methods->twrite(tdb, off, buf, todo) == -1)
ecode = tdb->methods->twrite(tdb, off, buf, todo);
if (ecode != TDB_SUCCESS) {
tdb->ecode = ecode;
return -1;
}
len -= todo;
off += todo;
}
......@@ -211,22 +215,25 @@ tdb_off_t tdb_read_off(struct tdb_context *tdb, tdb_off_t off)
}
/* write a lump of data at a specified offset */
static int tdb_write(struct tdb_context *tdb, tdb_off_t off,
static enum TDB_ERROR tdb_write(struct tdb_context *tdb, tdb_off_t off,
const void *buf, tdb_len_t len)
{
enum TDB_ERROR ecode;
if (tdb->read_only) {
tdb_logerr(tdb, TDB_ERR_RDONLY, TDB_LOG_USE_ERROR,
return tdb_logerr(tdb, TDB_ERR_RDONLY, TDB_LOG_USE_ERROR,
"Write to read-only database");
return -1;
}
/* FIXME: Bogus optimization? */
if (len == 0) {
return 0;
return TDB_SUCCESS;
}
if (tdb->methods->oob(tdb, off + len, 0) != 0)
return -1;
ecode = tdb->methods->oob(tdb, off + len, 0);
if (ecode != TDB_SUCCESS) {
return ecode;
}
if (tdb->map_ptr) {
memcpy(off + (char *)tdb->map_ptr, buf, len);
......@@ -238,22 +245,24 @@ static int tdb_write(struct tdb_context *tdb, tdb_off_t off,
if (ret >= 0)
errno = ENOSPC;
tdb_logerr(tdb, TDB_ERR_IO, TDB_LOG_ERROR,
return tdb_logerr(tdb, TDB_ERR_IO, TDB_LOG_ERROR,
"tdb_write: %zi at %zu len=%zu (%s)",
ret, (size_t)off, (size_t)len,
strerror(errno));
return -1;
}
}
return 0;
return TDB_SUCCESS;
}
/* read a lump of data at a specified offset */
static int tdb_read(struct tdb_context *tdb, tdb_off_t off, void *buf,
tdb_len_t len)
static enum TDB_ERROR tdb_read(struct tdb_context *tdb, tdb_off_t off,
void *buf, tdb_len_t len)
{
if (tdb->methods->oob(tdb, off + len, 0) != 0) {
return -1;
enum TDB_ERROR ecode;
ecode = tdb->methods->oob(tdb, off + len, 0);
if (ecode != TDB_SUCCESS) {
return ecode;
}
if (tdb->map_ptr) {
......@@ -261,22 +270,22 @@ static int tdb_read(struct tdb_context *tdb, tdb_off_t off, void *buf,
} else {
ssize_t r = pread(tdb->fd, buf, len, off);
if (r != len) {
tdb_logerr(tdb, TDB_ERR_IO, TDB_LOG_ERROR,
return tdb_logerr(tdb, TDB_ERR_IO, TDB_LOG_ERROR,
"tdb_read failed with %zi at %zu "
"len=%zu (%s) map_size=%zu",
r, (size_t)off, (size_t)len,
strerror(errno),
(size_t)tdb->map_size);
return -1;
}
}
return 0;
return TDB_SUCCESS;
}
int tdb_write_convert(struct tdb_context *tdb, tdb_off_t off,
const void *rec, size_t len)
{
int ret;
enum TDB_ERROR ecode;
if (unlikely((tdb->flags & TDB_CONVERT))) {
void *conv = malloc(len);
if (!conv) {
......@@ -286,21 +295,30 @@ int tdb_write_convert(struct tdb_context *tdb, tdb_off_t off,
return -1;
}
memcpy(conv, rec, len);
ret = tdb->methods->twrite(tdb, off,
ecode = tdb->methods->twrite(tdb, off,
tdb_convert(tdb, conv, len), len);
free(conv);
} else
ret = tdb->methods->twrite(tdb, off, rec, len);
} else {
ecode = tdb->methods->twrite(tdb, off, rec, len);
}
return ret;
if (ecode != TDB_SUCCESS) {
tdb->ecode = ecode;
return -1;
}
return 0;
}
int tdb_read_convert(struct tdb_context *tdb, tdb_off_t off,
void *rec, size_t len)
{
int ret = tdb->methods->tread(tdb, off, rec, len);
enum TDB_ERROR ecode = tdb->methods->tread(tdb, off, rec, len);
tdb_convert(tdb, rec, len);
return ret;
if (ecode != TDB_SUCCESS) {
tdb->ecode = ecode;
return -1;
}
return 0;
}
int tdb_write_off(struct tdb_context *tdb, tdb_off_t off, tdb_off_t val)
......@@ -326,6 +344,7 @@ static void *_tdb_alloc_read(struct tdb_context *tdb, tdb_off_t offset,
tdb_len_t len, unsigned int prefix)
{
void *buf;
enum TDB_ERROR ecode;
/* some systems don't like zero length malloc */
buf = malloc(prefix + len ? prefix + len : 1);
......@@ -333,11 +352,14 @@ static void *_tdb_alloc_read(struct tdb_context *tdb, tdb_off_t offset,
tdb_logerr(tdb, TDB_ERR_OOM, TDB_LOG_USE_ERROR,
"tdb_alloc_read malloc failed len=%zu",
(size_t)(prefix + len));
} else if (unlikely(tdb->methods->tread(tdb, offset, buf+prefix, len)
== -1)) {
} else {
ecode = tdb->methods->tread(tdb, offset, buf+prefix, len);
if (unlikely(ecode != TDB_SUCCESS)) {
tdb->ecode = ecode;
free(buf);
buf = NULL;
}
}
return buf;
}
......@@ -372,22 +394,21 @@ static int fill(struct tdb_context *tdb,
/* expand a file. we prefer to use ftruncate, as that is what posix
says to use for mmap expansion */
static int tdb_expand_file(struct tdb_context *tdb, tdb_len_t addition)
static enum TDB_ERROR tdb_expand_file(struct tdb_context *tdb,
tdb_len_t addition)
{
char buf[8192];
if (tdb->read_only) {
tdb_logerr(tdb, TDB_ERR_RDONLY, TDB_LOG_USE_ERROR,
return tdb_logerr(tdb, TDB_ERR_RDONLY, TDB_LOG_USE_ERROR,
"Expand on read-only database");
return -1;
}
if (tdb->flags & TDB_INTERNAL) {
char *new = realloc(tdb->map_ptr, tdb->map_size + addition);
if (!new) {
tdb_logerr(tdb, TDB_ERR_OOM, TDB_LOG_ERROR,
return tdb_logerr(tdb, TDB_ERR_OOM, TDB_LOG_ERROR,
"No memory to expand database");
return -1;
}
tdb->map_ptr = new;
tdb->map_size += addition;
......@@ -405,11 +426,11 @@ static int tdb_expand_file(struct tdb_context *tdb, tdb_len_t addition)
disk. This must be done with write, not via mmap */
memset(buf, 0x43, sizeof(buf));
if (fill(tdb, buf, sizeof(buf), tdb->map_size, addition) == -1)
return -1;
return tdb->ecode;
tdb->map_size += addition;
tdb_mmap(tdb);
}
return 0;
return TDB_SUCCESS;
}
const void *tdb_access_read(struct tdb_context *tdb,
......@@ -517,7 +538,7 @@ static void *tdb_direct(struct tdb_context *tdb, tdb_off_t off, size_t len,
if (unlikely(!tdb->map_ptr))
return NULL;
if (unlikely(tdb_oob(tdb, off + len, true) == -1))
if (unlikely(tdb_oob(tdb, off + len, true) != TDB_SUCCESS))
return NULL;
return (char *)tdb->map_ptr + off;
}
......
......@@ -379,10 +379,12 @@ struct tdb_context {
};
struct tdb_methods {
int (*tread)(struct tdb_context *, tdb_off_t, void *, tdb_len_t);
int (*twrite)(struct tdb_context *, tdb_off_t, const void *, tdb_len_t);
int (*oob)(struct tdb_context *, tdb_off_t, bool);
int (*expand_file)(struct tdb_context *, tdb_len_t);
enum TDB_ERROR (*tread)(struct tdb_context *, tdb_off_t, void *,
tdb_len_t);
enum TDB_ERROR (*twrite)(struct tdb_context *, tdb_off_t, const void *,
tdb_len_t);
enum TDB_ERROR (*oob)(struct tdb_context *, tdb_off_t, bool);
enum TDB_ERROR (*expand_file)(struct tdb_context *, tdb_len_t);
void *(*direct)(struct tdb_context *, tdb_off_t, size_t, bool);
};
......
......@@ -429,6 +429,7 @@ static int replace_data(struct tdb_context *tdb,
bool growing)
{
tdb_off_t new_off;
enum TDB_ERROR ecode;
/* Allocate a new record. */
new_off = alloc(tdb, key.dsize, dbuf.dsize, h->h, TDB_USED_MAGIC,
......@@ -450,12 +451,18 @@ static int replace_data(struct tdb_context *tdb,
}
new_off += sizeof(struct tdb_used_record);
if (tdb->methods->twrite(tdb, new_off, key.dptr, key.dsize) == -1)
ecode = tdb->methods->twrite(tdb, new_off, key.dptr, key.dsize);
if (ecode != TDB_SUCCESS) {
tdb->ecode = ecode;
return -1;
}
new_off += key.dsize;
if (tdb->methods->twrite(tdb, new_off, dbuf.dptr, dbuf.dsize) == -1)
ecode = tdb->methods->twrite(tdb, new_off, dbuf.dptr, dbuf.dsize);
if (ecode != TDB_SUCCESS) {
tdb->ecode = ecode;
return -1;
}
/* FIXME: tdb_increment_seqnum(tdb); */
return 0;
......@@ -469,6 +476,7 @@ int tdb_store(struct tdb_context *tdb,
tdb_len_t old_room = 0;
struct tdb_used_record rec;
int ret;
enum TDB_ERROR ecode;
off = find_and_lock(tdb, key, F_WRLCK, &h, &rec, NULL);
if (unlikely(off == TDB_OFF_ERR))
......@@ -490,10 +498,15 @@ int tdb_store(struct tdb_context *tdb,
key.dsize, dbuf.dsize,
&rec, h.h))
goto fail;
if (tdb->methods->twrite(tdb, off + sizeof(rec)
ecode = tdb->methods->twrite(tdb,
off + sizeof(rec)
+ key.dsize,
dbuf.dptr, dbuf.dsize))
dbuf.dptr,
dbuf.dsize);
if (ecode != TDB_SUCCESS) {
tdb->ecode = ecode;
goto fail;
}
tdb_unlock_hashes(tdb, h.hlock_start,
h.hlock_range, F_WRLCK);
return 0;
......@@ -528,6 +541,7 @@ int tdb_append(struct tdb_context *tdb,
tdb_len_t old_room = 0, old_dlen;
unsigned char *newdata;
struct tdb_data new_dbuf;
enum TDB_ERROR ecode;
int ret;
off = find_and_lock(tdb, key, F_WRLCK, &h, &rec, NULL);
......@@ -545,9 +559,12 @@ int tdb_append(struct tdb_context *tdb,
goto fail;
off += sizeof(rec) + key.dsize + old_dlen;
if (tdb->methods->twrite(tdb, off, dbuf.dptr,
dbuf.dsize) == -1)
ecode = tdb->methods->twrite(tdb, off, dbuf.dptr,
dbuf.dsize);
if (ecode != TDB_SUCCESS) {
tdb->ecode = ecode;
goto fail;
}
/* FIXME: tdb_increment_seqnum(tdb); */
tdb_unlock_hashes(tdb, h.hlock_start, h.hlock_range,
......@@ -563,8 +580,10 @@ int tdb_append(struct tdb_context *tdb,
(size_t)(key.dsize+old_dlen+dbuf.dsize));
goto fail;
}
if (tdb->methods->tread(tdb, off + sizeof(rec) + key.dsize,
newdata, old_dlen) != 0) {
ecode = tdb->methods->tread(tdb, off + sizeof(rec) + key.dsize,
newdata, old_dlen);
if (ecode != TDB_SUCCESS) {
tdb->ecode = ecode;
free(newdata);
goto fail;
}
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment