ovsdb-idl: On transaction hard failure make a reason available to client.
authorBen Pfaff <blp@nicira.com>
Fri, 5 Feb 2010 22:11:12 +0000 (14:11 -0800)
committerBen Pfaff <blp@nicira.com>
Mon, 8 Feb 2010 22:16:18 +0000 (14:16 -0800)
This make ovs-vsctl able to report problems that occur in better detail.

lib/ovsdb-idl.c
lib/ovsdb-idl.h
utilities/ovs-vsctl.c

index 2051000..a0b0cc9 100644 (file)
@@ -81,6 +81,7 @@ struct ovsdb_idl_txn {
     struct ovsdb_idl *idl;
     struct hmap txn_rows;
     enum ovsdb_idl_txn_status status;
+    char *error;
     bool dry_run;
     struct ds comment;
 
@@ -867,6 +868,7 @@ ovsdb_idl_txn_create(struct ovsdb_idl *idl)
     txn->idl = idl;
     hmap_init(&txn->txn_rows);
     txn->status = TXN_INCOMPLETE;
+    txn->error = NULL;
     txn->dry_run = false;
     ds_init(&txn->comment);
 
@@ -915,6 +917,7 @@ ovsdb_idl_txn_destroy(struct ovsdb_idl_txn *txn)
     }
     ovsdb_idl_txn_abort(txn);
     ds_destroy(&txn->comment);
+    free(txn->error);
     free(txn->inc_table);
     free(txn->inc_column);
     json_destroy(txn->inc_where);
@@ -1253,6 +1256,27 @@ ovsdb_idl_txn_abort(struct ovsdb_idl_txn *txn)
     }
 }
 
+const char *
+ovsdb_idl_txn_get_error(const struct ovsdb_idl_txn *txn)
+{
+    if (txn->status != TXN_ERROR) {
+        return ovsdb_idl_txn_status_to_string(txn->status);
+    } else if (txn->error) {
+        return txn->error;
+    } else {
+        return "no error details available";
+    }
+}
+
+static void
+ovsdb_idl_txn_set_error_json(struct ovsdb_idl_txn *txn,
+                             const struct json *json)
+{
+    if (txn->error == NULL) {
+        txn->error = json_to_string(json, JSSF_SORT);
+    }
+}
+
 /* For transaction 'txn' that completed successfully, finds and returns the
  * permanent UUID that the database assigned to a newly inserted row, given the
  * 'uuid' that ovsdb_idl_txn_insert() assigned locally to that row.
@@ -1566,15 +1590,18 @@ ovsdb_idl_txn_process_reply(struct ovsdb_idl *idl,
                             soft_errors++;
                         } else if (strcmp(error->u.string, "aborted")) {
                             hard_errors++;
+                            ovsdb_idl_txn_set_error_json(txn, op);
                         }
                     } else {
                         hard_errors++;
+                        ovsdb_idl_txn_set_error_json(txn, op);
                         VLOG_WARN_RL(&syntax_rl,
                                      "\"error\" in reply is not JSON string");
                     }
                 }
             } else {
                 hard_errors++;
+                ovsdb_idl_txn_set_error_json(txn, op);
                 VLOG_WARN_RL(&syntax_rl,
                              "operation reply is not JSON null or object");
             }
index 3b8582d..d451427 100644 (file)
@@ -67,6 +67,8 @@ void ovsdb_idl_txn_wait(const struct ovsdb_idl_txn *);
 enum ovsdb_idl_txn_status ovsdb_idl_txn_commit(struct ovsdb_idl_txn *);
 void ovsdb_idl_txn_abort(struct ovsdb_idl_txn *);
 
+const char *ovsdb_idl_txn_get_error(const struct ovsdb_idl_txn *);
+
 int64_t ovsdb_idl_txn_get_increment_new_value(const struct ovsdb_idl_txn *);
 const struct uuid *ovsdb_idl_txn_get_insert_uuid(const struct ovsdb_idl_txn *,
                                                  const struct uuid *);
index 8ee18d7..af90100 100644 (file)
@@ -2479,6 +2479,7 @@ do_vsctl(const char *args, struct vsctl_command *commands, size_t n_commands,
     struct vsctl_command *c;
     int64_t next_cfg = 0;
     char *comment;
+    char *error;
 
     txn = the_idl_txn = ovsdb_idl_txn_create(idl);
     if (dry_run) {
@@ -2528,6 +2529,7 @@ do_vsctl(const char *args, struct vsctl_command *commands, size_t n_commands,
             vsctl_context_done(&ctx, c);
         }
     }
+    error = xstrdup(ovsdb_idl_txn_get_error(txn));
     ovsdb_idl_txn_destroy(txn);
     the_idl_txn = NULL;
 
@@ -2547,14 +2549,16 @@ do_vsctl(const char *args, struct vsctl_command *commands, size_t n_commands,
         for (c = commands; c < &commands[n_commands]; c++) {
             ds_destroy(&c->output);
         }
+        free(error);
         return;
 
     case TXN_ERROR:
-        vsctl_fatal("transaction error");
+        vsctl_fatal("transaction error: %s", error);
 
     default:
         NOT_REACHED();
     }
+    free(error);
 
     for (c = commands; c < &commands[n_commands]; c++) {
         struct ds *ds = &c->output;