tdb2: return TDB_ERR_RDONLY from transactions on R/O databases, log nesting
authorRusty Russell <rusty@rustcorp.com.au>
Wed, 31 Aug 2011 06:01:08 +0000 (15:31 +0930)
committerRusty Russell <rusty@rustcorp.com.au>
Wed, 31 Aug 2011 06:01:08 +0000 (15:31 +0930)
Rather than rturning TDB_ERR_EINVAL, return TDB_ERR_RDONLY, and log
when we fail due to nesting.

ccan/tdb2/tdb1_transaction.c
ccan/tdb2/test/run-tdb1-nested-transactions.c

index 126f7684689ba50b7fbd352d75aa8c0679b185e8..6e39de33f4c95269d818b0d8150f68b2735b6c2b 100644 (file)
@@ -418,18 +418,34 @@ 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++;
index a6a815363cf1d6b86d54c628b00f2ec86f53aa96..149e5318a09efdcb69bf49d94bbbfd9f441566ff 100644 (file)
@@ -15,7 +15,7 @@ int main(int argc, char *argv[])
        hsize.base.next = &tap_log_attr;
        hsize.tdb1_hashsize.hsize = 1024;
 
-       plan_tests(29);
+       plan_tests(30);
        key.dsize = strlen("hi");
        key.dptr = (void *)"hi";
 
@@ -33,6 +33,7 @@ int main(int argc, char *argv[])
        ok1(memcmp(data.dptr, "world", strlen("world")) == 0);
        free(data.dptr);
        ok1(tdb_transaction_start(tdb) == TDB_ERR_EINVAL);
+       ok1(tap_log_messages == 1);
 
        ok1(tdb_fetch(tdb, key, &data) == TDB_SUCCESS);
        ok1(data.dsize == strlen("world"));
@@ -55,7 +56,7 @@ int main(int argc, char *argv[])
        ok1(tdb_transaction_commit(tdb) == TDB_SUCCESS);
        ok1(!tdb_exists(tdb, key));
        tdb_transaction_cancel(tdb);
-       ok1(tap_log_messages == 0);
+       ok1(tap_log_messages == 1);
        /* Surprise! Kills inner "committed" transaction. */
        ok1(tdb_exists(tdb, key));