*
* - A row modified by a transaction will have non-null 'old' and 'new'.
*
- * - 'old' and 'new' both null is invalid. It would indicate that a row
- * was added then deleted within a single transaction, but we instead
- * handle that case by deleting the txn_row entirely.
+ * - 'old' and 'new' both null indicates that a row was added then deleted
+ * within a single transaction. Most of the time we instead delete the
+ * ovsdb_txn_row entirely, but inside a for_each_txn_row() callback
+ * there are restrictions that sometimes mean we have to leave the
+ * ovsdb_txn_row in place.
*/
struct ovsdb_txn_row {
struct hmap_node hmap_node; /* In ovsdb_txn_table's txn_rows hmap. */
struct ovsdb_row *new; /* The new row. */
size_t n_refs; /* Number of remaining references. */
+ /* These members are the same as the corresponding members of 'old' or
+ * 'new'. They are present here for convenience and because occasionally
+ * there can be an ovsdb_txn_row where both 'old' and 'new' are NULL. */
+ struct uuid uuid;
+ struct ovsdb_table *table;
+
/* Used by for_each_txn_row(). */
unsigned int serial; /* Serial number of in-progress commit. */
ovsdb_txn_row_prefree(txn_row);
if (!old) {
- hmap_remove(&new->table->rows, &new->hmap_node);
+ if (new) {
+ hmap_remove(&new->table->rows, &new->hmap_node);
+ }
} else if (!new) {
hmap_insert(&old->table->rows, &old->hmap_node, ovsdb_row_hash(old));
} else {
HMAP_FOR_EACH_WITH_HASH (txn_row, hmap_node,
uuid_hash(uuid), &table->txn_table->txn_rows) {
- const struct ovsdb_row *row;
-
- row = txn_row->old ? txn_row->old : txn_row->new;
- if (uuid_equals(uuid, ovsdb_row_get_uuid(row))) {
+ if (uuid_equals(uuid, &txn_row->uuid)) {
return txn_row;
}
}
static struct ovsdb_error * WARN_UNUSED_RESULT
update_row_ref_count(struct ovsdb_txn *txn, struct ovsdb_txn_row *r)
{
- struct ovsdb_table *table = r->old ? r->old->table : r->new->table;
+ struct ovsdb_table *table = r->table;
struct shash_node *node;
SHASH_FOR_EACH (node, &table->schema->columns) {
return ovsdb_error("referential integrity violation",
"cannot delete %s row "UUID_FMT" because "
"of %zu remaining reference(s)",
- r->old->table->schema->name,
- UUID_ARGS(ovsdb_row_get_uuid(r->old)),
+ r->table->schema->name, UUID_ARGS(&r->uuid),
r->n_refs);
}
}
return NULL;
}
- table = txn_row->new->table;
+ table = txn_row->table;
SHASH_FOR_EACH (node, &table->schema->columns) {
const struct ovsdb_column *column = node->data;
struct ovsdb_datum *datum = &txn_row->new->fields[column->index];
static struct ovsdb_error * WARN_UNUSED_RESULT
determine_changes(struct ovsdb_txn *txn, struct ovsdb_txn_row *txn_row)
{
- struct ovsdb_table *table;
+ struct ovsdb_table *table = txn_row->table;
- table = (txn_row->old ? txn_row->old : txn_row->new)->table;
if (txn_row->old && txn_row->new) {
struct shash_node *node;
bool changed = false;
LIST_FOR_EACH (t, node, &txn->txn_tables) {
HMAP_FOR_EACH (r, hmap_node, &t->txn_rows) {
- if (!cb(r->old, r->new, r->changed, aux)) {
+ if ((r->old || r->new) && !cb(r->old, r->new, r->changed, aux)) {
break;
}
}
ovsdb_txn_row_create(struct ovsdb_txn *txn, struct ovsdb_table *table,
const struct ovsdb_row *old_, struct ovsdb_row *new)
{
+ const struct ovsdb_row *row = old_ ? old_ : new;
struct ovsdb_row *old = (struct ovsdb_row *) old_;
size_t n_columns = shash_count(&table->schema->columns);
struct ovsdb_txn_table *txn_table;
txn_row = xzalloc(offsetof(struct ovsdb_txn_row, changed)
+ bitmap_n_bytes(n_columns));
- txn_row->old = (struct ovsdb_row *) old;
+ txn_row->uuid = *ovsdb_row_get_uuid(row);
+ txn_row->table = row->table;
+ txn_row->old = old;
txn_row->new = new;
txn_row->n_refs = old ? old->n_refs : 0;
txn_row->serial = serial - 1;
static void
ovsdb_txn_row_prefree(struct ovsdb_txn_row *txn_row)
{
- struct ovsdb_row *row = txn_row->old ? txn_row->old : txn_row->new;
- struct ovsdb_txn_table *txn_table = row->table->txn_table;
+ struct ovsdb_txn_table *txn_table = txn_row->table->txn_table;
txn_table->n_processed--;
hmap_remove(&txn_table->txn_rows, &txn_row->hmap_node);
* in within the same txn_table. It may *not* delete any txn_tables. As long
* as these rules are followed, 'cb' will be called exactly once for each
* txn_row in 'txn', even those added by 'cb'.
+ *
+ * (Even though 'cb' is not allowed to delete some txn_rows, it can still
+ * delete any actual row by clearing a txn_row's 'new' member.)
*/
static struct ovsdb_error * WARN_UNUSED_RESULT
for_each_txn_row(struct ovsdb_txn *txn,