ofproto: Fix potential leak during flow mods.
[sliver-openvswitch.git] / lib / ovsdb-idl.c
index 0cb0759..7556b7f 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009, 2010, 2011, 2012 Nicira, Inc.
+/* Copyright (c) 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -91,7 +91,6 @@ struct ovsdb_idl_txn {
     char *error;
     bool dry_run;
     struct ds comment;
-    unsigned int commit_seqno;
 
     /* Increments. */
     const char *inc_table;
@@ -157,6 +156,9 @@ static void ovsdb_idl_parse_lock_notify(struct ovsdb_idl *,
  * 'class'.  (Ordinarily 'class' is compiled from an OVSDB schema automatically
  * by ovsdb-idlc.)
  *
+ * Passes 'retry' to jsonrpc_session_open().  See that function for
+ * documentation.
+ *
  * If 'monitor_everything_by_default' is true, then everything in the remote
  * database will be replicated by default.  ovsdb_idl_omit() and
  * ovsdb_idl_omit_alert() may be used to selectively drop some columns from
@@ -168,7 +170,7 @@ static void ovsdb_idl_parse_lock_notify(struct ovsdb_idl *,
  */
 struct ovsdb_idl *
 ovsdb_idl_create(const char *remote, const struct ovsdb_idl_class *class,
-                 bool monitor_everything_by_default)
+                 bool monitor_everything_by_default, bool retry)
 {
     struct ovsdb_idl *idl;
     uint8_t default_mode;
@@ -180,7 +182,7 @@ ovsdb_idl_create(const char *remote, const struct ovsdb_idl_class *class,
 
     idl = xzalloc(sizeof *idl);
     idl->class = class;
-    idl->session = jsonrpc_session_open(remote);
+    idl->session = jsonrpc_session_open(remote, retry);
     shash_init(&idl->table_by_name);
     idl->tables = xmalloc(class->n_tables * sizeof *idl->tables);
     for (i = 0; i < class->n_tables; i++) {
@@ -330,9 +332,6 @@ ovsdb_idl_run(struct ovsdb_idl *idl)
                    && !strcmp(msg->method, "stolen")) {
             /* Someone else stole our lock. */
             ovsdb_idl_parse_lock_notify(idl, msg->params, false);
-        } else if (msg->type == JSONRPC_REPLY && msg->id->type == JSON_STRING
-                   && !strcmp(msg->id->u.string, "echo")) {
-            /* Reply to our echo request.  Ignore it. */
         } else if ((msg->type == JSONRPC_ERROR
                     || msg->type == JSONRPC_REPLY)
                    && ovsdb_idl_txn_process_reply(idl, msg)) {
@@ -395,6 +394,14 @@ ovsdb_idl_has_ever_connected(const struct ovsdb_idl *idl)
     return ovsdb_idl_get_seqno(idl) != 0;
 }
 
+/* Reconfigures 'idl' so that it would reconnect to the database, if
+ * connection was dropped. */
+void
+ovsdb_idl_enable_reconnect(struct ovsdb_idl *idl)
+{
+    jsonrpc_session_enable_reconnect(idl->session);
+}
+
 /* Forces 'idl' to drop its connection to the database and reconnect.  In the
  * meantime, the contents of 'idl' will not change. */
 void
@@ -412,6 +419,18 @@ ovsdb_idl_verify_write_only(struct ovsdb_idl *idl)
 {
     idl->verify_write_only = true;
 }
+
+bool
+ovsdb_idl_is_alive(const struct ovsdb_idl *idl)
+{
+    return jsonrpc_session_is_alive(idl->session);
+}
+
+int
+ovsdb_idl_get_last_error(const struct ovsdb_idl *idl)
+{
+    return jsonrpc_session_get_last_error(idl->session);
+}
 \f
 static unsigned char *
 ovsdb_idl_get_mode(struct ovsdb_idl *idl,
@@ -430,7 +449,7 @@ ovsdb_idl_get_mode(struct ovsdb_idl *idl,
         }
     }
 
-    NOT_REACHED();
+    OVS_NOT_REACHED();
 }
 
 static void
@@ -494,7 +513,7 @@ ovsdb_idl_add_table(struct ovsdb_idl *idl,
         }
     }
 
-    NOT_REACHED();
+    OVS_NOT_REACHED();
 }
 
 /* Turns off OVSDB_IDL_ALERT for 'column' in 'idl'.
@@ -1227,7 +1246,6 @@ ovsdb_idl_txn_create(struct ovsdb_idl *idl)
     txn->error = NULL;
     txn->dry_run = false;
     ds_init(&txn->comment);
-    txn->commit_seqno = txn->idl->change_seqno;
 
     txn->inc_table = NULL;
     txn->inc_column = NULL;
@@ -1826,10 +1844,10 @@ ovsdb_idl_txn_complete(struct ovsdb_idl_txn *txn,
  * Takes ownership of what 'datum' points to (and in some cases destroys that
  * data before returning) but makes a copy of 'datum' itself.  (Commonly
  * 'datum' is on the caller's stack.) */
-void
-ovsdb_idl_txn_write(const struct ovsdb_idl_row *row_,
-                    const struct ovsdb_idl_column *column,
-                    struct ovsdb_datum *datum)
+static void
+ovsdb_idl_txn_write__(const struct ovsdb_idl_row *row_,
+                      const struct ovsdb_idl_column *column,
+                      struct ovsdb_datum *datum, bool owns_datum)
 {
     struct ovsdb_idl_row *row = CONST_CAST(struct ovsdb_idl_row *, row_);
     const struct ovsdb_idl_table_class *class;
@@ -1837,8 +1855,7 @@ ovsdb_idl_txn_write(const struct ovsdb_idl_row *row_,
     bool write_only;
 
     if (ovsdb_idl_row_is_synthetic(row)) {
-        ovsdb_datum_destroy(datum, &column->type);
-        return;
+        goto discard_datum;
     }
 
     class = row->table->class;
@@ -1853,8 +1870,7 @@ ovsdb_idl_txn_write(const struct ovsdb_idl_row *row_,
     if (row->table->idl->verify_write_only && !write_only) {
         VLOG_ERR("Bug: Attempt to write to a read/write column (%s:%s) when"
                  " explicitly configured not to.", class->name, column->name);
-        ovsdb_datum_destroy(datum, &column->type);
-        return;
+        goto discard_datum;
     }
 
     /* If this is a write-only column and the datum being written is the same
@@ -1870,8 +1886,7 @@ ovsdb_idl_txn_write(const struct ovsdb_idl_row *row_,
      * ovsdb_idl_txn_commit().) */
     if (write_only && ovsdb_datum_equals(ovsdb_idl_read(row, column),
                                          datum, &column->type)) {
-        ovsdb_datum_destroy(datum, &column->type);
-        return;
+        goto discard_datum;
     }
 
     if (hmap_node_is_null(&row->txn_node)) {
@@ -1889,9 +1904,36 @@ ovsdb_idl_txn_write(const struct ovsdb_idl_row *row_,
     } else {
         bitmap_set1(row->written, column_idx);
     }
-    row->new[column_idx] = *datum;
+    if (owns_datum) {
+        row->new[column_idx] = *datum;
+    } else {
+        ovsdb_datum_clone(&row->new[column_idx], datum, &column->type);
+    }
     (column->unparse)(row);
     (column->parse)(row, &row->new[column_idx]);
+    return;
+
+discard_datum:
+    if (owns_datum) {
+        ovsdb_datum_destroy(datum, &column->type);
+    }
+}
+
+void
+ovsdb_idl_txn_write(const struct ovsdb_idl_row *row,
+                    const struct ovsdb_idl_column *column,
+                    struct ovsdb_datum *datum)
+{
+    ovsdb_idl_txn_write__(row, column, datum, true);
+}
+
+void
+ovsdb_idl_txn_write_clone(const struct ovsdb_idl_row *row,
+                          const struct ovsdb_idl_column *column,
+                          const struct ovsdb_datum *datum)
+{
+    ovsdb_idl_txn_write__(row, column,
+                          CONST_CAST(struct ovsdb_datum *, datum), false);
 }
 
 /* Causes the original contents of 'column' in 'row_' to be verified as a
@@ -2071,7 +2113,7 @@ ovsdb_idl_txn_process_inc_reply(struct ovsdb_idl_txn *txn,
 
     if (txn->inc_index + 2 > results->n) {
         VLOG_WARN_RL(&syntax_rl, "reply does not contain enough operations "
-                     "for increment (has %zu, needs %u)",
+                     "for increment (has %"PRIuSIZE", needs %u)",
                      results->n, txn->inc_index + 2);
         return false;
     }
@@ -2096,7 +2138,7 @@ ovsdb_idl_txn_process_inc_reply(struct ovsdb_idl_txn *txn,
         return false;
     }
     if (rows->u.array.n != 1) {
-        VLOG_WARN_RL(&syntax_rl, "\"select\" reply \"rows\" has %zu elements "
+        VLOG_WARN_RL(&syntax_rl, "\"select\" reply \"rows\" has %"PRIuSIZE" elements "
                      "instead of 1",
                      rows->u.array.n);
         return false;
@@ -2126,7 +2168,7 @@ ovsdb_idl_txn_process_insert_reply(struct ovsdb_idl_txn_insert *insert,
 
     if (insert->op_index >= results->n) {
         VLOG_WARN_RL(&syntax_rl, "reply does not contain enough operations "
-                     "for insert (has %zu, needs %u)",
+                     "for insert (has %"PRIuSIZE", needs %u)",
                      results->n, insert->op_index);
         return false;
     }
@@ -2145,6 +2187,7 @@ ovsdb_idl_txn_process_insert_reply(struct ovsdb_idl_txn_insert *insert,
         VLOG_WARN_RL(&syntax_rl, "\"insert\" reply \"uuid\" is not a JSON "
                      "UUID: %s", s);
         free(s);
+        ovsdb_error_destroy(error);
         return false;
     }