netdev: Allow recv, recv_wait, drain, send, send_wait to be null.
[sliver-openvswitch.git] / lib / ovsdb-idl.c
index 4826d62..42c53b8 100644 (file)
@@ -541,10 +541,41 @@ ovsdb_idl_row_update(struct ovsdb_idl_row *row, const struct json *row_json)
     }
 }
 
+/* When a row A refers to row B through a column with a "refTable" constraint,
+ * but row B does not exist, row B is called an "orphan row".  Orphan rows
+ * should not persist, because the database enforces referential integrity, but
+ * they can appear transiently as changes from the database are received (the
+ * database doesn't try to topologically sort them and circular references mean
+ * it isn't always possible anyhow).
+ *
+ * This function returns true if 'row' is an orphan row, otherwise false.
+ */
 static bool
 ovsdb_idl_row_is_orphan(const struct ovsdb_idl_row *row)
 {
-    return !row->old;
+    return !row->old && !row->new;
+}
+
+/* Returns true if 'row' is conceptually part of the database as modified by
+ * the current transaction (if any), false otherwise.
+ *
+ * This function will return true if 'row' is not an orphan (see the comment on
+ * ovsdb_idl_row_is_orphan()) and:
+ *
+ *   - 'row' exists in the database and has not been deleted within the
+ *     current transaction (if any).
+ *
+ *   - 'row' was inserted within the current transaction and has not been
+ *     deleted.  (In the latter case you should not have passed 'row' in at
+ *     all, because ovsdb_idl_txn_delete() freed it.)
+ *
+ * This function will return false if 'row' is an orphan or if 'row' was
+ * deleted within the current transaction.
+ */
+static bool
+ovsdb_idl_row_exists(const struct ovsdb_idl_row *row)
+{
+    return row->new != NULL;
 }
 
 static void
@@ -810,7 +841,7 @@ next_real_row(struct ovsdb_idl_table *table, struct hmap_node *node)
         struct ovsdb_idl_row *row;
 
         row = CONTAINER_OF(node, struct ovsdb_idl_row, hmap_node);
-        if (row->new || !ovsdb_idl_row_is_orphan(row)) {
+        if (ovsdb_idl_row_exists(row)) {
             return row;
         }
     }
@@ -883,13 +914,22 @@ ovsdb_idl_txn_create(struct ovsdb_idl *idl)
     return txn;
 }
 
+/* Appends 's', which is treated as a printf()-type format string, to the
+ * comments that will be passed to the OVSDB server when 'txn' is committed.
+ * (The comment will be committed to the OVSDB log, which "ovsdb-tool
+ * show-log" can print in a relatively human-readable form.) */
 void
-ovsdb_idl_txn_add_comment(struct ovsdb_idl_txn *txn, const char *s)
+ovsdb_idl_txn_add_comment(struct ovsdb_idl_txn *txn, const char *s, ...)
 {
+    va_list args;
+
     if (txn->comment.length) {
         ds_put_char(&txn->comment, '\n');
     }
-    ds_put_cstr(&txn->comment, s);
+
+    va_start(args, s);
+    ds_put_format_valist(&txn->comment, s, args);
+    va_end(args);
 }
 
 void
@@ -1233,6 +1273,23 @@ ovsdb_idl_txn_commit(struct ovsdb_idl_txn *txn)
     return txn->status;
 }
 
+/* Attempts to commit 'txn', blocking until the commit either succeeds or
+ * fails.  Returns the final commit status, which may be any TXN_* value other
+ * than TXN_INCOMPLETE. */
+enum ovsdb_idl_txn_status
+ovsdb_idl_txn_commit_block(struct ovsdb_idl_txn *txn)
+{
+    enum ovsdb_idl_txn_status status;
+
+    while ((status = ovsdb_idl_txn_commit(txn)) == TXN_INCOMPLETE) {
+        ovsdb_idl_run(txn->idl);
+        ovsdb_idl_wait(txn->idl);
+        ovsdb_idl_txn_wait(txn);
+        poll_block();
+    }
+    return status;
+}
+
 int64_t
 ovsdb_idl_txn_get_increment_new_value(const struct ovsdb_idl_txn *txn)
 {
@@ -1633,3 +1690,10 @@ ovsdb_idl_txn_get(const struct ovsdb_idl_row *row)
     assert(txn != NULL);
     return txn;
 }
+
+struct ovsdb_idl *
+ovsdb_idl_txn_get_idl (struct ovsdb_idl_txn *txn)
+{
+    return txn->idl;
+}
+