]> git.ozlabs.org Git - ccan/blobdiff - ccan/tdb2/tdb1_transaction.c
ttxml: removed cruft from tests
[ccan] / ccan / tdb2 / tdb1_transaction.c
index ecd7d2628e4981e42634da4617c6581f831a0d87..9cb95235662d7864e3739e75f9d86ee1d8760715 100644 (file)
@@ -376,9 +376,9 @@ static void transaction1_next_hash_chain(struct tdb_context *tdb, uint32_t *chai
 /*
   out of bounds check during a transaction
 */
-static int transaction1_oob(struct tdb_context *tdb, tdb1_off_t len, int probe)
+static int transaction1_oob(struct tdb_context *tdb, tdb1_off_t off, tdb1_off_t len, int probe)
 {
-       if (len <= tdb->file->map_size) {
+       if (off + len >= off && off + len <= tdb->file->map_size) {
                return 0;
        }
        tdb->last_error = TDB_ERR_IO;
@@ -418,20 +418,37 @@ static const struct tdb1_methods transaction1_methods = {
 static int _tdb1_transaction_start(struct tdb_context *tdb)
 {
        /* some sanity checks */
-       if ((tdb->flags & TDB_RDONLY) || (tdb->flags & TDB_INTERNAL) || tdb->tdb1.traverse_read) {
-               tdb->last_error = tdb_logerr(tdb, TDB_ERR_EINVAL, TDB_LOG_USE_ERROR,
-                                       "tdb1_transaction_start: cannot start a"
-                                       " transaction on a read-only or"
-                                       " internal db");
+       if (tdb->flags & TDB_INTERNAL) {
+               tdb->last_error = tdb_logerr(tdb, TDB_ERR_EINVAL,
+                                            TDB_LOG_USE_ERROR,
+                                            "tdb1_transaction_start:"
+                                            " cannot start a"
+                                            " transaction on an"
+                                            " internal tdb");
+               return -1;
+       }
+
+       if ((tdb->flags & TDB_RDONLY) || tdb->tdb1.traverse_read) {
+               tdb->last_error = tdb_logerr(tdb, TDB_ERR_RDONLY,
+                                            TDB_LOG_USE_ERROR,
+                                            "tdb_transaction_start:"
+                                            " cannot start a"
+                                            " transaction on a "
+                                            " read-only tdb");
                return -1;
        }
 
        /* cope with nested tdb1_transaction_start() calls */
        if (tdb->tdb1.transaction != NULL) {
                if (!(tdb->flags & TDB_ALLOW_NESTING)) {
-                       tdb->last_error = TDB_ERR_EINVAL;
+                       tdb->last_error
+                               = tdb_logerr(tdb, TDB_ERR_EINVAL,
+                                            TDB_LOG_USE_ERROR,
+                                            "tdb_transaction_start:"
+                                            " already inside transaction");
                        return -1;
                }
+               tdb->stats.transaction_nest++;
                tdb->tdb1.transaction->nesting++;
                return 0;
        }
@@ -503,7 +520,7 @@ static int _tdb1_transaction_start(struct tdb_context *tdb)
 
        /* make sure we know about any file expansions already done by
           anyone else */
-       tdb->tdb1.io->tdb1_oob(tdb, tdb->file->map_size + 1, 1);
+       tdb->tdb1.io->tdb1_oob(tdb, tdb->file->map_size, 1, 1);
        tdb->tdb1.transaction->old_map_size = tdb->file->map_size;
 
        /* finally hook the io methods, replacing them with
@@ -511,6 +528,7 @@ static int _tdb1_transaction_start(struct tdb_context *tdb)
        tdb->tdb1.transaction->io_methods = tdb->tdb1.io;
        tdb->tdb1.io = &transaction1_methods;
 
+       tdb->stats.transactions++;
        return 0;
 
 fail:
@@ -621,6 +639,7 @@ static int _tdb1_transaction_cancel(struct tdb_context *tdb)
 */
 int tdb1_transaction_cancel(struct tdb_context *tdb)
 {
+       tdb->stats.transaction_cancel++;
        return _tdb1_transaction_cancel(tdb);
 }
 
@@ -726,8 +745,11 @@ static int tdb1_recovery_allocate(struct tdb_context *tdb,
        *recovery_size = tdb1_recovery_size(tdb);
 
        /* round up to a multiple of page size */
-       *recovery_max_size = TDB1_ALIGN(sizeof(rec) + *recovery_size,
-                                       tdb->tdb1.page_size) - sizeof(rec);
+       *recovery_max_size = tdb1_expand_adjust(tdb->file->map_size,
+                                              *recovery_size,
+                                              tdb->tdb1.page_size)
+               - sizeof(rec);
+
        *recovery_offset = tdb->file->map_size;
        recovery_head = *recovery_offset;
 
@@ -739,9 +761,10 @@ static int tdb1_recovery_allocate(struct tdb_context *tdb,
                           " failed to create recovery area");
                return -1;
        }
+       tdb->stats.transaction_expand_file++;
 
        /* remap the file (if using mmap) */
-       methods->tdb1_oob(tdb, tdb->file->map_size + 1, 1);
+       methods->tdb1_oob(tdb, tdb->file->map_size, 1, 1);
 
        /* we have to reset the old map size so that we don't try to expand the file
           again in the transaction commit, which would destroy the recovery area */
@@ -1000,8 +1023,9 @@ static int _tdb1_transaction_prepare_commit(struct tdb_context *tdb)
                                   " expansion failed");
                        return -1;
                }
+               tdb->stats.transaction_expand_file++;
                tdb->file->map_size = tdb->tdb1.transaction->old_map_size;
-               methods->tdb1_oob(tdb, tdb->file->map_size + 1, 1);
+               methods->tdb1_oob(tdb, tdb->file->map_size, 1, 1);
        }
 
        /* Keep the open lock until the actual commit */
@@ -1153,7 +1177,8 @@ int tdb1_transaction_commit(struct tdb_context *tdb)
        _tdb1_transaction_cancel(tdb);
 
        if (need_repack) {
-               return tdb_repack(tdb);
+               if (tdb_repack(tdb) != 0)
+                       return -1;
        }
 
        return 0;
@@ -1296,7 +1321,7 @@ tdb_bool_err tdb1_needs_recovery(struct tdb_context *tdb)
 
        /* find the recovery area */
        if (tdb1_ofs_read(tdb, TDB1_RECOVERY_HEAD, &recovery_head) == -1) {
-               return tdb->last_error;
+               return TDB_ERR_TO_OFF(tdb->last_error);
        }
 
        if (recovery_head == 0) {
@@ -1307,7 +1332,7 @@ tdb_bool_err tdb1_needs_recovery(struct tdb_context *tdb)
        /* read the recovery record */
        if (tdb->tdb1.io->tdb1_read(tdb, recovery_head, &rec,
                                   sizeof(rec), TDB1_DOCONV()) == -1) {
-               return tdb->last_error;
+               return TDB_ERR_TO_OFF(tdb->last_error);
        }
 
        return (rec.magic == TDB1_RECOVERY_MAGIC);