Commit f6067e4c authored by Rusty Russell's avatar Rusty Russell

tdb2: tdb_error()

This makes transition from tdb1 much simpler.
parent 8d8de08d
......@@ -765,13 +765,13 @@ enum TDB_ERROR tdb_check_(struct tdb_context *tdb,
ecode = tdb_allrecord_lock(tdb, F_RDLCK, TDB_LOCK_WAIT, false);
if (ecode != TDB_SUCCESS) {
return ecode;
return tdb->last_error = ecode;
}
ecode = tdb_lock_expand(tdb, F_RDLCK);
if (ecode != TDB_SUCCESS) {
tdb_allrecord_unlock(tdb, F_RDLCK);
return ecode;
return tdb->last_error = ecode;
}
ecode = check_header(tdb, &recovery, &features);
......@@ -812,5 +812,5 @@ out:
tdb_unlock_expand(tdb, F_RDLCK);
free(fr);
free(used);
return ecode;
return tdb->last_error = ecode;
}
......@@ -857,7 +857,8 @@ static enum TDB_ERROR chainlock(struct tdb_context *tdb, const TDB_DATA *key,
contention - it cannot guarantee how many records will be locked */
enum TDB_ERROR tdb_chainlock(struct tdb_context *tdb, TDB_DATA key)
{
return chainlock(tdb, &key, F_WRLCK, TDB_LOCK_WAIT, "tdb_chainlock");
return tdb->last_error = chainlock(tdb, &key, F_WRLCK, TDB_LOCK_WAIT,
"tdb_chainlock");
}
enum TDB_ERROR tdb_chainunlock(struct tdb_context *tdb, TDB_DATA key)
......@@ -872,5 +873,6 @@ enum TDB_ERROR tdb_chainunlock(struct tdb_context *tdb, TDB_DATA key)
lockstart = hlock_range(group, &locksize);
tdb_trace_1rec(tdb, "tdb_chainunlock", key);
return tdb_unlock_hashes(tdb, lockstart, locksize, F_WRLCK);
return tdb->last_error = tdb_unlock_hashes(tdb, lockstart, locksize,
F_WRLCK);
}
......@@ -209,6 +209,7 @@ struct tdb_context *tdb_open(const char *name, int tdb_flags,
tdb->transaction = NULL;
tdb->stats = NULL;
tdb->access = NULL;
tdb->last_error = TDB_SUCCESS;
tdb->file = NULL;
tdb_hash_init(tdb);
tdb_io_init(tdb);
......
......@@ -390,6 +390,9 @@ struct tdb_context {
/* Direct access information */
struct tdb_access_hdr *access;
/* Last error we returned. */
enum TDB_ERROR last_error;
/* The actual file information */
struct tdb_file *file;
};
......
......@@ -169,13 +169,13 @@ enum TDB_ERROR tdb_summary(struct tdb_context *tdb,
ecode = tdb_allrecord_lock(tdb, F_RDLCK, TDB_LOCK_WAIT, false);
if (ecode != TDB_SUCCESS) {
return ecode;
return tdb->last_error = ecode;
}
ecode = tdb_lock_expand(tdb, F_RDLCK);
if (ecode != TDB_SUCCESS) {
tdb_allrecord_unlock(tdb, F_RDLCK);
return ecode;
return tdb->last_error = ecode;
}
/* Start stats off empty. */
......@@ -289,5 +289,5 @@ unlock:
tdb_allrecord_unlock(tdb, F_RDLCK);
tdb_unlock_expand(tdb, F_RDLCK);
return ecode;
return tdb->last_error = ecode;
}
......@@ -98,7 +98,7 @@ enum TDB_ERROR tdb_store(struct tdb_context *tdb,
off = find_and_lock(tdb, key, F_WRLCK, &h, &rec, NULL);
if (TDB_OFF_IS_ERR(off)) {
return off;
return tdb->last_error = off;
}
/* Now we have lock on this hash bucket. */
......@@ -128,7 +128,7 @@ enum TDB_ERROR tdb_store(struct tdb_context *tdb,
}
tdb_unlock_hashes(tdb, h.hlock_start,
h.hlock_range, F_WRLCK);
return TDB_SUCCESS;
return tdb->last_error = TDB_SUCCESS;
}
} else {
if (flag == TDB_MODIFY) {
......@@ -145,7 +145,7 @@ enum TDB_ERROR tdb_store(struct tdb_context *tdb,
ecode = replace_data(tdb, &h, key, dbuf, off, old_room, off);
out:
tdb_unlock_hashes(tdb, h.hlock_start, h.hlock_range, F_WRLCK);
return ecode;
return tdb->last_error = ecode;
}
enum TDB_ERROR tdb_append(struct tdb_context *tdb,
......@@ -161,7 +161,7 @@ enum TDB_ERROR tdb_append(struct tdb_context *tdb,
off = find_and_lock(tdb, key, F_WRLCK, &h, &rec, NULL);
if (TDB_OFF_IS_ERR(off)) {
return off;
return tdb->last_error = off;
}
if (off) {
......@@ -213,7 +213,7 @@ out_free_newdata:
free(newdata);
out:
tdb_unlock_hashes(tdb, h.hlock_start, h.hlock_range, F_WRLCK);
return ecode;
return tdb->last_error = ecode;
}
enum TDB_ERROR tdb_fetch(struct tdb_context *tdb, struct tdb_data key,
......@@ -226,7 +226,7 @@ enum TDB_ERROR tdb_fetch(struct tdb_context *tdb, struct tdb_data key,
off = find_and_lock(tdb, key, F_RDLCK, &h, &rec, NULL);
if (TDB_OFF_IS_ERR(off)) {
return off;
return tdb->last_error = off;
}
if (!off) {
......@@ -242,7 +242,7 @@ enum TDB_ERROR tdb_fetch(struct tdb_context *tdb, struct tdb_data key,
}
tdb_unlock_hashes(tdb, h.hlock_start, h.hlock_range, F_RDLCK);
return ecode;
return tdb->last_error = ecode;
}
bool tdb_exists(struct tdb_context *tdb, TDB_DATA key)
......@@ -253,10 +253,12 @@ bool tdb_exists(struct tdb_context *tdb, TDB_DATA key)
off = find_and_lock(tdb, key, F_RDLCK, &h, &rec, NULL);
if (TDB_OFF_IS_ERR(off)) {
tdb->last_error = off;
return false;
}
tdb_unlock_hashes(tdb, h.hlock_start, h.hlock_range, F_RDLCK);
tdb->last_error = TDB_SUCCESS;
return off ? true : false;
}
......@@ -269,7 +271,7 @@ enum TDB_ERROR tdb_delete(struct tdb_context *tdb, struct tdb_data key)
off = find_and_lock(tdb, key, F_WRLCK, &h, &rec, NULL);
if (TDB_OFF_IS_ERR(off)) {
return off;
return tdb->last_error = off;
}
if (!off) {
......@@ -295,7 +297,7 @@ enum TDB_ERROR tdb_delete(struct tdb_context *tdb, struct tdb_data key)
unlock:
tdb_unlock_hashes(tdb, h.hlock_start, h.hlock_range, F_WRLCK);
return ecode;
return tdb->last_error = ecode;
}
unsigned int tdb_get_flags(struct tdb_context *tdb)
......@@ -306,8 +308,9 @@ unsigned int tdb_get_flags(struct tdb_context *tdb)
void tdb_add_flag(struct tdb_context *tdb, unsigned flag)
{
if (tdb->flags & TDB_INTERNAL) {
tdb_logerr(tdb, TDB_ERR_EINVAL, TDB_LOG_USE_ERROR,
"tdb_add_flag: internal db");
tdb->last_error = tdb_logerr(tdb, TDB_ERR_EINVAL,
TDB_LOG_USE_ERROR,
"tdb_add_flag: internal db");
return;
}
switch (flag) {
......@@ -325,16 +328,19 @@ void tdb_add_flag(struct tdb_context *tdb, unsigned flag)
tdb->flags |= TDB_SEQNUM;
break;
default:
tdb_logerr(tdb, TDB_ERR_EINVAL, TDB_LOG_USE_ERROR,
"tdb_add_flag: Unknown flag %u", flag);
tdb->last_error = tdb_logerr(tdb, TDB_ERR_EINVAL,
TDB_LOG_USE_ERROR,
"tdb_add_flag: Unknown flag %u",
flag);
}
}
void tdb_remove_flag(struct tdb_context *tdb, unsigned flag)
{
if (tdb->flags & TDB_INTERNAL) {
tdb_logerr(tdb, TDB_ERR_EINVAL, TDB_LOG_USE_ERROR,
"tdb_remove_flag: internal db");
tdb->last_error = tdb_logerr(tdb, TDB_ERR_EINVAL,
TDB_LOG_USE_ERROR,
"tdb_remove_flag: internal db");
return;
}
switch (flag) {
......@@ -352,8 +358,10 @@ void tdb_remove_flag(struct tdb_context *tdb, unsigned flag)
tdb->flags &= ~TDB_SEQNUM;
break;
default:
tdb_logerr(tdb, TDB_ERR_EINVAL, TDB_LOG_USE_ERROR,
"tdb_remove_flag: Unknown flag %u", flag);
tdb->last_error = tdb_logerr(tdb, TDB_ERR_EINVAL,
TDB_LOG_USE_ERROR,
"tdb_remove_flag: Unknown flag %u",
flag);
}
}
......@@ -419,7 +427,7 @@ enum TDB_ERROR tdb_parse_record_(struct tdb_context *tdb,
off = find_and_lock(tdb, key, F_RDLCK, &h, &rec, NULL);
if (TDB_OFF_IS_ERR(off)) {
return off;
return tdb->last_error = off;
}
if (!off) {
......@@ -439,7 +447,7 @@ enum TDB_ERROR tdb_parse_record_(struct tdb_context *tdb,
}
tdb_unlock_hashes(tdb, h.hlock_start, h.hlock_range, F_RDLCK);
return ecode;
return tdb->last_error = ecode;
}
const char *tdb_name(const struct tdb_context *tdb)
......@@ -449,7 +457,12 @@ const char *tdb_name(const struct tdb_context *tdb)
int64_t tdb_get_seqnum(struct tdb_context *tdb)
{
return tdb_read_off(tdb, offsetof(struct tdb_header, seqnum));
tdb_off_t off = tdb_read_off(tdb, offsetof(struct tdb_header, seqnum));
if (TDB_OFF_IS_ERR(off))
tdb->last_error = off;
else
tdb->last_error = TDB_SUCCESS;
return off;
}
......
......@@ -430,6 +430,17 @@ enum TDB_ERROR tdb_check_(struct tdb_context *tdb,
void *private),
void *private);
/**
* tdb_error - get the last error (not threadsafe)
* @tdb: the tdb context returned from tdb_open()
*
* Returns the last error returned by a TDB function.
*
* This makes porting from TDB1 easier, but note that the last error is not
* reliable in threaded programs.
*/
enum TDB_ERROR tdb_error(struct tdb_context *tdb);
/**
* enum tdb_summary_flags - flags for tdb_summary.
*/
......
......@@ -519,32 +519,42 @@ enum TDB_ERROR tdb_transaction_start(struct tdb_context *tdb)
/* some sanity checks */
if (tdb->read_only || (tdb->flags & TDB_INTERNAL)) {
return tdb_logerr(tdb, TDB_ERR_EINVAL, TDB_LOG_USE_ERROR,
"tdb_transaction_start: cannot start a"
" transaction on a read-only or internal db");
return tdb->last_error = tdb_logerr(tdb, TDB_ERR_EINVAL,
TDB_LOG_USE_ERROR,
"tdb_transaction_start:"
" cannot start a"
" transaction on a "
"read-only or internal db");
}
/* cope with nested tdb_transaction_start() calls */
if (tdb->transaction != NULL) {
return tdb_logerr(tdb, TDB_ERR_IO, TDB_LOG_USE_ERROR,
"tdb_transaction_start:"
" already inside transaction");
return tdb->last_error = tdb_logerr(tdb, TDB_ERR_IO,
TDB_LOG_USE_ERROR,
"tdb_transaction_start:"
" already inside"
" transaction");
}
if (tdb_has_hash_locks(tdb)) {
/* the caller must not have any locks when starting a
transaction as otherwise we'll be screwed by lack
of nested locks in POSIX */
return tdb_logerr(tdb, TDB_ERR_LOCK, TDB_LOG_USE_ERROR,
"tdb_transaction_start: cannot start a"
" transaction with locks held");
return tdb->last_error = tdb_logerr(tdb, TDB_ERR_LOCK,
TDB_LOG_USE_ERROR,
"tdb_transaction_start:"
" cannot start a"
" transaction with locks"
" held");
}
tdb->transaction = (struct tdb_transaction *)
calloc(sizeof(struct tdb_transaction), 1);
if (tdb->transaction == NULL) {
return tdb_logerr(tdb, TDB_ERR_OOM, TDB_LOG_ERROR,
"tdb_transaction_start: cannot allocate");
return tdb->last_error = tdb_logerr(tdb, TDB_ERR_OOM,
TDB_LOG_ERROR,
"tdb_transaction_start:"
" cannot allocate");
}
/* get the transaction write lock. This is a blocking lock. As
......@@ -554,7 +564,7 @@ enum TDB_ERROR tdb_transaction_start(struct tdb_context *tdb)
if (ecode != TDB_SUCCESS) {
SAFE_FREE(tdb->transaction->blocks);
SAFE_FREE(tdb->transaction);
return ecode;
return tdb->last_error = ecode;
}
/* get a read lock over entire file. This is upgraded to a write
......@@ -573,13 +583,13 @@ enum TDB_ERROR tdb_transaction_start(struct tdb_context *tdb)
transaction specific methods */
tdb->transaction->io_methods = tdb->methods;
tdb->methods = &transaction_methods;
return TDB_SUCCESS;
return tdb->last_error = TDB_SUCCESS;
fail_allrecord_lock:
tdb_transaction_unlock(tdb, F_WRLCK);
SAFE_FREE(tdb->transaction->blocks);
SAFE_FREE(tdb->transaction);
return ecode;
return tdb->last_error = ecode;
}
......@@ -983,27 +993,29 @@ enum TDB_ERROR tdb_transaction_commit(struct tdb_context *tdb)
enum TDB_ERROR ecode;
if (tdb->transaction == NULL) {
return tdb_logerr(tdb, TDB_ERR_EINVAL, TDB_LOG_USE_ERROR,
"tdb_transaction_commit: no transaction");
return tdb->last_error = tdb_logerr(tdb, TDB_ERR_EINVAL,
TDB_LOG_USE_ERROR,
"tdb_transaction_commit:"
" no transaction");
}
tdb_trace(tdb, "tdb_transaction_commit");
if (tdb->transaction->nesting != 0) {
tdb->transaction->nesting--;
return TDB_SUCCESS;
return tdb->last_error = TDB_SUCCESS;
}
/* check for a null transaction */
if (tdb->transaction->blocks == NULL) {
_tdb_transaction_cancel(tdb);
return TDB_SUCCESS;
return tdb->last_error = TDB_SUCCESS;
}
if (!tdb->transaction->prepared) {
ecode = _tdb_transaction_prepare_commit(tdb);
if (ecode != TDB_SUCCESS)
return ecode;
return tdb->last_error = ecode;
}
methods = tdb->transaction->io_methods;
......@@ -1038,7 +1050,7 @@ enum TDB_ERROR tdb_transaction_commit(struct tdb_context *tdb)
_tdb_transaction_cancel(tdb);
return ecode;
return tdb->last_error = ecode;
}
SAFE_FREE(tdb->transaction->blocks[i]);
}
......@@ -1049,7 +1061,7 @@ enum TDB_ERROR tdb_transaction_commit(struct tdb_context *tdb)
/* ensure the new data is on disk */
ecode = transaction_sync(tdb, 0, tdb->file->map_size);
if (ecode != TDB_SUCCESS) {
return ecode;
return tdb->last_error = ecode;
}
/*
......@@ -1071,7 +1083,7 @@ enum TDB_ERROR tdb_transaction_commit(struct tdb_context *tdb)
transaction locks */
_tdb_transaction_cancel(tdb);
return TDB_SUCCESS;
return tdb->last_error = TDB_SUCCESS;
}
......
......@@ -37,14 +37,16 @@ int64_t tdb_traverse_(struct tdb_context *tdb,
count++;
if (fn && fn(tdb, k, d, p)) {
free(k.dptr);
tdb->last_error = TDB_SUCCESS;
return count;
}
free(k.dptr);
}
if (ecode != TDB_ERR_NOEXIST) {
return ecode;
return tdb->last_error = ecode;
}
tdb->last_error = TDB_SUCCESS;
return count;
}
......@@ -52,7 +54,7 @@ enum TDB_ERROR tdb_firstkey(struct tdb_context *tdb, struct tdb_data *key)
{
struct traverse_info tinfo;
return first_in_hash(tdb, &tinfo, key, NULL);
return tdb->last_error = first_in_hash(tdb, &tinfo, key, NULL);
}
/* We lock twice, not very efficient. We could keep last key & tinfo cached. */
......@@ -65,11 +67,11 @@ enum TDB_ERROR tdb_nextkey(struct tdb_context *tdb, struct tdb_data *key)
tinfo.prev = find_and_lock(tdb, *key, F_RDLCK, &h, &rec, &tinfo);
free(key->dptr);
if (TDB_OFF_IS_ERR(tinfo.prev)) {
return tinfo.prev;
return tdb->last_error = tinfo.prev;
}
tdb_unlock_hashes(tdb, h.hlock_start, h.hlock_range, F_RDLCK);
return next_in_hash(tdb, &tinfo, key, NULL);
return tdb->last_error = next_in_hash(tdb, &tinfo, key, NULL);
}
static int wipe_one(struct tdb_context *tdb,
......@@ -86,12 +88,12 @@ enum TDB_ERROR tdb_wipe_all(struct tdb_context *tdb)
ecode = tdb_allrecord_lock(tdb, F_WRLCK, TDB_LOCK_WAIT, false);
if (ecode != TDB_SUCCESS)
return ecode;
return tdb->last_error = ecode;
/* FIXME: Be smarter. */
count = tdb_traverse(tdb, wipe_one, &ecode);
if (count < 0)
ecode = count;
tdb_allrecord_unlock(tdb, F_WRLCK);
return ecode;
return tdb->last_error = ecode;
}
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