The state machine didn't have a proper state for "not yet committed or
aborted", which meant that destroying an ovsdb_idl_txn without committing
or aborting it caused a segfault. This fixes the problem by adding a new
state TXN_UNCOMMITTED to the state machine.
This is related to commit
79554078d "ovsdb-idl: Fix bad logic in
ovsdb_idl_txn_commit() state transitions", which fixed a related bug.
Bug #2438.
ovsdb_idl_txn_status_to_string(enum ovsdb_idl_txn_status status)
{
switch (status) {
+ case TXN_UNCOMMITTED:
+ return "uncommitted";
case TXN_UNCHANGED:
return "unchanged";
case TXN_INCOMPLETE:
txn->request_id = NULL;
txn->idl = idl;
hmap_init(&txn->txn_rows);
- txn->status = TXN_INCOMPLETE;
+ txn->status = TXN_UNCOMMITTED;
txn->error = NULL;
txn->dry_run = false;
ds_init(&txn->comment);
void
ovsdb_idl_txn_wait(const struct ovsdb_idl_txn *txn)
{
- if (txn->status != TXN_INCOMPLETE) {
+ if (txn->status != TXN_UNCOMMITTED && txn->status != TXN_INCOMPLETE) {
poll_immediate_wake();
}
}
"transact", operations, &txn->request_id))) {
hmap_insert(&txn->idl->outstanding_txns, &txn->hmap_node,
json_hash(txn->request_id, 0));
+ txn->status = TXN_INCOMPLETE;
} else {
txn->status = TXN_TRY_AGAIN;
}
ovsdb_idl_txn_abort(struct ovsdb_idl_txn *txn)
{
ovsdb_idl_txn_disassemble(txn);
- if (txn->status == TXN_INCOMPLETE) {
+ if (txn->status == TXN_UNCOMMITTED || txn->status == TXN_INCOMPLETE) {
txn->status = TXN_ABORTED;
}
}
/* Transactions. */
enum ovsdb_idl_txn_status {
+ TXN_UNCOMMITTED, /* Not yet committed or aborted. */
TXN_UNCHANGED, /* Transaction didn't include any changes. */
TXN_INCOMPLETE, /* Commit in progress, please wait. */
TXN_ABORTED, /* ovsdb_idl_txn_abort() called. */
003: done
]])
+OVSDB_CHECK_IDL([simple idl, aborting],
+ [['["idltest",
+ {"op": "insert",
+ "table": "simple",
+ "row": {}}]']],
+ [['set 0 r 2.0, abort' \
+'+set 0 b 1']],
+ [[000: i=0 r=0 b=false s= u=<0> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<1>
+001: commit, status=aborted
+002: commit, status=success
+003: i=0 r=0 b=true s= u=<0> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<1>
+004: done
+]])
+
+OVSDB_CHECK_IDL([simple idl, destroy without commit or abort],
+ [['["idltest",
+ {"op": "insert",
+ "table": "simple",
+ "row": {}}]']],
+ [['set 0 r 2.0, destroy' \
+'+set 0 b 1']],
+ [[000: i=0 r=0 b=false s= u=<0> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<1>
+001: destroy
+002: commit, status=success
+003: i=0 r=0 b=true s= u=<0> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<1>
+004: done
+]])
+
OVSDB_CHECK_IDL([self-linking idl, consistent ops],
[],
[['["idltest",
}
ovsdb_idl_txn_increment(txn, arg1, arg2, NULL);
increment = true;
+ } else if (!strcmp(name, "abort")) {
+ ovsdb_idl_txn_abort(txn);
+ break;
+ } else if (!strcmp(name, "destroy")) {
+ printf("%03d: destroy\n", step);
+ ovsdb_idl_txn_destroy(txn);
+ return;
} else {
ovs_fatal(0, "unknown command %s", name);
}
txn = the_idl_txn = NULL;
switch (status) {
+ case TXN_UNCOMMITTED:
case TXN_INCOMPLETE:
NOT_REACHED();