#include "ovsdb-data.h"
#include "ovsdb-error.h"
#include "ovsdb-idl-provider.h"
+#include "poll-loop.h"
#include "shash.h"
#include "util.h"
struct ovsdb_idl *idl;
struct hmap txn_rows;
enum ovsdb_idl_txn_status status;
+ bool dry_run;
};
static struct vlog_rate_limit syntax_rl = VLOG_RATE_LIMIT_INIT(1, 5);
{
int i;
+ assert(!idl->txn);
jsonrpc_session_run(idl->session);
for (i = 0; jsonrpc_session_is_connected(idl->session) && i < 50; i++) {
struct jsonrpc_msg *msg, *reply;
static struct ovsdb_idl_row *
ovsdb_idl_row_create__(const struct ovsdb_idl_table_class *class)
{
- struct ovsdb_idl_row *row = xmalloc(class->allocation_size);
+ struct ovsdb_idl_row *row = xzalloc(class->allocation_size);
memset(row, 0, sizeof *row);
list_init(&row->src_arcs);
list_init(&row->dst_arcs);
txn->idl = idl;
txn->status = TXN_INCOMPLETE;
hmap_init(&txn->txn_rows);
+ txn->dry_run = false;
return txn;
}
+void
+ovsdb_idl_txn_set_dry_run(struct ovsdb_idl_txn *txn)
+{
+ txn->dry_run = true;
+}
+
void
ovsdb_idl_txn_destroy(struct ovsdb_idl_txn *txn)
{
free(txn);
}
+void
+ovsdb_idl_txn_wait(const struct ovsdb_idl_txn *txn)
+{
+ if (txn->status != TXN_INCOMPLETE) {
+ poll_immediate_wake();
+ }
+}
+
static struct json *
where_uuid_equals(const struct uuid *uuid)
{
HMAP_FOR_EACH_SAFE (row, next, struct ovsdb_idl_row, txn_node,
&txn->txn_rows) {
+ if (row->old && row->written) {
+ (row->table->class->unparse)(row);
+ ovsdb_idl_row_clear_arcs(row, false);
+ (row->table->class->parse)(row);
+ }
ovsdb_idl_row_clear_new(row);
free(row->prereqs);
struct ovsdb_idl_row *row;
struct json *operations;
bool any_updates;
- enum ovsdb_idl_txn_status status;
if (txn != txn->idl->txn) {
return txn->status;
any_updates = false;
HMAP_FOR_EACH (row, struct ovsdb_idl_row, txn_node, &txn->txn_rows) {
const struct ovsdb_idl_table_class *class = row->table->class;
- size_t n_columns = class->n_columns;
- struct json *row_json;
- size_t idx;
if (row->old == row->new) {
continue;
json_object_put_string(op, "table", class->name);
json_object_put(op, "where", where_uuid_equals(&row->uuid));
json_array_add(operations, op);
+ any_updates = true;
} else {
- row_json = NULL;
- BITMAP_FOR_EACH_1 (idx, n_columns, row->written) {
+ struct json *row_json;
+ struct json *op;
+ size_t idx;
+
+ op = json_object_create();
+ json_object_put_string(op, "op", row->old ? "update" : "insert");
+ json_object_put_string(op, "table", class->name);
+ if (row->old) {
+ json_object_put(op, "where", where_uuid_equals(&row->uuid));
+ } else {
+ json_object_put(op, "uuid-name",
+ json_string_create_nocopy(
+ uuid_name_from_uuid(&row->uuid)));
+ }
+ row_json = json_object_create();
+ json_object_put(op, "row", row_json);
+
+ BITMAP_FOR_EACH_1 (idx, class->n_columns, row->written) {
const struct ovsdb_idl_column *column = &class->columns[idx];
- if (row->old
- && ovsdb_datum_equals(&row->old[idx], &row->new[idx],
- &column->type)) {
- continue;
+ if (!row->old || !ovsdb_datum_equals(&row->old[idx],
+ &row->new[idx],
+ &column->type)) {
+ json_object_put(row_json, column->name,
+ substitute_uuids(
+ ovsdb_datum_to_json(&row->new[idx],
+ &column->type),
+ txn));
}
- if (!row_json) {
- struct json *op = json_object_create();
- json_array_add(operations, op);
- json_object_put_string(op, "op",
- row->old ? "update" : "insert");
- json_object_put_string(op, "table", class->name);
- if (row->old) {
- json_object_put(op, "where",
- where_uuid_equals(&row->uuid));
- } else {
- json_object_put(op, "uuid-name",
- json_string_create_nocopy(
- uuid_name_from_uuid(&row->uuid)));
- }
- row_json = json_object_create();
- json_object_put(op, "row", row_json);
- any_updates = true;
- }
- json_object_put(row_json, column->name,
- substitute_uuids(
- ovsdb_datum_to_json(&row->new[idx],
- &column->type),
- txn));
+ }
+
+ if (!row->old || !shash_is_empty(json_object(row_json))) {
+ json_array_add(operations, op);
+ any_updates = true;
+ } else {
+ json_destroy(op);
}
}
}
- status = (!any_updates ? TXN_SUCCESS
- : jsonrpc_session_send(
- txn->idl->session,
- jsonrpc_create_request(
- "transact", operations, &txn->request_id))
- ? TXN_TRY_AGAIN
- : TXN_INCOMPLETE);
+ if (txn->dry_run) {
+ struct json *op = json_object_create();
+ json_object_put_string(op, "op", "abort");
+ json_array_add(operations, op);
+ }
- hmap_insert(&txn->idl->outstanding_txns, &txn->hmap_node,
- json_hash(txn->request_id, 0));
- txn->idl->txn = NULL;
+ if (!any_updates) {
+ txn->status = TXN_SUCCESS;
+ } else if (!jsonrpc_session_send(
+ txn->idl->session,
+ jsonrpc_create_request(
+ "transact", operations, &txn->request_id))) {
+ hmap_insert(&txn->idl->outstanding_txns, &txn->hmap_node,
+ json_hash(txn->request_id, 0));
+ } else {
+ txn->status = TXN_INCOMPLETE;
+ }
+ txn->idl->txn = NULL;
ovsdb_idl_txn_disassemble(txn);
- if (status != TXN_INCOMPLETE) {
- ovsdb_idl_txn_complete(txn, status);
- }
return txn->status;
}
hmap_insert(&row->table->idl->txn->txn_rows, &row->txn_node,
uuid_hash(&row->uuid));
}
- if (row->new == row->old) {
- row->new = NULL;
- } else {
- ovsdb_idl_row_clear_new(row);
- }
+ ovsdb_idl_row_clear_new(row);
+ row->new = NULL;
}
struct ovsdb_idl_row *
if (error->type == JSON_STRING) {
if (!strcmp(error->u.string, "timed out")) {
soft_errors++;
- } else {
+ } else if (strcmp(error->u.string, "aborted")) {
hard_errors++;
}
} else {
ovsdb_idl_txn_complete(txn, status);
return true;
}
+
+struct ovsdb_idl_txn *
+ovsdb_idl_txn_get(const struct ovsdb_idl_row *row)
+{
+ struct ovsdb_idl_txn *txn = row->table->idl->txn;
+ assert(txn != NULL);
+ return txn;
+}