LCOV - code coverage report
Current view: top level - lib - ovsdb-idl.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 1402 1605 87.4 %
Date: 2016-09-14 01:02:56 Functions: 168 180 93.3 %
Branches: 733 1034 70.9 %

           Branch data     Line data    Source code
       1                 :            : /* Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016 Nicira, Inc.
       2                 :            :  *
       3                 :            :  * Licensed under the Apache License, Version 2.0 (the "License");
       4                 :            :  * you may not use this file except in compliance with the License.
       5                 :            :  * You may obtain a copy of the License at:
       6                 :            :  *
       7                 :            :  *     http://www.apache.org/licenses/LICENSE-2.0
       8                 :            :  *
       9                 :            :  * Unless required by applicable law or agreed to in writing, software
      10                 :            :  * distributed under the License is distributed on an "AS IS" BASIS,
      11                 :            :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      12                 :            :  * See the License for the specific language governing permissions and
      13                 :            :  * limitations under the License.
      14                 :            :  */
      15                 :            : 
      16                 :            : #include <config.h>
      17                 :            : 
      18                 :            : #include "ovsdb-idl.h"
      19                 :            : 
      20                 :            : #include <errno.h>
      21                 :            : #include <inttypes.h>
      22                 :            : #include <limits.h>
      23                 :            : #include <stdlib.h>
      24                 :            : 
      25                 :            : #include "bitmap.h"
      26                 :            : #include "coverage.h"
      27                 :            : #include "openvswitch/dynamic-string.h"
      28                 :            : #include "fatal-signal.h"
      29                 :            : #include "openvswitch/json.h"
      30                 :            : #include "jsonrpc.h"
      31                 :            : #include "ovsdb/ovsdb.h"
      32                 :            : #include "ovsdb/table.h"
      33                 :            : #include "ovsdb-data.h"
      34                 :            : #include "ovsdb-error.h"
      35                 :            : #include "ovsdb-idl-provider.h"
      36                 :            : #include "ovsdb-parser.h"
      37                 :            : #include "poll-loop.h"
      38                 :            : #include "openvswitch/shash.h"
      39                 :            : #include "sset.h"
      40                 :            : #include "util.h"
      41                 :            : #include "openvswitch/vlog.h"
      42                 :            : 
      43                 :      15050 : VLOG_DEFINE_THIS_MODULE(ovsdb_idl);
      44                 :            : 
      45                 :      88364 : COVERAGE_DEFINE(txn_uncommitted);
      46                 :     194762 : COVERAGE_DEFINE(txn_unchanged);
      47                 :     171440 : COVERAGE_DEFINE(txn_incomplete);
      48                 :      88370 : COVERAGE_DEFINE(txn_aborted);
      49                 :     142322 : COVERAGE_DEFINE(txn_success);
      50                 :      88370 : COVERAGE_DEFINE(txn_try_again);
      51                 :      88364 : COVERAGE_DEFINE(txn_not_locked);
      52                 :      88364 : COVERAGE_DEFINE(txn_error);
      53                 :            : 
      54                 :            : /* An arc from one idl_row to another.  When row A contains a UUID that
      55                 :            :  * references row B, this is represented by an arc from A (the source) to B
      56                 :            :  * (the destination).
      57                 :            :  *
      58                 :            :  * Arcs from a row to itself are omitted, that is, src and dst are always
      59                 :            :  * different.
      60                 :            :  *
      61                 :            :  * Arcs are never duplicated, that is, even if there are multiple references
      62                 :            :  * from A to B, there is only a single arc from A to B.
      63                 :            :  *
      64                 :            :  * Arcs are directed: an arc from A to B is the converse of an an arc from B to
      65                 :            :  * A.  Both an arc and its converse may both be present, if each row refers
      66                 :            :  * to the other circularly.
      67                 :            :  *
      68                 :            :  * The source and destination row may be in the same table or in different
      69                 :            :  * tables.
      70                 :            :  */
      71                 :            : struct ovsdb_idl_arc {
      72                 :            :     struct ovs_list src_node;   /* In src->src_arcs list. */
      73                 :            :     struct ovs_list dst_node;   /* In dst->dst_arcs list. */
      74                 :            :     struct ovsdb_idl_row *src;  /* Source row. */
      75                 :            :     struct ovsdb_idl_row *dst;  /* Destination row. */
      76                 :            : };
      77                 :            : 
      78                 :            : enum ovsdb_idl_state {
      79                 :            :     IDL_S_SCHEMA_REQUESTED,
      80                 :            :     IDL_S_MONITOR_REQUESTED,
      81                 :            :     IDL_S_MONITORING,
      82                 :            :     IDL_S_MONITOR_COND_REQUESTED,
      83                 :            :     IDL_S_MONITORING_COND,
      84                 :            :     IDL_S_NO_SCHEMA
      85                 :            : };
      86                 :            : 
      87                 :            : struct ovsdb_idl {
      88                 :            :     const struct ovsdb_idl_class *class;
      89                 :            :     struct jsonrpc_session *session;
      90                 :            :     struct uuid uuid;
      91                 :            :     struct shash table_by_name;
      92                 :            :     struct ovsdb_idl_table *tables; /* Contains "struct ovsdb_idl_table *"s.*/
      93                 :            :     unsigned int change_seqno;
      94                 :            :     bool verify_write_only;
      95                 :            : 
      96                 :            :     /* Session state. */
      97                 :            :     unsigned int state_seqno;
      98                 :            :     enum ovsdb_idl_state state;
      99                 :            :     struct json *request_id;
     100                 :            :     struct json *schema;
     101                 :            : 
     102                 :            :     /* Database locking. */
     103                 :            :     char *lock_name;            /* Name of lock we need, NULL if none. */
     104                 :            :     bool has_lock;              /* Has db server told us we have the lock? */
     105                 :            :     bool is_lock_contended;     /* Has db server told us we can't get lock? */
     106                 :            :     struct json *lock_request_id; /* JSON-RPC ID of in-flight lock request. */
     107                 :            : 
     108                 :            :     /* Transaction support. */
     109                 :            :     struct ovsdb_idl_txn *txn;
     110                 :            :     struct hmap outstanding_txns;
     111                 :            :     bool cond_changed;
     112                 :            : };
     113                 :            : 
     114                 :            : struct ovsdb_idl_txn {
     115                 :            :     struct hmap_node hmap_node;
     116                 :            :     struct json *request_id;
     117                 :            :     struct ovsdb_idl *idl;
     118                 :            :     struct hmap txn_rows;
     119                 :            :     enum ovsdb_idl_txn_status status;
     120                 :            :     char *error;
     121                 :            :     bool dry_run;
     122                 :            :     struct ds comment;
     123                 :            : 
     124                 :            :     /* Increments. */
     125                 :            :     const char *inc_table;
     126                 :            :     const char *inc_column;
     127                 :            :     struct uuid inc_row;
     128                 :            :     bool inc_force;
     129                 :            :     unsigned int inc_index;
     130                 :            :     int64_t inc_new_value;
     131                 :            : 
     132                 :            :     /* Inserted rows. */
     133                 :            :     struct hmap inserted_rows;  /* Contains "struct ovsdb_idl_txn_insert"s. */
     134                 :            : };
     135                 :            : 
     136                 :            : struct ovsdb_idl_txn_insert {
     137                 :            :     struct hmap_node hmap_node; /* In struct ovsdb_idl_txn's inserted_rows. */
     138                 :            :     struct uuid dummy;          /* Dummy UUID used locally. */
     139                 :            :     int op_index;               /* Index into transaction's operation array. */
     140                 :            :     struct uuid real;           /* Real UUID used by database server. */
     141                 :            : };
     142                 :            : 
     143                 :            : enum ovsdb_update_version {
     144                 :            :     OVSDB_UPDATE,               /* RFC 7047 "update" method. */
     145                 :            :     OVSDB_UPDATE2               /* "update2" Extension to RFC 7047.
     146                 :            :                                    See ovsdb-server(1) for more information. */
     147                 :            : };
     148                 :            : 
     149                 :            : /* Name arrays indexed by 'enum ovsdb_update_version'. */
     150                 :            : static const char *table_updates_names[] = {"table_updates", "table_updates2"};
     151                 :            : static const char *table_update_names[] = {"table_update", "table_update2"};
     152                 :            : static const char *row_update_names[] = {"row_update", "row_update2"};
     153                 :            : 
     154                 :            : static struct vlog_rate_limit syntax_rl = VLOG_RATE_LIMIT_INIT(1, 5);
     155                 :            : static struct vlog_rate_limit semantic_rl = VLOG_RATE_LIMIT_INIT(1, 5);
     156                 :            : 
     157                 :            : static void ovsdb_idl_clear(struct ovsdb_idl *);
     158                 :            : static void ovsdb_idl_send_schema_request(struct ovsdb_idl *);
     159                 :            : static void ovsdb_idl_send_monitor_request(struct ovsdb_idl *);
     160                 :            : static void ovsdb_idl_send_monitor_cond_request(struct ovsdb_idl *);
     161                 :            : static void ovsdb_idl_parse_update(struct ovsdb_idl *, const struct json *,
     162                 :            :                                    enum ovsdb_update_version);
     163                 :            : static struct ovsdb_error *ovsdb_idl_parse_update__(struct ovsdb_idl *,
     164                 :            :                                                     const struct json *,
     165                 :            :                                                     enum ovsdb_update_version);
     166                 :            : static bool ovsdb_idl_process_update(struct ovsdb_idl_table *,
     167                 :            :                                      const struct uuid *,
     168                 :            :                                      const struct json *old,
     169                 :            :                                      const struct json *new);
     170                 :            : static bool ovsdb_idl_process_update2(struct ovsdb_idl_table *,
     171                 :            :                                       const struct uuid *,
     172                 :            :                                       const char *operation,
     173                 :            :                                       const struct json *row);
     174                 :            : static void ovsdb_idl_insert_row(struct ovsdb_idl_row *, const struct json *);
     175                 :            : static void ovsdb_idl_delete_row(struct ovsdb_idl_row *);
     176                 :            : static bool ovsdb_idl_modify_row(struct ovsdb_idl_row *, const struct json *);
     177                 :            : static bool ovsdb_idl_modify_row_by_diff(struct ovsdb_idl_row *,
     178                 :            :                                          const struct json *);
     179                 :            : 
     180                 :            : static bool ovsdb_idl_row_is_orphan(const struct ovsdb_idl_row *);
     181                 :            : static struct ovsdb_idl_row *ovsdb_idl_row_create__(
     182                 :            :     const struct ovsdb_idl_table_class *);
     183                 :            : static struct ovsdb_idl_row *ovsdb_idl_row_create(struct ovsdb_idl_table *,
     184                 :            :                                                   const struct uuid *);
     185                 :            : static void ovsdb_idl_row_destroy(struct ovsdb_idl_row *);
     186                 :            : static void ovsdb_idl_row_destroy_postprocess(struct ovsdb_idl *);
     187                 :            : static void ovsdb_idl_destroy_all_map_op_lists(struct ovsdb_idl_row *);
     188                 :            : static void ovsdb_idl_destroy_all_set_op_lists(struct ovsdb_idl_row *);
     189                 :            : 
     190                 :            : static void ovsdb_idl_row_parse(struct ovsdb_idl_row *);
     191                 :            : static void ovsdb_idl_row_unparse(struct ovsdb_idl_row *);
     192                 :            : static void ovsdb_idl_row_clear_old(struct ovsdb_idl_row *);
     193                 :            : static void ovsdb_idl_row_clear_new(struct ovsdb_idl_row *);
     194                 :            : static void ovsdb_idl_row_clear_arcs(struct ovsdb_idl_row *, bool destroy_dsts);
     195                 :            : 
     196                 :            : static void ovsdb_idl_txn_abort_all(struct ovsdb_idl *);
     197                 :            : static bool ovsdb_idl_txn_process_reply(struct ovsdb_idl *,
     198                 :            :                                         const struct jsonrpc_msg *msg);
     199                 :            : static bool ovsdb_idl_txn_extract_mutations(struct ovsdb_idl_row *,
     200                 :            :                                             struct json *);
     201                 :            : static void ovsdb_idl_txn_add_map_op(struct ovsdb_idl_row *,
     202                 :            :                                      const struct ovsdb_idl_column *,
     203                 :            :                                      struct ovsdb_datum *,
     204                 :            :                                      enum map_op_type);
     205                 :            : static void ovsdb_idl_txn_add_set_op(struct ovsdb_idl_row *,
     206                 :            :                                      const struct ovsdb_idl_column *,
     207                 :            :                                      struct ovsdb_datum *,
     208                 :            :                                      enum set_op_type);
     209                 :            : 
     210                 :            : static void ovsdb_idl_send_lock_request(struct ovsdb_idl *);
     211                 :            : static void ovsdb_idl_send_unlock_request(struct ovsdb_idl *);
     212                 :            : static void ovsdb_idl_parse_lock_reply(struct ovsdb_idl *,
     213                 :            :                                        const struct json *);
     214                 :            : static void ovsdb_idl_parse_lock_notify(struct ovsdb_idl *,
     215                 :            :                                         const struct json *params,
     216                 :            :                                         bool new_has_lock);
     217                 :            : static struct ovsdb_idl_table *
     218                 :            : ovsdb_idl_table_from_class(const struct ovsdb_idl *,
     219                 :            :                            const struct ovsdb_idl_table_class *);
     220                 :            : static bool ovsdb_idl_track_is_set(struct ovsdb_idl_table *table);
     221                 :            : static void ovsdb_idl_send_cond_change(struct ovsdb_idl *idl);
     222                 :            : static void ovsdb_idl_condition_init(struct ovsdb_idl_condition *cnd,
     223                 :            :                                      const struct ovsdb_idl_table_class *tc);
     224                 :            : 
     225                 :            : /* Creates and returns a connection to database 'remote', which should be in a
     226                 :            :  * form acceptable to jsonrpc_session_open().  The connection will maintain an
     227                 :            :  * in-memory replica of the remote database whose schema is described by
     228                 :            :  * 'class'.  (Ordinarily 'class' is compiled from an OVSDB schema automatically
     229                 :            :  * by ovsdb-idlc.)
     230                 :            :  *
     231                 :            :  * Passes 'retry' to jsonrpc_session_open().  See that function for
     232                 :            :  * documentation.
     233                 :            :  *
     234                 :            :  * If 'monitor_everything_by_default' is true, then everything in the remote
     235                 :            :  * database will be replicated by default.  ovsdb_idl_omit() and
     236                 :            :  * ovsdb_idl_omit_alert() may be used to selectively drop some columns from
     237                 :            :  * monitoring.
     238                 :            :  *
     239                 :            :  * If 'monitor_everything_by_default' is false, then no columns or tables will
     240                 :            :  * be replicated by default.  ovsdb_idl_add_column() and ovsdb_idl_add_table()
     241                 :            :  * must be used to choose some columns or tables to replicate.
     242                 :            :  */
     243                 :            : struct ovsdb_idl *
     244                 :       7158 : ovsdb_idl_create(const char *remote, const struct ovsdb_idl_class *class,
     245                 :            :                  bool monitor_everything_by_default, bool retry)
     246                 :            : {
     247                 :            :     struct ovsdb_idl *idl;
     248                 :            :     uint8_t default_mode;
     249                 :            :     size_t i;
     250                 :            : 
     251         [ +  + ]:       7158 :     default_mode = (monitor_everything_by_default
     252                 :            :                     ? OVSDB_IDL_MONITOR | OVSDB_IDL_ALERT
     253                 :            :                     : 0);
     254                 :            : 
     255                 :       7158 :     idl = xzalloc(sizeof *idl);
     256                 :       7158 :     idl->class = class;
     257                 :       7158 :     idl->session = jsonrpc_session_open(remote, retry);
     258                 :       7158 :     shash_init(&idl->table_by_name);
     259                 :       7158 :     idl->tables = xmalloc(class->n_tables * sizeof *idl->tables);
     260         [ +  + ]:     116923 :     for (i = 0; i < class->n_tables; i++) {
     261                 :     109765 :         const struct ovsdb_idl_table_class *tc = &class->tables[i];
     262                 :     109765 :         struct ovsdb_idl_table *table = &idl->tables[i];
     263                 :            :         size_t j;
     264                 :            : 
     265                 :     109765 :         shash_add_assert(&idl->table_by_name, tc->name, table);
     266                 :     109765 :         table->class = tc;
     267                 :     109765 :         table->modes = xmalloc(tc->n_columns);
     268                 :     109765 :         memset(table->modes, default_mode, tc->n_columns);
     269                 :     109765 :         table->need_table = false;
     270                 :     109765 :         shash_init(&table->columns);
     271         [ +  + ]:    1113287 :         for (j = 0; j < tc->n_columns; j++) {
     272                 :    1003522 :             const struct ovsdb_idl_column *column = &tc->columns[j];
     273                 :            : 
     274                 :    1003522 :             shash_add_assert(&table->columns, column->name, column);
     275                 :            :         }
     276                 :     109765 :         hmap_init(&table->rows);
     277                 :     109765 :         ovs_list_init(&table->track_list);
     278                 :            :         table->change_seqno[OVSDB_IDL_CHANGE_INSERT]
     279                 :     109765 :             = table->change_seqno[OVSDB_IDL_CHANGE_MODIFY]
     280                 :     109765 :             = table->change_seqno[OVSDB_IDL_CHANGE_DELETE] = 0;
     281                 :     109765 :         table->idl = idl;
     282                 :     109765 :         ovsdb_idl_condition_init(&table->condition, tc);
     283                 :     109765 :         table->cond_changed = false;
     284                 :            :     }
     285                 :            : 
     286                 :       7158 :     idl->cond_changed = false;
     287                 :       7158 :     idl->state_seqno = UINT_MAX;
     288                 :       7158 :     idl->request_id = NULL;
     289                 :       7158 :     idl->schema = NULL;
     290                 :            : 
     291                 :       7158 :     hmap_init(&idl->outstanding_txns);
     292                 :       7158 :     uuid_generate(&idl->uuid);
     293                 :            : 
     294                 :       7158 :     return idl;
     295                 :            : }
     296                 :            : 
     297                 :            : /* Changes the remote and creates a new session. */
     298                 :            : void
     299                 :          2 : ovsdb_idl_set_remote(struct ovsdb_idl *idl, const char *remote,
     300                 :            :                      bool retry)
     301                 :            : {
     302         [ +  - ]:          2 :     if (idl) {
     303         [ -  + ]:          2 :         ovs_assert(!idl->txn);
     304                 :          2 :         jsonrpc_session_close(idl->session);
     305                 :          2 :         idl->session = jsonrpc_session_open(remote, retry);
     306                 :          2 :         idl->state_seqno = UINT_MAX;
     307                 :            :     }
     308                 :          2 : }
     309                 :            : 
     310                 :            : /* Destroys 'idl' and all of the data structures that it manages. */
     311                 :            : void
     312                 :       7159 : ovsdb_idl_destroy(struct ovsdb_idl *idl)
     313                 :            : {
     314         [ +  + ]:       7159 :     if (idl) {
     315                 :            :         size_t i;
     316                 :            : 
     317         [ -  + ]:       7156 :         ovs_assert(!idl->txn);
     318                 :       7156 :         ovsdb_idl_clear(idl);
     319                 :       7156 :         jsonrpc_session_close(idl->session);
     320                 :            : 
     321         [ +  + ]:     116909 :         for (i = 0; i < idl->class->n_tables; i++) {
     322                 :     109753 :             struct ovsdb_idl_table *table = &idl->tables[i];
     323                 :     109753 :             shash_destroy(&table->columns);
     324                 :     109753 :             hmap_destroy(&table->rows);
     325                 :     109753 :             free(table->modes);
     326                 :            :         }
     327                 :       7156 :         shash_destroy(&idl->table_by_name);
     328                 :       7156 :         free(idl->tables);
     329                 :       7156 :         json_destroy(idl->request_id);
     330                 :       7156 :         free(idl->lock_name);
     331                 :       7156 :         json_destroy(idl->lock_request_id);
     332                 :       7156 :         json_destroy(idl->schema);
     333                 :       7156 :         hmap_destroy(&idl->outstanding_txns);
     334                 :       7156 :         free(idl);
     335                 :            :     }
     336                 :       7159 : }
     337                 :            : 
     338                 :            : static void
     339                 :      14308 : ovsdb_idl_clear(struct ovsdb_idl *idl)
     340                 :            : {
     341                 :      14308 :     bool changed = false;
     342                 :            :     size_t i;
     343                 :            : 
     344         [ +  + ]:     233700 :     for (i = 0; i < idl->class->n_tables; i++) {
     345                 :     219392 :         struct ovsdb_idl_table *table = &idl->tables[i];
     346                 :            :         struct ovsdb_idl_row *row, *next_row;
     347                 :            : 
     348         [ +  + ]:     219392 :         if (hmap_is_empty(&table->rows)) {
     349                 :     196449 :             continue;
     350                 :            :         }
     351                 :            : 
     352                 :      22943 :         changed = true;
     353 [ +  + ][ -  + ]:     132558 :         HMAP_FOR_EACH_SAFE (row, next_row, hmap_node, &table->rows) {
                 [ +  + ]
     354                 :            :             struct ovsdb_idl_arc *arc, *next_arc;
     355                 :            : 
     356         [ +  + ]:     109615 :             if (!ovsdb_idl_row_is_orphan(row)) {
     357                 :     109349 :                 ovsdb_idl_row_unparse(row);
     358                 :            :             }
     359 [ +  + ][ +  + ]:     201585 :             LIST_FOR_EACH_SAFE (arc, next_arc, src_node, &row->src_arcs) {
     360                 :      91970 :                 free(arc);
     361                 :            :             }
     362                 :            :             /* No need to do anything with dst_arcs: some node has those arcs
     363                 :            :              * as forward arcs and will destroy them itself. */
     364                 :            : 
     365         [ +  + ]:     109615 :             if (!ovs_list_is_empty(&row->track_node)) {
     366                 :        128 :                 ovs_list_remove(&row->track_node);
     367                 :            :             }
     368                 :            : 
     369                 :     109615 :             ovsdb_idl_row_destroy(row);
     370                 :            :         }
     371                 :            :     }
     372                 :            : 
     373                 :      14308 :     ovsdb_idl_track_clear(idl);
     374                 :            : 
     375         [ +  + ]:      14308 :     if (changed) {
     376                 :       7145 :         idl->change_seqno++;
     377                 :            :     }
     378                 :      14308 : }
     379                 :            : 
     380                 :            : /* Processes a batch of messages from the database server on 'idl'.  This may
     381                 :            :  * cause the IDL's contents to change.  The client may check for that with
     382                 :            :  * ovsdb_idl_get_seqno(). */
     383                 :            : void
     384                 :     147927 : ovsdb_idl_run(struct ovsdb_idl *idl)
     385                 :            : {
     386                 :            :     int i;
     387                 :            : 
     388         [ -  + ]:     147927 :     ovs_assert(!idl->txn);
     389                 :            : 
     390                 :     147927 :     ovsdb_idl_send_cond_change(idl);
     391                 :            : 
     392                 :     147927 :     jsonrpc_session_run(idl->session);
     393 [ +  + ][ +  - ]:     191688 :     for (i = 0; jsonrpc_session_is_connected(idl->session) && i < 50; i++) {
     394                 :            :         struct jsonrpc_msg *msg;
     395                 :            :         unsigned int seqno;
     396                 :            : 
     397                 :     184287 :         seqno = jsonrpc_session_get_seqno(idl->session);
     398         [ +  + ]:     184287 :         if (idl->state_seqno != seqno) {
     399                 :       7152 :             idl->state_seqno = seqno;
     400                 :       7152 :             json_destroy(idl->request_id);
     401                 :       7152 :             idl->request_id = NULL;
     402                 :       7152 :             ovsdb_idl_txn_abort_all(idl);
     403                 :            : 
     404                 :       7152 :             ovsdb_idl_send_schema_request(idl);
     405                 :       7152 :             idl->state = IDL_S_SCHEMA_REQUESTED;
     406         [ +  + ]:       7152 :             if (idl->lock_name) {
     407                 :        618 :                 ovsdb_idl_send_lock_request(idl);
     408                 :            :             }
     409                 :            :         }
     410                 :            : 
     411                 :     184287 :         msg = jsonrpc_session_recv(idl->session);
     412         [ +  + ]:     184287 :         if (!msg) {
     413                 :     140526 :             break;
     414                 :            :         }
     415                 :            : 
     416         [ +  + ]:      43761 :         if (msg->type == JSONRPC_NOTIFY
     417         [ +  + ]:      17498 :             && !strcmp(msg->method, "update2")
     418         [ +  - ]:      17488 :             && msg->params->type == JSON_ARRAY
     419         [ +  - ]:      17488 :             && msg->params->u.array.n == 2
     420         [ +  - ]:      17488 :             && msg->params->u.array.elems[0]->type == JSON_STRING) {
     421                 :            :             /* Database contents changed. */
     422                 :      17488 :             ovsdb_idl_parse_update(idl, msg->params->u.array.elems[1],
     423                 :            :                                    OVSDB_UPDATE2);
     424         [ +  + ]:      26273 :         } else if (msg->type == JSONRPC_REPLY
     425         [ +  + ]:      26260 :                    && idl->request_id
     426         [ +  + ]:      14922 :                    && json_equal(idl->request_id, msg->id)) {
     427                 :      14304 :             json_destroy(idl->request_id);
     428                 :      14304 :             idl->request_id = NULL;
     429                 :            : 
     430      [ +  +  - ]:      14304 :             switch (idl->state) {
     431                 :            :             case IDL_S_SCHEMA_REQUESTED:
     432                 :            :                 /* Reply to our "get_schema" request. */
     433                 :       7152 :                 idl->schema = json_clone(msg->result);
     434                 :       7152 :                 ovsdb_idl_send_monitor_cond_request(idl);
     435                 :       7152 :                 idl->state = IDL_S_MONITOR_COND_REQUESTED;
     436                 :       7152 :                 break;
     437                 :            : 
     438                 :            :             case IDL_S_MONITOR_REQUESTED:
     439                 :            :             case IDL_S_MONITOR_COND_REQUESTED:
     440                 :            :                 /* Reply to our "monitor" or "monitor_cond" request. */
     441                 :       7152 :                 idl->change_seqno++;
     442                 :       7152 :                 ovsdb_idl_clear(idl);
     443         [ +  + ]:       7152 :                 if (idl->state == IDL_S_MONITOR_REQUESTED) {
     444                 :          3 :                     idl->state = IDL_S_MONITORING;
     445                 :          3 :                     ovsdb_idl_parse_update(idl, msg->result, OVSDB_UPDATE);
     446                 :            :                 } else { /* IDL_S_MONITOR_COND_REQUESTED. */
     447                 :       7149 :                     idl->state = IDL_S_MONITORING_COND;
     448                 :       7149 :                     ovsdb_idl_parse_update(idl, msg->result, OVSDB_UPDATE2);
     449                 :            :                 }
     450                 :            : 
     451                 :            :                 /* Schema is not useful after monitor request is accepted
     452                 :            :                  * by the server.  */
     453                 :       7152 :                 json_destroy(idl->schema);
     454                 :       7152 :                 idl->schema = NULL;
     455                 :       7152 :                 break;
     456                 :            : 
     457                 :            :             case IDL_S_MONITORING:
     458                 :            :             case IDL_S_MONITORING_COND:
     459                 :            :             case IDL_S_NO_SCHEMA:
     460                 :            :             default:
     461                 :          0 :                 OVS_NOT_REACHED();
     462                 :            :             }
     463         [ +  + ]:      26273 :         } else if (msg->type == JSONRPC_NOTIFY
     464         [ +  + ]:         10 :                    && !strcmp(msg->method, "update")
     465         [ +  - ]:          8 :                    && msg->params->type == JSON_ARRAY
     466         [ +  - ]:          8 :                    && msg->params->u.array.n == 2
     467         [ +  - ]:          8 :                    && msg->params->u.array.elems[0]->type == JSON_STRING) {
     468                 :            :             /* Database contents changed. */
     469                 :          8 :             ovsdb_idl_parse_update(idl, msg->params->u.array.elems[1],
     470                 :            :                                    OVSDB_UPDATE);
     471         [ +  + ]:      11961 :         } else if (msg->type == JSONRPC_REPLY
     472         [ +  + ]:      11956 :                    && idl->lock_request_id
     473         [ +  - ]:        618 :                    && json_equal(idl->lock_request_id, msg->id)) {
     474                 :            :             /* Reply to our "lock" request. */
     475                 :        618 :             ovsdb_idl_parse_lock_reply(idl, msg->result);
     476         [ +  + ]:      11343 :         } else if (msg->type == JSONRPC_NOTIFY
     477         [ +  - ]:          2 :                    && !strcmp(msg->method, "locked")) {
     478                 :            :             /* We got our lock. */
     479                 :          2 :             ovsdb_idl_parse_lock_notify(idl, msg->params, true);
     480         [ -  + ]:      11341 :         } else if (msg->type == JSONRPC_NOTIFY
     481         [ #  # ]:          0 :                    && !strcmp(msg->method, "stolen")) {
     482                 :            :             /* Someone else stole our lock. */
     483                 :          0 :             ovsdb_idl_parse_lock_notify(idl, msg->params, false);
     484         [ +  + ]:      11341 :         } else if (msg->type == JSONRPC_ERROR
     485         [ +  - ]:          3 :                    && idl->state == IDL_S_MONITOR_COND_REQUESTED
     486         [ +  - ]:          3 :                    && idl->request_id
     487         [ +  - ]:          3 :                    && json_equal(idl->request_id, msg->id)) {
     488 [ +  - ][ +  - ]:          6 :             if (msg->error && !strcmp(json_string(msg->error),
     489                 :            :                                       "unknown method")) {
     490                 :            :                 /* Fall back to using "monitor" method.  */
     491                 :          3 :                 json_destroy(idl->request_id);
     492                 :          3 :                 idl->request_id = NULL;
     493                 :          3 :                 ovsdb_idl_send_monitor_request(idl);
     494                 :          3 :                 idl->state = IDL_S_MONITOR_REQUESTED;
     495                 :            :             }
     496         [ -  + ]:      11338 :         } else if (msg->type == JSONRPC_ERROR
     497         [ #  # ]:          0 :                    && idl->state == IDL_S_SCHEMA_REQUESTED
     498         [ #  # ]:          0 :                    && idl->request_id
     499         [ #  # ]:          0 :                    && json_equal(idl->request_id, msg->id)) {
     500                 :          0 :                 json_destroy(idl->request_id);
     501                 :          0 :                 idl->request_id = NULL;
     502         [ #  # ]:          0 :                 VLOG_ERR("%s: requested schema not found",
     503                 :            :                          jsonrpc_session_get_name(idl->session));
     504                 :          0 :                 idl->state = IDL_S_NO_SCHEMA;
     505         [ +  - ]:      11338 :         } else if ((msg->type == JSONRPC_ERROR
     506         [ +  - ]:      11338 :                     || msg->type == JSONRPC_REPLY)
     507         [ +  + ]:      11338 :                    && ovsdb_idl_txn_process_reply(idl, msg)) {
     508                 :            :             /* ovsdb_idl_txn_process_reply() did everything needful. */
     509                 :            :         } else {
     510                 :            :             /* This can happen if ovsdb_idl_txn_destroy() is called to destroy
     511                 :            :              * a transaction before we receive the reply, so keep the log level
     512                 :            :              * low. */
     513         [ -  + ]:       2344 :             VLOG_DBG("%s: received unexpected %s message",
     514                 :            :                      jsonrpc_session_get_name(idl->session),
     515                 :            :                      jsonrpc_msg_type_to_string(msg->type));
     516                 :            :         }
     517                 :      43761 :         jsonrpc_msg_destroy(msg);
     518                 :            :     }
     519                 :     147927 :     ovsdb_idl_row_destroy_postprocess(idl);
     520                 :     147927 : }
     521                 :            : 
     522                 :            : /* Arranges for poll_block() to wake up when ovsdb_idl_run() has something to
     523                 :            :  * do or when activity occurs on a transaction on 'idl'. */
     524                 :            : void
     525                 :     136036 : ovsdb_idl_wait(struct ovsdb_idl *idl)
     526                 :            : {
     527                 :     136036 :     jsonrpc_session_wait(idl->session);
     528                 :     136036 :     jsonrpc_session_recv_wait(idl->session);
     529                 :     136036 : }
     530                 :            : 
     531                 :            : /* Returns a "sequence number" that represents the state of 'idl'.  When
     532                 :            :  * ovsdb_idl_run() changes the database, the sequence number changes.  The
     533                 :            :  * initial fetch of the entire contents of the remote database is considered to
     534                 :            :  * be one kind of change.  Successfully acquiring a lock, if one has been
     535                 :            :  * configured with ovsdb_idl_set_lock(), is also considered to be a change.
     536                 :            :  *
     537                 :            :  * As long as the sequence number does not change, the client may continue to
     538                 :            :  * use any data structures it obtains from 'idl'.  But when it changes, the
     539                 :            :  * client must not access any of these data structures again, because they
     540                 :            :  * could have freed or reused for other purposes.
     541                 :            :  *
     542                 :            :  * The sequence number can occasionally change even if the database does not.
     543                 :            :  * This happens if the connection to the database drops and reconnects, which
     544                 :            :  * causes the database contents to be reloaded even if they didn't change.  (It
     545                 :            :  * could also happen if the database server sends out a "change" that reflects
     546                 :            :  * what the IDL already thought was in the database.  The database server is
     547                 :            :  * not supposed to do that, but bugs could in theory cause it to do so.) */
     548                 :            : unsigned int
     549                 :     279268 : ovsdb_idl_get_seqno(const struct ovsdb_idl *idl)
     550                 :            : {
     551                 :     279268 :     return idl->change_seqno;
     552                 :            : }
     553                 :            : 
     554                 :            : /* Returns true if 'idl' successfully connected to the remote database and
     555                 :            :  * retrieved its contents (even if the connection subsequently dropped and is
     556                 :            :  * in the process of reconnecting).  If so, then 'idl' contains an atomic
     557                 :            :  * snapshot of the database's contents (but it might be arbitrarily old if the
     558                 :            :  * connection dropped).
     559                 :            :  *
     560                 :            :  * Returns false if 'idl' has never connected or retrieved the database's
     561                 :            :  * contents.  If so, 'idl' is empty. */
     562                 :            : bool
     563                 :     107425 : ovsdb_idl_has_ever_connected(const struct ovsdb_idl *idl)
     564                 :            : {
     565                 :     107425 :     return ovsdb_idl_get_seqno(idl) != 0;
     566                 :            : }
     567                 :            : 
     568                 :            : /* Reconfigures 'idl' so that it would reconnect to the database, if
     569                 :            :  * connection was dropped. */
     570                 :            : void
     571                 :       2164 : ovsdb_idl_enable_reconnect(struct ovsdb_idl *idl)
     572                 :            : {
     573                 :       2164 :     jsonrpc_session_enable_reconnect(idl->session);
     574                 :       2164 : }
     575                 :            : 
     576                 :            : /* Forces 'idl' to drop its connection to the database and reconnect.  In the
     577                 :            :  * meantime, the contents of 'idl' will not change. */
     578                 :            : void
     579                 :          2 : ovsdb_idl_force_reconnect(struct ovsdb_idl *idl)
     580                 :            : {
     581                 :          2 :     jsonrpc_session_force_reconnect(idl->session);
     582                 :          2 : }
     583                 :            : 
     584                 :            : /* Some IDL users should only write to write-only columns.  Furthermore,
     585                 :            :  * writing to a column which is not write-only can cause serious performance
     586                 :            :  * degradations for these users.  This function causes 'idl' to reject writes
     587                 :            :  * to columns which are not marked write only using ovsdb_idl_omit_alert(). */
     588                 :            : void
     589                 :        617 : ovsdb_idl_verify_write_only(struct ovsdb_idl *idl)
     590                 :            : {
     591                 :        617 :     idl->verify_write_only = true;
     592                 :        617 : }
     593                 :            : 
     594                 :            : /* Returns true if 'idl' is currently connected or trying to connect
     595                 :            :  * and a negative response to a schema request has not been received */
     596                 :            : bool
     597                 :      16379 : ovsdb_idl_is_alive(const struct ovsdb_idl *idl)
     598                 :            : {
     599 [ +  + ][ +  - ]:      16379 :     return jsonrpc_session_is_alive(idl->session) &&
     600                 :      16374 :            idl->state != IDL_S_NO_SCHEMA;
     601                 :            : }
     602                 :            : 
     603                 :            : /* Returns the last error reported on a connection by 'idl'.  The return value
     604                 :            :  * is 0 only if no connection made by 'idl' has ever encountered an error and
     605                 :            :  * a negative response to a schema request has never been received. See
     606                 :            :  * jsonrpc_get_status() for jsonrpc_session_get_last_error() return value
     607                 :            :  * interpretation. */
     608                 :            : int
     609                 :          5 : ovsdb_idl_get_last_error(const struct ovsdb_idl *idl)
     610                 :            : {
     611                 :            :     int err;
     612                 :            : 
     613                 :          5 :     err = jsonrpc_session_get_last_error(idl->session);
     614                 :            : 
     615         [ +  - ]:          5 :     if (err) {
     616                 :          5 :         return err;
     617         [ #  # ]:          0 :     } else if (idl->state == IDL_S_NO_SCHEMA) {
     618                 :          0 :         return ENOENT;
     619                 :            :     } else {
     620                 :          0 :         return 0;
     621                 :            :     }
     622                 :            : }
     623                 :            : 
     624                 :            : /* Sets the "probe interval" for 'idl->session' to 'probe_interval', in
     625                 :            :  * milliseconds.
     626                 :            :  */
     627                 :            : void
     628                 :       3167 : ovsdb_idl_set_probe_interval(const struct ovsdb_idl *idl, int probe_interval)
     629                 :            : {
     630                 :       3167 :     jsonrpc_session_set_probe_interval(idl->session, probe_interval);
     631                 :       3167 : }
     632                 :            : 
     633                 :            : static unsigned char *
     634                 :     131671 : ovsdb_idl_get_mode(struct ovsdb_idl *idl,
     635                 :            :                    const struct ovsdb_idl_column *column)
     636                 :            : {
     637                 :            :     size_t i;
     638                 :            : 
     639         [ -  + ]:     131671 :     ovs_assert(!idl->change_seqno);
     640                 :            : 
     641         [ +  - ]:    1047862 :     for (i = 0; i < idl->class->n_tables; i++) {
     642                 :    1047862 :         const struct ovsdb_idl_table *table = &idl->tables[i];
     643                 :    1047862 :         const struct ovsdb_idl_table_class *tc = table->class;
     644                 :            : 
     645 [ +  + ][ +  + ]:    1047862 :         if (column >= tc->columns && column < &tc->columns[tc->n_columns]) {
     646                 :     131671 :             return &table->modes[column - tc->columns];
     647                 :            :         }
     648                 :            :     }
     649                 :            : 
     650                 :          0 :     OVS_NOT_REACHED();
     651                 :            : }
     652                 :            : 
     653                 :            : static void
     654                 :     174678 : add_ref_table(struct ovsdb_idl *idl, const struct ovsdb_base_type *base)
     655                 :            : {
     656 [ +  + ][ +  + ]:     174678 :     if (base->type == OVSDB_TYPE_UUID && base->u.uuid.refTableName) {
     657                 :            :         struct ovsdb_idl_table *table;
     658                 :            : 
     659                 :      27244 :         table = shash_find_data(&idl->table_by_name,
     660                 :      27244 :                                 base->u.uuid.refTableName);
     661         [ +  - ]:      27244 :         if (table) {
     662                 :      27244 :             table->need_table = true;
     663                 :            :         } else {
     664         [ #  # ]:          0 :             VLOG_WARN("%s IDL class missing referenced table %s",
     665                 :            :                       idl->class->database, base->u.uuid.refTableName);
     666                 :            :         }
     667                 :            :     }
     668                 :     174678 : }
     669                 :            : 
     670                 :            : /* Turns on OVSDB_IDL_MONITOR and OVSDB_IDL_ALERT for 'column' in 'idl'.  Also
     671                 :            :  * ensures that any tables referenced by 'column' will be replicated, even if
     672                 :            :  * no columns in that table are selected for replication (see
     673                 :            :  * ovsdb_idl_add_table() for more information).
     674                 :            :  *
     675                 :            :  * This function is only useful if 'monitor_everything_by_default' was false in
     676                 :            :  * the call to ovsdb_idl_create().  This function should be called between
     677                 :            :  * ovsdb_idl_create() and the first call to ovsdb_idl_run().
     678                 :            :  */
     679                 :            : void
     680                 :      87339 : ovsdb_idl_add_column(struct ovsdb_idl *idl,
     681                 :            :                      const struct ovsdb_idl_column *column)
     682                 :            : {
     683                 :      87339 :     *ovsdb_idl_get_mode(idl, column) = OVSDB_IDL_MONITOR | OVSDB_IDL_ALERT;
     684                 :      87339 :     add_ref_table(idl, &column->type.key);
     685                 :      87339 :     add_ref_table(idl, &column->type.value);
     686                 :      87339 : }
     687                 :            : 
     688                 :            : /* Ensures that the table with class 'tc' will be replicated on 'idl' even if
     689                 :            :  * no columns are selected for replication. Just the necessary data for table
     690                 :            :  * references will be replicated (the UUID of the rows, for instance), any
     691                 :            :  * columns not selected for replication will remain unreplicated.
     692                 :            :  * This can be useful because it allows 'idl' to keep track of what rows in the
     693                 :            :  * table actually exist, which in turn allows columns that reference the table
     694                 :            :  * to have accurate contents. (The IDL presents the database with references to
     695                 :            :  * rows that do not exist removed.)
     696                 :            :  *
     697                 :            :  * This function is only useful if 'monitor_everything_by_default' was false in
     698                 :            :  * the call to ovsdb_idl_create().  This function should be called between
     699                 :            :  * ovsdb_idl_create() and the first call to ovsdb_idl_run().
     700                 :            :  */
     701                 :            : void
     702                 :      18394 : ovsdb_idl_add_table(struct ovsdb_idl *idl,
     703                 :            :                     const struct ovsdb_idl_table_class *tc)
     704                 :            : {
     705                 :            :     size_t i;
     706                 :            : 
     707         [ +  - ]:     142229 :     for (i = 0; i < idl->class->n_tables; i++) {
     708                 :     142229 :         struct ovsdb_idl_table *table = &idl->tables[i];
     709                 :            : 
     710         [ +  + ]:     142229 :         if (table->class == tc) {
     711                 :      18394 :             table->need_table = true;
     712                 :      18394 :             return;
     713                 :            :         }
     714                 :            :     }
     715                 :            : 
     716                 :          0 :     OVS_NOT_REACHED();
     717                 :            : }
     718                 :            : 
     719                 :            : struct ovsdb_idl_clause {
     720                 :            :     struct ovs_list node;
     721                 :            :     enum ovsdb_function function;
     722                 :            :     const struct ovsdb_idl_column *column;
     723                 :            :     struct ovsdb_datum arg;
     724                 :            : };
     725                 :            : 
     726                 :            : static struct json *
     727                 :         26 : ovsdb_idl_clause_to_json(const struct ovsdb_idl_clause *clause)
     728                 :            : {
     729 [ +  + ][ +  + ]:         26 :     if (clause->function != OVSDB_F_TRUE &&
     730                 :         25 :         clause->function != OVSDB_F_FALSE) {
     731                 :          9 :         const char *function = ovsdb_function_to_string(clause->function);
     732                 :            : 
     733                 :          9 :         return json_array_create_3(json_string_create(clause->column->name),
     734                 :            :                                    json_string_create(function),
     735                 :            :                                    ovsdb_datum_to_json(&clause->arg,
     736                 :          9 :                                                        &clause->column->type));
     737                 :            :     }
     738                 :            : 
     739                 :         17 :     return json_boolean_create(clause->function == OVSDB_F_TRUE ?
     740                 :            :                                true : false);
     741                 :            : }
     742                 :            : 
     743                 :            : static void
     744                 :          2 : ovsdb_idl_clause_free(struct ovsdb_idl_clause *clause)
     745                 :            : {
     746 [ +  - ][ +  + ]:          2 :     if (clause->function != OVSDB_F_TRUE &&
     747                 :          2 :         clause->function != OVSDB_F_FALSE) {
     748                 :          1 :         ovsdb_datum_destroy(&clause->arg, &clause->column->type);
     749                 :            :     }
     750                 :            : 
     751                 :          2 :     ovs_list_remove(&clause->node);
     752                 :          2 :     free(clause);
     753                 :          2 : }
     754                 :            : 
     755                 :            : /* Clears all of the conditional clauses from table 'tc', so that all of the
     756                 :            :  * rows in the table will be replicated.  (This is the default, so this
     757                 :            :  * function has an effect only if some clauses were added to 'tc' using
     758                 :            :  * ovsdb_idl_condition_add_clause().) */
     759                 :            : void
     760                 :          0 : ovsdb_idl_condition_reset(struct ovsdb_idl *idl,
     761                 :            :                           const struct ovsdb_idl_table_class *tc)
     762                 :            : {
     763                 :            :     struct ovsdb_idl_clause *c, *next;
     764                 :          0 :     struct ovsdb_idl_table *table = ovsdb_idl_table_from_class(idl, tc);
     765                 :            : 
     766 [ #  # ][ #  # ]:          0 :     LIST_FOR_EACH_SAFE (c, next, node, &table->condition.clauses) {
     767                 :          0 :         ovsdb_idl_clause_free(c);
     768                 :            :     }
     769                 :          0 :     idl->cond_changed = table->cond_changed = true;
     770                 :          0 : }
     771                 :            : 
     772                 :            : static void
     773                 :     109765 : ovsdb_idl_condition_init(struct ovsdb_idl_condition *cnd,
     774                 :            :                          const struct ovsdb_idl_table_class *tc)
     775                 :            : {
     776                 :     109765 :     cnd->tc = tc;
     777                 :     109765 :     ovs_list_init(&cnd->clauses);
     778                 :     109765 : }
     779                 :            : 
     780                 :            : static struct ovsdb_idl_clause *
     781                 :         19 : ovsdb_idl_condition_find_clause(struct ovsdb_idl_table *table,
     782                 :            :                                 enum ovsdb_function function,
     783                 :            :                                 const struct ovsdb_idl_column *column,
     784                 :            :                                 const struct ovsdb_datum *arg)
     785                 :            : {
     786                 :            :     struct ovsdb_idl_clause *c;
     787         [ +  + ]:         31 :     LIST_FOR_EACH (c, node, &table->condition.clauses) {
     788 [ +  + ][ +  + ]:         14 :         if (c->function == function &&
     789   [ +  -  +  + ]:          6 :             (!column || (c->column == column &&
     790                 :          3 :                          ovsdb_datum_equals(&c->arg,
     791                 :            :                                              arg, &column->type)))) {
     792                 :          2 :             return c;
     793                 :            :         }
     794                 :            :     }
     795                 :         17 :     return NULL;
     796                 :            : }
     797                 :            : 
     798                 :            : /* Adds a clause to the condition for replicating the table with class 'tc' in
     799                 :            :  * 'idl'.
     800                 :            :  *
     801                 :            :  * By default, a table has no clauses, and in that case the IDL replicates all
     802                 :            :  * its rows.  When a table has one or more clauses, the IDL replicates only
     803                 :            :  * rows that satisfy at least one clause.
     804                 :            :  *
     805                 :            :  * Two distinct of clauses can be added:
     806                 :            :  *
     807                 :            :  *    - A 'function' of OVSDB_F_FALSE or OVSDB_F_TRUE adds a Boolean clause.  A
     808                 :            :  *      "false" clause by itself prevents any rows from being replicated; in
     809                 :            :  *      combination with other clauses it has no effect.  A "true" clause
     810                 :            :  *      causes every row to be replicated, regardless of whether other clauses
     811                 :            :  *      exist (thus, a condition that includes "true" is like a condition
     812                 :            :  *      without any clauses at all).
     813                 :            :  *
     814                 :            :  *      'column' should be NULL and 'arg' should be an empty datum (initialized
     815                 :            :  *      with ovsdb_datum_init_empty()).
     816                 :            :  *
     817                 :            :  *    - Other 'functions' add a clause of the form "<column> <function> <arg>",
     818                 :            :  *      e.g. "column == 5" or "column <= 10".  In this case, 'arg' must have a
     819                 :            :  *      type that is compatible with 'column'.
     820                 :            :  */
     821                 :            : void
     822                 :         17 : ovsdb_idl_condition_add_clause(struct ovsdb_idl *idl,
     823                 :            :                                const struct ovsdb_idl_table_class *tc,
     824                 :            :                                enum ovsdb_function function,
     825                 :            :                                const struct ovsdb_idl_column *column,
     826                 :            :                                const struct ovsdb_datum *arg)
     827                 :            : {
     828                 :         17 :     struct ovsdb_idl_table *table = ovsdb_idl_table_from_class(idl, tc);
     829                 :            : 
     830                 :            :     /* Return without doing anything, if this would be a duplicate clause. */
     831         [ -  + ]:         17 :     if (ovsdb_idl_condition_find_clause(table, function, column, arg)) {
     832                 :          0 :         return;
     833                 :            :     }
     834                 :            : 
     835                 :         17 :     struct ovsdb_idl_clause *clause = xzalloc(sizeof *clause);
     836                 :         17 :     ovs_list_init(&clause->node);
     837                 :         17 :     clause->function = function;
     838                 :         17 :     clause->column = column;
     839         [ +  + ]:         17 :     ovsdb_datum_clone(&clause->arg, arg,
     840                 :            :                       column ? &column->type : &ovsdb_type_boolean);
     841                 :         17 :     ovs_list_push_back(&table->condition.clauses, &clause->node);
     842                 :         17 :     idl->cond_changed = table->cond_changed = true;
     843                 :         17 :     poll_immediate_wake();
     844                 :            : }
     845                 :            : 
     846                 :            : /* If a clause matching (function, column, arg) is included in the condition
     847                 :            :  * for 'tc' within 'idl', removes it.  (If this was the last clause included in
     848                 :            :  * the table's condition, then this means that the IDL will begin replicating
     849                 :            :  * every row in the table.) */
     850                 :            : void
     851                 :          2 : ovsdb_idl_condition_remove_clause(struct ovsdb_idl *idl,
     852                 :            :                                   const struct ovsdb_idl_table_class *tc,
     853                 :            :                                   enum ovsdb_function function,
     854                 :            :                                   const struct ovsdb_idl_column *column,
     855                 :            :                                   const struct ovsdb_datum *arg)
     856                 :            : {
     857                 :          2 :     struct ovsdb_idl_table *table = ovsdb_idl_table_from_class(idl, tc);
     858                 :          2 :     struct ovsdb_idl_clause *c
     859                 :            :         = ovsdb_idl_condition_find_clause(table, function, column, arg);
     860         [ +  - ]:          2 :     if (c) {
     861                 :          2 :         ovsdb_idl_clause_free(c);
     862                 :          2 :         idl->cond_changed = table->cond_changed = true;
     863                 :          2 :         poll_immediate_wake();
     864                 :            :     }
     865                 :          2 : }
     866                 :            : 
     867                 :            : static struct json *
     868                 :         17 : ovsdb_idl_condition_to_json(const struct ovsdb_idl_condition *cnd)
     869                 :            : {
     870                 :            :     struct json **clauses;
     871                 :         17 :     size_t i = 0, n_clauses = ovs_list_size(&cnd->clauses);
     872                 :            :     struct ovsdb_idl_clause *c;
     873                 :            : 
     874                 :         17 :     clauses = xmalloc(n_clauses * sizeof *clauses);
     875         [ +  + ]:         43 :     LIST_FOR_EACH (c, node, &cnd->clauses) {
     876                 :         26 :         clauses[i++] = ovsdb_idl_clause_to_json(c);
     877                 :            :     }
     878                 :            : 
     879                 :         17 :     return json_array_create(clauses, n_clauses);
     880                 :            : }
     881                 :            : 
     882                 :            : static struct json *
     883                 :          9 : ovsdb_idl_create_cond_change_req(struct ovsdb_idl_table *table)
     884                 :            : {
     885                 :          9 :     const struct ovsdb_idl_condition *cond = &table->condition;
     886                 :          9 :     struct json *monitor_cond_change_request = json_object_create();
     887                 :          9 :     struct json *cond_json = ovsdb_idl_condition_to_json(cond);
     888                 :            : 
     889                 :          9 :     json_object_put(monitor_cond_change_request, "where", cond_json);
     890                 :            : 
     891                 :          9 :     return monitor_cond_change_request;
     892                 :            : }
     893                 :            : 
     894                 :            : static void
     895                 :     147927 : ovsdb_idl_send_cond_change(struct ovsdb_idl *idl)
     896                 :            : {
     897                 :            :     int i;
     898                 :            :     char uuid[UUID_LEN + 1];
     899                 :            :     struct json *params, *json_uuid;
     900                 :            :     struct jsonrpc_msg *request;
     901                 :            : 
     902 [ +  + ][ +  + ]:     147927 :     if (!idl->cond_changed || !jsonrpc_session_is_connected(idl->session) ||
                 [ +  + ]
     903                 :         11 :         idl->state != IDL_S_MONITORING_COND) {
     904                 :     147918 :         return;
     905                 :            :     }
     906                 :            : 
     907                 :          9 :     struct json *monitor_cond_change_requests = NULL;
     908                 :            : 
     909         [ +  + ]:         63 :     for (i = 0; i < idl->class->n_tables; i++) {
     910                 :         54 :         struct ovsdb_idl_table *table = &idl->tables[i];
     911                 :            : 
     912         [ +  + ]:         54 :         if (table->cond_changed) {
     913                 :          9 :             struct json *req = ovsdb_idl_create_cond_change_req(table);
     914         [ +  - ]:          9 :             if (req) {
     915         [ +  - ]:          9 :                 if (!monitor_cond_change_requests) {
     916                 :          9 :                     monitor_cond_change_requests = json_object_create();
     917                 :            :                 }
     918                 :          9 :                 json_object_put(monitor_cond_change_requests,
     919                 :          9 :                              table->class->name,
     920                 :            :                              json_array_create_1(req));
     921                 :            :             }
     922                 :          9 :             table->cond_changed = false;
     923                 :            :         }
     924                 :            :     }
     925                 :            : 
     926                 :            :     /* Send request if not empty. */
     927         [ +  - ]:          9 :     if (monitor_cond_change_requests) {
     928                 :         27 :         snprintf(uuid, sizeof uuid, UUID_FMT,
     929                 :         27 :                  UUID_ARGS(&idl->uuid));
     930                 :          9 :         json_uuid = json_string_create(uuid);
     931                 :            : 
     932                 :            :         /* Create a new uuid */
     933                 :          9 :         uuid_generate(&idl->uuid);
     934                 :         27 :         snprintf(uuid, sizeof uuid, UUID_FMT,
     935                 :         27 :                  UUID_ARGS(&idl->uuid));
     936                 :          9 :         params = json_array_create_3(json_uuid, json_string_create(uuid),
     937                 :            :                                      monitor_cond_change_requests);
     938                 :            : 
     939                 :          9 :         request = jsonrpc_create_request("monitor_cond_change", params, NULL);
     940                 :          9 :         jsonrpc_session_send(idl->session, request);
     941                 :            :     }
     942                 :          9 :     idl->cond_changed = false;
     943                 :            : }
     944                 :            : 
     945                 :            : /* Turns off OVSDB_IDL_ALERT for 'column' in 'idl'.
     946                 :            :  *
     947                 :            :  * This function should be called between ovsdb_idl_create() and the first call
     948                 :            :  * to ovsdb_idl_run().
     949                 :            :  */
     950                 :            : void
     951                 :      26706 : ovsdb_idl_omit_alert(struct ovsdb_idl *idl,
     952                 :            :                      const struct ovsdb_idl_column *column)
     953                 :            : {
     954                 :      26706 :     *ovsdb_idl_get_mode(idl, column) &= ~OVSDB_IDL_ALERT;
     955                 :      26706 : }
     956                 :            : 
     957                 :            : /* Sets the mode for 'column' in 'idl' to 0.  See the big comment above
     958                 :            :  * OVSDB_IDL_MONITOR for details.
     959                 :            :  *
     960                 :            :  * This function should be called between ovsdb_idl_create() and the first call
     961                 :            :  * to ovsdb_idl_run().
     962                 :            :  */
     963                 :            : void
     964                 :      13574 : ovsdb_idl_omit(struct ovsdb_idl *idl, const struct ovsdb_idl_column *column)
     965                 :            : {
     966                 :      13574 :     *ovsdb_idl_get_mode(idl, column) = 0;
     967                 :      13574 : }
     968                 :            : 
     969                 :            : /* Returns the most recent IDL change sequence number that caused a
     970                 :            :  * insert, modify or delete update to the table with class 'table_class'.
     971                 :            :  */
     972                 :            : unsigned int
     973                 :          0 : ovsdb_idl_table_get_seqno(const struct ovsdb_idl *idl,
     974                 :            :                           const struct ovsdb_idl_table_class *table_class)
     975                 :            : {
     976                 :          0 :     struct ovsdb_idl_table *table
     977                 :            :         = ovsdb_idl_table_from_class(idl, table_class);
     978                 :          0 :     unsigned int max_seqno = table->change_seqno[OVSDB_IDL_CHANGE_INSERT];
     979                 :            : 
     980         [ #  # ]:          0 :     if (max_seqno < table->change_seqno[OVSDB_IDL_CHANGE_MODIFY]) {
     981                 :          0 :         max_seqno = table->change_seqno[OVSDB_IDL_CHANGE_MODIFY];
     982                 :            :     }
     983         [ #  # ]:          0 :     if (max_seqno < table->change_seqno[OVSDB_IDL_CHANGE_DELETE]) {
     984                 :          0 :         max_seqno = table->change_seqno[OVSDB_IDL_CHANGE_DELETE];
     985                 :            :     }
     986                 :          0 :     return max_seqno;
     987                 :            : }
     988                 :            : 
     989                 :            : /* For each row that contains tracked columns, IDL stores the most
     990                 :            :  * recent IDL change sequence numbers associateed with insert, modify
     991                 :            :  * and delete updates to the table.
     992                 :            :  */
     993                 :            : unsigned int
     994                 :          9 : ovsdb_idl_row_get_seqno(const struct ovsdb_idl_row *row,
     995                 :            :                         enum ovsdb_idl_change change)
     996                 :            : {
     997                 :          9 :     return row->change_seqno[change];
     998                 :            : }
     999                 :            : 
    1000                 :            : /* Turns on OVSDB_IDL_TRACK for 'column' in 'idl', ensuring that
    1001                 :            :  * all rows whose 'column' is modified are traced. Similarly, insert
    1002                 :            :  * or delete of rows having 'column' are tracked. Clients are able
    1003                 :            :  * to retrive the tracked rows with the ovsdb_idl_track_get_*()
    1004                 :            :  * functions.
    1005                 :            :  *
    1006                 :            :  * This function should be called between ovsdb_idl_create() and
    1007                 :            :  * the first call to ovsdb_idl_run(). The column to be tracked
    1008                 :            :  * should have OVSDB_IDL_ALERT turned on.
    1009                 :            :  */
    1010                 :            : void
    1011                 :       2026 : ovsdb_idl_track_add_column(struct ovsdb_idl *idl,
    1012                 :            :                            const struct ovsdb_idl_column *column)
    1013                 :            : {
    1014         [ +  + ]:       2026 :     if (!(*ovsdb_idl_get_mode(idl, column) & OVSDB_IDL_ALERT)) {
    1015                 :         44 :         ovsdb_idl_add_column(idl, column);
    1016                 :            :     }
    1017                 :       2026 :     *ovsdb_idl_get_mode(idl, column) |= OVSDB_IDL_TRACK;
    1018                 :       2026 : }
    1019                 :            : 
    1020                 :            : void
    1021                 :         46 : ovsdb_idl_track_add_all(struct ovsdb_idl *idl)
    1022                 :            : {
    1023                 :            :     size_t i, j;
    1024                 :            : 
    1025         [ +  + ]:        542 :     for (i = 0; i < idl->class->n_tables; i++) {
    1026                 :        496 :         const struct ovsdb_idl_table_class *tc = &idl->class->tables[i];
    1027                 :            : 
    1028         [ +  + ]:       2522 :         for (j = 0; j < tc->n_columns; j++) {
    1029                 :       2026 :             const struct ovsdb_idl_column *column = &tc->columns[j];
    1030                 :       2026 :             ovsdb_idl_track_add_column(idl, column);
    1031                 :            :         }
    1032                 :            :     }
    1033                 :         46 : }
    1034                 :            : 
    1035                 :            : /* Returns true if 'table' has any tracked column. */
    1036                 :            : static bool
    1037                 :     134805 : ovsdb_idl_track_is_set(struct ovsdb_idl_table *table)
    1038                 :            : {
    1039                 :            :     size_t i;
    1040                 :            : 
    1041         [ +  + ]:    2509971 :     for (i = 0; i < table->class->n_columns; i++) {
    1042         [ +  + ]:    2400346 :         if (table->modes[i] & OVSDB_IDL_TRACK) {
    1043                 :      25180 :             return true;
    1044                 :            :         }
    1045                 :            :     }
    1046                 :     109625 :    return false;
    1047                 :            : }
    1048                 :            : 
    1049                 :            : /* Returns the first tracked row in table with class 'table_class'
    1050                 :            :  * for the specified 'idl'. Returns NULL if there are no tracked rows */
    1051                 :            : const struct ovsdb_idl_row *
    1052                 :         24 : ovsdb_idl_track_get_first(const struct ovsdb_idl *idl,
    1053                 :            :                           const struct ovsdb_idl_table_class *table_class)
    1054                 :            : {
    1055                 :         24 :     struct ovsdb_idl_table *table
    1056                 :            :         = ovsdb_idl_table_from_class(idl, table_class);
    1057                 :            : 
    1058         [ +  + ]:         24 :     if (!ovs_list_is_empty(&table->track_list)) {
    1059                 :          7 :         return CONTAINER_OF(ovs_list_front(&table->track_list), struct ovsdb_idl_row, track_node);
    1060                 :            :     }
    1061                 :         17 :     return NULL;
    1062                 :            : }
    1063                 :            : 
    1064                 :            : /* Returns the next tracked row in table after the specified 'row'
    1065                 :            :  * (in no particular order). Returns NULL if there are no tracked rows */
    1066                 :            : const struct ovsdb_idl_row *
    1067                 :          9 : ovsdb_idl_track_get_next(const struct ovsdb_idl_row *row)
    1068                 :            : {
    1069         [ +  + ]:          9 :     if (row->track_node.next != &row->table->track_list) {
    1070                 :          2 :         return CONTAINER_OF(row->track_node.next, struct ovsdb_idl_row, track_node);
    1071                 :            :     }
    1072                 :            : 
    1073                 :          7 :     return NULL;
    1074                 :            : }
    1075                 :            : 
    1076                 :            : /* Returns true if a tracked 'column' in 'row' was updated by IDL, false
    1077                 :            :  * otherwise. The tracking data is cleared by ovsdb_idl_track_clear()
    1078                 :            :  *
    1079                 :            :  * Function returns false if 'column' is not tracked (see
    1080                 :            :  * ovsdb_idl_track_add_column()).
    1081                 :            :  */
    1082                 :            : bool
    1083                 :        740 : ovsdb_idl_track_is_updated(const struct ovsdb_idl_row *row,
    1084                 :            :                            const struct ovsdb_idl_column *column)
    1085                 :            : {
    1086                 :            :     const struct ovsdb_idl_table_class *class;
    1087                 :            :     size_t column_idx;
    1088                 :            : 
    1089                 :        740 :     class = row->table->class;
    1090                 :        740 :     column_idx = column - class->columns;
    1091                 :            : 
    1092 [ +  + ][ +  + ]:        740 :     if (row->updated && bitmap_is_set(row->updated, column_idx)) {
    1093                 :         47 :         return true;
    1094                 :            :     } else {
    1095                 :        693 :         return false;
    1096                 :            :     }
    1097                 :            : }
    1098                 :            : 
    1099                 :            : /* Flushes the tracked rows. Client calls this function after calling
    1100                 :            :  * ovsdb_idl_run() and read all tracked rows with the ovsdb_idl_track_get_*()
    1101                 :            :  * functions. This is usually done at the end of the client's processing
    1102                 :            :  * loop when it is ready to do ovsdb_idl_run() again.
    1103                 :            :  */
    1104                 :            : void
    1105                 :      20671 : ovsdb_idl_track_clear(const struct ovsdb_idl *idl)
    1106                 :            : {
    1107                 :            :     size_t i;
    1108                 :            : 
    1109         [ +  + ]:     325746 :     for (i = 0; i < idl->class->n_tables; i++) {
    1110                 :     305075 :         struct ovsdb_idl_table *table = &idl->tables[i];
    1111                 :            : 
    1112         [ +  + ]:     305075 :         if (!ovs_list_is_empty(&table->track_list)) {
    1113                 :            :             struct ovsdb_idl_row *row, *next;
    1114                 :            : 
    1115 [ +  + ][ +  + ]:     144619 :             LIST_FOR_EACH_SAFE(row, next, track_node, &table->track_list) {
    1116         [ +  + ]:     119699 :                 if (row->updated) {
    1117                 :       9578 :                     free(row->updated);
    1118                 :       9578 :                     row->updated = NULL;
    1119                 :            :                 }
    1120                 :     119699 :                 ovs_list_remove(&row->track_node);
    1121                 :     119699 :                 ovs_list_init(&row->track_node);
    1122         [ +  + ]:     119699 :                 if (ovsdb_idl_row_is_orphan(row)) {
    1123                 :     110252 :                     ovsdb_idl_row_clear_old(row);
    1124                 :     110252 :                     free(row);
    1125                 :            :                 }
    1126                 :            :             }
    1127                 :            :         }
    1128                 :            :     }
    1129                 :      20671 : }
    1130                 :            : 
    1131                 :            : 
    1132                 :            : static void
    1133                 :       7152 : ovsdb_idl_send_schema_request(struct ovsdb_idl *idl)
    1134                 :            : {
    1135                 :            :     struct jsonrpc_msg *msg;
    1136                 :            : 
    1137                 :       7152 :     json_destroy(idl->request_id);
    1138                 :       7152 :     msg = jsonrpc_create_request(
    1139                 :            :         "get_schema",
    1140                 :       7152 :         json_array_create_1(json_string_create(idl->class->database)),
    1141                 :            :         &idl->request_id);
    1142                 :       7152 :     jsonrpc_session_send(idl->session, msg);
    1143                 :       7152 : }
    1144                 :            : 
    1145                 :            : static void
    1146                 :          0 : log_error(struct ovsdb_error *error)
    1147                 :            : {
    1148                 :          0 :     char *s = ovsdb_error_to_string(error);
    1149         [ #  # ]:          0 :     VLOG_WARN("error parsing database schema: %s", s);
    1150                 :          0 :     free(s);
    1151                 :          0 :     ovsdb_error_destroy(error);
    1152                 :          0 : }
    1153                 :            : 
    1154                 :            : /* Frees 'schema', which is in the format returned by parse_schema(). */
    1155                 :            : static void
    1156                 :       7155 : free_schema(struct shash *schema)
    1157                 :            : {
    1158         [ +  - ]:       7155 :     if (schema) {
    1159                 :            :         struct shash_node *node, *next;
    1160                 :            : 
    1161 [ +  + ][ -  + ]:     116841 :         SHASH_FOR_EACH_SAFE (node, next, schema) {
                 [ +  + ]
    1162                 :     109686 :             struct sset *sset = node->data;
    1163                 :     109686 :             sset_destroy(sset);
    1164                 :     109686 :             free(sset);
    1165                 :     109686 :             shash_delete(schema, node);
    1166                 :            :         }
    1167                 :       7155 :         shash_destroy(schema);
    1168                 :       7155 :         free(schema);
    1169                 :            :     }
    1170                 :       7155 : }
    1171                 :            : 
    1172                 :            : /* Parses 'schema_json', an OVSDB schema in JSON format as described in RFC
    1173                 :            :  * 7047, to obtain the names of its rows and columns.  If successful, returns
    1174                 :            :  * an shash whose keys are table names and whose values are ssets, where each
    1175                 :            :  * sset contains the names of its table's columns.  On failure (due to a parse
    1176                 :            :  * error), returns NULL.
    1177                 :            :  *
    1178                 :            :  * It would also be possible to use the general-purpose OVSDB schema parser in
    1179                 :            :  * ovsdb-server, but that's overkill, possibly too strict for the current use
    1180                 :            :  * case, and would require restructuring ovsdb-server to separate the schema
    1181                 :            :  * code from the rest. */
    1182                 :            : static struct shash *
    1183                 :       7155 : parse_schema(const struct json *schema_json)
    1184                 :            : {
    1185                 :            :     struct ovsdb_parser parser;
    1186                 :            :     const struct json *tables_json;
    1187                 :            :     struct ovsdb_error *error;
    1188                 :            :     struct shash_node *node;
    1189                 :            :     struct shash *schema;
    1190                 :            : 
    1191                 :       7155 :     ovsdb_parser_init(&parser, schema_json, "database schema");
    1192                 :       7155 :     tables_json = ovsdb_parser_member(&parser, "tables", OP_OBJECT);
    1193                 :       7155 :     error = ovsdb_parser_destroy(&parser);
    1194         [ -  + ]:       7155 :     if (error) {
    1195                 :          0 :         log_error(error);
    1196                 :          0 :         return NULL;
    1197                 :            :     }
    1198                 :            : 
    1199                 :       7155 :     schema = xmalloc(sizeof *schema);
    1200                 :       7155 :     shash_init(schema);
    1201 [ +  + ][ -  + ]:     116841 :     SHASH_FOR_EACH (node, json_object(tables_json)) {
    1202                 :     109686 :         const char *table_name = node->name;
    1203                 :     109686 :         const struct json *json = node->data;
    1204                 :            :         const struct json *columns_json;
    1205                 :            : 
    1206                 :     109686 :         ovsdb_parser_init(&parser, json, "table schema for table %s",
    1207                 :            :                           table_name);
    1208                 :     109686 :         columns_json = ovsdb_parser_member(&parser, "columns", OP_OBJECT);
    1209                 :     109686 :         error = ovsdb_parser_destroy(&parser);
    1210         [ -  + ]:     109686 :         if (error) {
    1211                 :          0 :             log_error(error);
    1212                 :          0 :             free_schema(schema);
    1213                 :          0 :             return NULL;
    1214                 :            :         }
    1215                 :            : 
    1216                 :     109686 :         struct sset *columns = xmalloc(sizeof *columns);
    1217                 :     109686 :         sset_init(columns);
    1218                 :            : 
    1219                 :            :         struct shash_node *node2;
    1220 [ +  + ][ -  + ]:    1112172 :         SHASH_FOR_EACH (node2, json_object(columns_json)) {
    1221                 :    1002486 :             const char *column_name = node2->name;
    1222                 :    1002486 :             sset_add(columns, column_name);
    1223                 :            :         }
    1224                 :     109686 :         shash_add(schema, table_name, columns);
    1225                 :            :     }
    1226                 :       7155 :     return schema;
    1227                 :            : }
    1228                 :            : 
    1229                 :            : static void
    1230                 :       7155 : ovsdb_idl_send_monitor_request__(struct ovsdb_idl *idl,
    1231                 :            :                                  const char *method)
    1232                 :            : {
    1233                 :            :     struct shash *schema;
    1234                 :            :     struct json *monitor_requests;
    1235                 :            :     struct jsonrpc_msg *msg;
    1236                 :            :     char uuid[UUID_LEN + 1];
    1237                 :            :     size_t i;
    1238                 :            : 
    1239                 :       7155 :     schema = parse_schema(idl->schema);
    1240                 :       7155 :     monitor_requests = json_object_create();
    1241         [ +  + ]:     116842 :     for (i = 0; i < idl->class->n_tables; i++) {
    1242                 :     109687 :         struct ovsdb_idl_table *table = &idl->tables[i];
    1243                 :     109687 :         const struct ovsdb_idl_table_class *tc = table->class;
    1244                 :            :         struct json *monitor_request, *columns, *where;
    1245                 :            :         const struct sset *table_schema;
    1246                 :            :         size_t j;
    1247                 :            : 
    1248                 :     109687 :         table_schema = (schema
    1249                 :     109687 :                         ? shash_find_data(schema, table->class->name)
    1250         [ +  - ]:     109687 :                         : NULL);
    1251                 :            : 
    1252         [ +  + ]:     109687 :         columns = table->need_table ? json_array_create_empty() : NULL;
    1253         [ +  + ]:    1112176 :         for (j = 0; j < tc->n_columns; j++) {
    1254                 :    1002489 :             const struct ovsdb_idl_column *column = &tc->columns[j];
    1255         [ +  + ]:    1002489 :             if (table->modes[j] & OVSDB_IDL_MONITOR) {
    1256         [ +  + ]:     204808 :                 if (table_schema
    1257         [ +  + ]:     204806 :                     && !sset_contains(table_schema, column->name)) {
    1258         [ +  - ]:          1 :                     VLOG_WARN("%s table in %s database lacks %s column "
    1259                 :            :                               "(database needs upgrade?)",
    1260                 :            :                               table->class->name, idl->class->database,
    1261                 :            :                               column->name);
    1262                 :          1 :                     continue;
    1263                 :            :                 }
    1264         [ +  + ]:     204807 :                 if (!columns) {
    1265                 :      22308 :                     columns = json_array_create_empty();
    1266                 :            :                 }
    1267                 :     204807 :                 json_array_add(columns, json_string_create(column->name));
    1268                 :            :             }
    1269                 :            :         }
    1270                 :            : 
    1271         [ +  + ]:     109687 :         if (columns) {
    1272 [ +  - ][ +  + ]:      45023 :             if (schema && !table_schema) {
    1273         [ +  - ]:          1 :                 VLOG_WARN("%s database lacks %s table "
    1274                 :            :                           "(database needs upgrade?)",
    1275                 :            :                           idl->class->database, table->class->name);
    1276                 :          1 :                 json_destroy(columns);
    1277                 :          1 :                 continue;
    1278                 :            :             }
    1279                 :            : 
    1280                 :      45022 :             monitor_request = json_object_create();
    1281                 :      45022 :             json_object_put(monitor_request, "columns", columns);
    1282         [ +  + ]:      45030 :             if (!strcmp(method, "monitor_cond") && table->cond_changed &&
           [ +  +  +  - ]
    1283                 :          8 :                 ovs_list_size(&table->condition.clauses) > 0) {
    1284                 :          8 :                 where = ovsdb_idl_condition_to_json(&table->condition);
    1285                 :          8 :                 json_object_put(monitor_request, "where", where);
    1286                 :          8 :                 table->cond_changed = false;
    1287                 :            :             }
    1288                 :      45022 :             json_object_put(monitor_requests, tc->name, monitor_request);
    1289                 :            :         }
    1290                 :            :     }
    1291                 :       7155 :     free_schema(schema);
    1292                 :            : 
    1293                 :       7155 :     json_destroy(idl->request_id);
    1294                 :            : 
    1295                 :       7155 :     snprintf(uuid, sizeof uuid, UUID_FMT, UUID_ARGS(&idl->uuid));
    1296                 :       7155 :     msg = jsonrpc_create_request(
    1297                 :            :         method,
    1298                 :       7155 :         json_array_create_3(json_string_create(idl->class->database),
    1299                 :            :                             json_string_create(uuid), monitor_requests),
    1300                 :            :         &idl->request_id);
    1301                 :       7155 :     jsonrpc_session_send(idl->session, msg);
    1302                 :       7155 :     idl->cond_changed = false;
    1303                 :       7155 : }
    1304                 :            : 
    1305                 :            : static void
    1306                 :          3 : ovsdb_idl_send_monitor_request(struct ovsdb_idl *idl)
    1307                 :            : {
    1308                 :          3 :     ovsdb_idl_send_monitor_request__(idl, "monitor");
    1309                 :          3 : }
    1310                 :            : 
    1311                 :            : static void
    1312                 :          0 : log_parse_update_error(struct ovsdb_error *error)
    1313                 :            : {
    1314         [ #  # ]:          0 :         if (!VLOG_DROP_WARN(&syntax_rl)) {
    1315                 :          0 :             char *s = ovsdb_error_to_string(error);
    1316         [ #  # ]:          0 :             VLOG_WARN_RL(&syntax_rl, "%s", s);
    1317                 :          0 :             free(s);
    1318                 :            :         }
    1319                 :          0 :         ovsdb_error_destroy(error);
    1320                 :          0 : }
    1321                 :            : 
    1322                 :            : static void
    1323                 :       7152 : ovsdb_idl_send_monitor_cond_request(struct ovsdb_idl *idl)
    1324                 :            : {
    1325                 :       7152 :     ovsdb_idl_send_monitor_request__(idl, "monitor_cond");
    1326                 :       7152 : }
    1327                 :            : 
    1328                 :            : static void
    1329                 :      24648 : ovsdb_idl_parse_update(struct ovsdb_idl *idl, const struct json *table_updates,
    1330                 :            :                        enum ovsdb_update_version version)
    1331                 :            : {
    1332                 :      24648 :     struct ovsdb_error *error = ovsdb_idl_parse_update__(idl, table_updates,
    1333                 :            :                                                          version);
    1334         [ -  + ]:      24648 :     if (error) {
    1335                 :          0 :         log_parse_update_error(error);
    1336                 :            :     }
    1337                 :      24648 : }
    1338                 :            : 
    1339                 :            : static struct ovsdb_error *
    1340                 :      24648 : ovsdb_idl_parse_update__(struct ovsdb_idl *idl,
    1341                 :            :                          const struct json *table_updates,
    1342                 :            :                          enum ovsdb_update_version version)
    1343                 :            : {
    1344                 :            :     const struct shash_node *tables_node;
    1345                 :      24648 :     const char *table_updates_name = table_updates_names[version];
    1346                 :      24648 :     const char *table_update_name = table_update_names[version];
    1347                 :      24648 :     const char *row_update_name = row_update_names[version];
    1348                 :            : 
    1349         [ -  + ]:      24648 :     if (table_updates->type != JSON_OBJECT) {
    1350                 :          0 :         return ovsdb_syntax_error(table_updates, NULL,
    1351                 :            :                                   "<%s> is not an object",
    1352                 :            :                                   table_updates_name);
    1353                 :            :     }
    1354                 :            : 
    1355 [ +  + ][ -  + ]:      77379 :     SHASH_FOR_EACH (tables_node, json_object(table_updates)) {
    1356                 :      52731 :         const struct json *table_update = tables_node->data;
    1357                 :            :         const struct shash_node *table_node;
    1358                 :            :         struct ovsdb_idl_table *table;
    1359                 :            : 
    1360                 :      52731 :         table = shash_find_data(&idl->table_by_name, tables_node->name);
    1361         [ -  + ]:      52731 :         if (!table) {
    1362                 :          0 :             return ovsdb_syntax_error(
    1363                 :            :                 table_updates, NULL,
    1364                 :            :                 "<%s> includes unknown table \"%s\"",
    1365                 :            :                 table_updates_name,
    1366                 :            :                 tables_node->name);
    1367                 :            :         }
    1368                 :            : 
    1369         [ -  + ]:      52731 :         if (table_update->type != JSON_OBJECT) {
    1370                 :          0 :             return ovsdb_syntax_error(table_update, NULL,
    1371                 :            :                                       "<%s> for table \"%s\" is "
    1372                 :            :                                       "not an object",
    1373                 :            :                                       table_update_name,
    1374                 :          0 :                                       table->class->name);
    1375                 :            :         }
    1376 [ +  + ][ -  + ]:     198037 :         SHASH_FOR_EACH (table_node, json_object(table_update)) {
    1377                 :     145306 :             const struct json *row_update = table_node->data;
    1378                 :            :             const struct json *old_json, *new_json;
    1379                 :            :             struct uuid uuid;
    1380                 :            : 
    1381         [ -  + ]:     145306 :             if (!uuid_from_string(&uuid, table_node->name)) {
    1382                 :          0 :                 return ovsdb_syntax_error(table_update, NULL,
    1383                 :            :                                           "<%s> for table \"%s\" "
    1384                 :            :                                           "contains bad UUID "
    1385                 :            :                                           "\"%s\" as member name",
    1386                 :            :                                           table_update_name,
    1387                 :          0 :                                           table->class->name,
    1388                 :            :                                           table_node->name);
    1389                 :            :             }
    1390         [ -  + ]:     145306 :             if (row_update->type != JSON_OBJECT) {
    1391                 :          0 :                 return ovsdb_syntax_error(row_update, NULL,
    1392                 :            :                                           "<%s> for table \"%s\" "
    1393                 :            :                                           "contains <%s> for %s that "
    1394                 :            :                                           "is not an object",
    1395                 :            :                                           table_update_name,
    1396                 :          0 :                                           table->class->name,
    1397                 :            :                                           row_update_name,
    1398                 :            :                                           table_node->name);
    1399                 :            :             }
    1400                 :            : 
    1401      [ +  +  - ]:     145306 :             switch(version) {
    1402                 :            :             case OVSDB_UPDATE:
    1403                 :         36 :                 old_json = shash_find_data(json_object(row_update), "old");
    1404                 :         36 :                 new_json = shash_find_data(json_object(row_update), "new");
    1405 [ +  + ][ -  + ]:         36 :                 if (old_json && old_json->type != JSON_OBJECT) {
    1406                 :          0 :                     return ovsdb_syntax_error(old_json, NULL,
    1407                 :            :                                               "\"old\" <row> is not object");
    1408 [ +  - ][ -  + ]:         36 :                 } else if (new_json && new_json->type != JSON_OBJECT) {
    1409                 :          0 :                     return ovsdb_syntax_error(new_json, NULL,
    1410                 :            :                                               "\"new\" <row> is not object");
    1411         [ -  + ]:         36 :                 } else if ((old_json != NULL) + (new_json != NULL)
    1412                 :         36 :                            != shash_count(json_object(row_update))) {
    1413                 :          0 :                     return ovsdb_syntax_error(row_update, NULL,
    1414                 :            :                                               "<row-update> contains "
    1415                 :            :                                               "unexpected member");
    1416 [ +  + ][ -  + ]:         36 :                 } else if (!old_json && !new_json) {
    1417                 :          0 :                     return ovsdb_syntax_error(row_update, NULL,
    1418                 :            :                                               "<row-update> missing \"old\" "
    1419                 :            :                                               "and \"new\" members");
    1420                 :            :                 }
    1421                 :            : 
    1422         [ +  + ]:         36 :                 if (ovsdb_idl_process_update(table, &uuid, old_json,
    1423                 :            :                                              new_json)) {
    1424                 :         32 :                     idl->change_seqno++;
    1425                 :            :                 }
    1426                 :         36 :                 break;
    1427                 :            : 
    1428                 :            :             case OVSDB_UPDATE2: {
    1429                 :     145270 :                 const char *ops[] = {"modify", "insert", "delete", "initial"};
    1430                 :            :                 const char *operation;
    1431                 :            :                 const struct json *row;
    1432                 :            :                 int i;
    1433                 :            : 
    1434         [ +  - ]:     443696 :                 for (i = 0; i < ARRAY_SIZE(ops); i++) {
    1435                 :     443696 :                     operation = ops[i];
    1436                 :     443696 :                     row = shash_find_data(json_object(row_update), operation);
    1437                 :            : 
    1438         [ +  + ]:     443696 :                     if (row)  {
    1439         [ +  + ]:     145270 :                         if (ovsdb_idl_process_update2(table, &uuid, operation,
    1440                 :            :                                                       row)) {
    1441                 :     133394 :                             idl->change_seqno++;
    1442                 :            :                         }
    1443                 :     145270 :                         break;
    1444                 :            :                     }
    1445                 :            :                 }
    1446                 :            : 
    1447                 :            :                 /* row_update2 should contain one of the objects */
    1448         [ -  + ]:     145270 :                 if (i == ARRAY_SIZE(ops)) {
    1449                 :          0 :                     return ovsdb_syntax_error(row_update, NULL,
    1450                 :            :                                               "<row_update2> includes unknown "
    1451                 :            :                                               "object");
    1452                 :            :                 }
    1453                 :     145270 :                 break;
    1454                 :            :             }
    1455                 :            : 
    1456                 :            :             default:
    1457                 :          0 :                 OVS_NOT_REACHED();
    1458                 :            :             }
    1459                 :            :         }
    1460                 :            :     }
    1461                 :            : 
    1462                 :      24648 :     return NULL;
    1463                 :            : }
    1464                 :            : 
    1465                 :            : static struct ovsdb_idl_row *
    1466                 :     687041 : ovsdb_idl_get_row(struct ovsdb_idl_table *table, const struct uuid *uuid)
    1467                 :            : {
    1468                 :            :     struct ovsdb_idl_row *row;
    1469                 :            : 
    1470 [ +  + ][ -  + ]:     687041 :     HMAP_FOR_EACH_WITH_HASH (row, hmap_node, uuid_hash(uuid), &table->rows) {
    1471         [ +  - ]:     572521 :         if (uuid_equals(&row->uuid, uuid)) {
    1472                 :     572521 :             return row;
    1473                 :            :         }
    1474                 :            :     }
    1475                 :     114520 :     return NULL;
    1476                 :            : }
    1477                 :            : 
    1478                 :            : /* Returns true if a column with mode OVSDB_IDL_MODE_RW changed, false
    1479                 :            :  * otherwise. */
    1480                 :            : static bool
    1481                 :         36 : ovsdb_idl_process_update(struct ovsdb_idl_table *table,
    1482                 :            :                          const struct uuid *uuid, const struct json *old,
    1483                 :            :                          const struct json *new)
    1484                 :            : {
    1485                 :            :     struct ovsdb_idl_row *row;
    1486                 :            : 
    1487                 :         36 :     row = ovsdb_idl_get_row(table, uuid);
    1488         [ -  + ]:         36 :     if (!new) {
    1489                 :            :         /* Delete row. */
    1490 [ #  # ][ #  # ]:          0 :         if (row && !ovsdb_idl_row_is_orphan(row)) {
    1491                 :            :             /* XXX perhaps we should check the 'old' values? */
    1492                 :          0 :             ovsdb_idl_delete_row(row);
    1493                 :            :         } else {
    1494         [ #  # ]:          0 :             VLOG_WARN_RL(&semantic_rl, "cannot delete missing row "UUID_FMT" "
    1495                 :            :                          "from table %s",
    1496                 :            :                          UUID_ARGS(uuid), table->class->name);
    1497                 :          0 :             return false;
    1498                 :            :         }
    1499         [ +  + ]:         36 :     } else if (!old) {
    1500                 :            :         /* Insert row. */
    1501         [ +  - ]:         22 :         if (!row) {
    1502                 :         22 :             ovsdb_idl_insert_row(ovsdb_idl_row_create(table, uuid), new);
    1503         [ #  # ]:          0 :         } else if (ovsdb_idl_row_is_orphan(row)) {
    1504                 :          0 :             ovsdb_idl_insert_row(row, new);
    1505                 :            :         } else {
    1506         [ #  # ]:          0 :             VLOG_WARN_RL(&semantic_rl, "cannot add existing row "UUID_FMT" to "
    1507                 :            :                          "table %s", UUID_ARGS(uuid), table->class->name);
    1508                 :          0 :             return ovsdb_idl_modify_row(row, new);
    1509                 :            :         }
    1510                 :            :     } else {
    1511                 :            :         /* Modify row. */
    1512         [ +  - ]:         14 :         if (row) {
    1513                 :            :             /* XXX perhaps we should check the 'old' values? */
    1514         [ +  - ]:         14 :             if (!ovsdb_idl_row_is_orphan(row)) {
    1515                 :         14 :                 return ovsdb_idl_modify_row(row, new);
    1516                 :            :             } else {
    1517         [ #  # ]:          0 :                 VLOG_WARN_RL(&semantic_rl, "cannot modify missing but "
    1518                 :            :                              "referenced row "UUID_FMT" in table %s",
    1519                 :            :                              UUID_ARGS(uuid), table->class->name);
    1520                 :          0 :                 ovsdb_idl_insert_row(row, new);
    1521                 :            :             }
    1522                 :            :         } else {
    1523         [ #  # ]:          0 :             VLOG_WARN_RL(&semantic_rl, "cannot modify missing row "UUID_FMT" "
    1524                 :            :                          "in table %s", UUID_ARGS(uuid), table->class->name);
    1525                 :          0 :             ovsdb_idl_insert_row(ovsdb_idl_row_create(table, uuid), new);
    1526                 :            :         }
    1527                 :            :     }
    1528                 :            : 
    1529                 :         22 :     return true;
    1530                 :            : }
    1531                 :            : 
    1532                 :            : /* Returns true if a column with mode OVSDB_IDL_MODE_RW changed, false
    1533                 :            :  * otherwise. */
    1534                 :            : static bool
    1535                 :     145270 : ovsdb_idl_process_update2(struct ovsdb_idl_table *table,
    1536                 :            :                           const struct uuid *uuid,
    1537                 :            :                           const char *operation,
    1538                 :            :                           const struct json *json_row)
    1539                 :            : {
    1540                 :            :     struct ovsdb_idl_row *row;
    1541                 :            : 
    1542                 :     145270 :     row = ovsdb_idl_get_row(table, uuid);
    1543         [ +  + ]:     145270 :     if (!strcmp(operation, "delete")) {
    1544                 :            :         /* Delete row. */
    1545 [ +  - ][ +  - ]:       4782 :         if (row && !ovsdb_idl_row_is_orphan(row)) {
    1546                 :       4782 :             ovsdb_idl_delete_row(row);
    1547                 :            :         } else {
    1548         [ #  # ]:          0 :             VLOG_WARN_RL(&semantic_rl, "cannot delete missing row "UUID_FMT" "
    1549                 :            :                          "from table %s",
    1550                 :            :                          UUID_ARGS(uuid), table->class->name);
    1551                 :          0 :             return false;
    1552                 :            :         }
    1553 [ +  + ][ +  + ]:     140488 :     } else if (!strcmp(operation, "insert") || !strcmp(operation, "initial")) {
    1554                 :            :         /* Insert row. */
    1555         [ +  + ]:     228224 :         if (!row) {
    1556                 :     106805 :             ovsdb_idl_insert_row(ovsdb_idl_row_create(table, uuid), json_row);
    1557         [ +  - ]:       7307 :         } else if (ovsdb_idl_row_is_orphan(row)) {
    1558                 :       7307 :             ovsdb_idl_insert_row(row, json_row);
    1559                 :            :         } else {
    1560         [ #  # ]:          0 :             VLOG_WARN_RL(&semantic_rl, "cannot add existing row "UUID_FMT" to "
    1561                 :            :                          "table %s", UUID_ARGS(uuid), table->class->name);
    1562                 :          0 :             ovsdb_idl_delete_row(row);
    1563                 :          0 :             ovsdb_idl_insert_row(row, json_row);
    1564                 :            :         }
    1565         [ +  - ]:      26376 :     } else if (!strcmp(operation, "modify")) {
    1566                 :            :         /* Modify row. */
    1567         [ +  - ]:      26376 :         if (row) {
    1568         [ +  - ]:      26376 :             if (!ovsdb_idl_row_is_orphan(row)) {
    1569                 :      26376 :                 return ovsdb_idl_modify_row_by_diff(row, json_row);
    1570                 :            :             } else {
    1571         [ #  # ]:          0 :                 VLOG_WARN_RL(&semantic_rl, "cannot modify missing but "
    1572                 :            :                              "referenced row "UUID_FMT" in table %s",
    1573                 :            :                              UUID_ARGS(uuid), table->class->name);
    1574                 :          0 :                 return false;
    1575                 :            :             }
    1576                 :            :         } else {
    1577         [ #  # ]:          0 :             VLOG_WARN_RL(&semantic_rl, "cannot modify missing row "UUID_FMT" "
    1578                 :            :                          "in table %s", UUID_ARGS(uuid), table->class->name);
    1579                 :          0 :             return false;
    1580                 :            :         }
    1581                 :            :     } else {
    1582         [ #  # ]:          0 :             VLOG_WARN_RL(&semantic_rl, "unknown operation %s to "
    1583                 :            :                          "table %s", operation, table->class->name);
    1584                 :          0 :             return false;
    1585                 :            :     }
    1586                 :            : 
    1587                 :     118894 :     return true;
    1588                 :            : }
    1589                 :            : 
    1590                 :            : /* Returns true if a column with mode OVSDB_IDL_MODE_RW changed, false
    1591                 :            :  * otherwise.
    1592                 :            :  *
    1593                 :            :  * Change 'row' either with the content of 'row_json' or by apply 'diff'.
    1594                 :            :  * Caller needs to provide either valid 'row_json' or 'diff', but not
    1595                 :            :  * both.  */
    1596                 :            : static bool
    1597                 :     140524 : ovsdb_idl_row_change__(struct ovsdb_idl_row *row, const struct json *row_json,
    1598                 :            :                        const struct json *diff_json,
    1599                 :            :                        enum ovsdb_idl_change change)
    1600                 :            : {
    1601                 :     140524 :     struct ovsdb_idl_table *table = row->table;
    1602                 :     140524 :     const struct ovsdb_idl_table_class *class = table->class;
    1603                 :            :     struct shash_node *node;
    1604                 :     140524 :     bool changed = false;
    1605                 :     140524 :     bool apply_diff = diff_json != NULL;
    1606         [ +  + ]:     140524 :     const struct json *json = apply_diff ? diff_json : row_json;
    1607                 :            : 
    1608 [ +  + ][ -  + ]:     546812 :     SHASH_FOR_EACH (node, json_object(json)) {
    1609                 :     406288 :         const char *column_name = node->name;
    1610                 :            :         const struct ovsdb_idl_column *column;
    1611                 :            :         struct ovsdb_datum datum;
    1612                 :            :         struct ovsdb_error *error;
    1613                 :            :         unsigned int column_idx;
    1614                 :            :         struct ovsdb_datum *old;
    1615                 :            : 
    1616                 :     406288 :         column = shash_find_data(&table->columns, column_name);
    1617         [ -  + ]:     406288 :         if (!column) {
    1618         [ #  # ]:          0 :             VLOG_WARN_RL(&syntax_rl, "unknown column %s updating row "UUID_FMT,
    1619                 :            :                          column_name, UUID_ARGS(&row->uuid));
    1620                 :          0 :             continue;
    1621                 :            :         }
    1622                 :            : 
    1623                 :     406288 :         column_idx = column - table->class->columns;
    1624                 :     406288 :         old = &row->old[column_idx];
    1625                 :            : 
    1626                 :     406288 :         error = NULL;
    1627         [ +  + ]:     406288 :         if (apply_diff) {
    1628                 :            :             struct ovsdb_datum diff;
    1629                 :            : 
    1630         [ -  + ]:      45815 :             ovs_assert(!row_json);
    1631                 :      45815 :             error = ovsdb_transient_datum_from_json(&diff, &column->type,
    1632                 :      45815 :                                                     node->data);
    1633         [ +  - ]:      45815 :             if (!error) {
    1634                 :      45815 :                 error = ovsdb_datum_apply_diff(&datum, old, &diff,
    1635                 :            :                                                &column->type);
    1636                 :      45815 :                 ovsdb_datum_destroy(&diff, &column->type);
    1637                 :            :             }
    1638                 :            :         } else {
    1639         [ -  + ]:     360473 :             ovs_assert(!diff_json);
    1640                 :     360473 :             error = ovsdb_datum_from_json(&datum, &column->type, node->data,
    1641                 :            :                                           NULL);
    1642                 :            :         }
    1643                 :            : 
    1644         [ +  - ]:     406288 :         if (!error) {
    1645         [ +  + ]:     406288 :             if (!ovsdb_datum_equals(old, &datum, &column->type)) {
    1646                 :     405992 :                 ovsdb_datum_swap(old, &datum);
    1647         [ +  + ]:     405992 :                 if (table->modes[column_idx] & OVSDB_IDL_ALERT) {
    1648                 :     343697 :                     changed = true;
    1649                 :            :                     row->change_seqno[change]
    1650                 :     687394 :                         = row->table->change_seqno[change]
    1651                 :     343697 :                         = row->table->idl->change_seqno + 1;
    1652         [ +  + ]:     343697 :                     if (table->modes[column_idx] & OVSDB_IDL_TRACK) {
    1653         [ +  + ]:      51280 :                         if (!ovs_list_is_empty(&row->track_node)) {
    1654                 :      41702 :                             ovs_list_remove(&row->track_node);
    1655                 :            :                         }
    1656                 :      51280 :                         ovs_list_push_back(&row->table->track_list,
    1657                 :            :                                        &row->track_node);
    1658         [ +  + ]:      51280 :                         if (!row->updated) {
    1659                 :       9578 :                             row->updated = bitmap_allocate(class->n_columns);
    1660                 :            :                         }
    1661                 :     405992 :                         bitmap_set1(row->updated, column_idx);
    1662                 :            :                     }
    1663                 :            :                 }
    1664                 :            :             } else {
    1665                 :            :                 /* Didn't really change but the OVSDB monitor protocol always
    1666                 :            :                  * includes every value in a row. */
    1667                 :            :             }
    1668                 :            : 
    1669                 :     406288 :             ovsdb_datum_destroy(&datum, &column->type);
    1670                 :            :         } else {
    1671                 :          0 :             char *s = ovsdb_error_to_string(error);
    1672         [ #  # ]:          0 :             VLOG_WARN_RL(&syntax_rl, "error parsing column %s in row "UUID_FMT
    1673                 :            :                          " in table %s: %s", column_name,
    1674                 :            :                          UUID_ARGS(&row->uuid), table->class->name, s);
    1675                 :          0 :             free(s);
    1676                 :     406288 :             ovsdb_error_destroy(error);
    1677                 :            :         }
    1678                 :            :     }
    1679                 :     140524 :     return changed;
    1680                 :            : }
    1681                 :            : 
    1682                 :            : static bool
    1683                 :     114148 : ovsdb_idl_row_update(struct ovsdb_idl_row *row, const struct json *row_json,
    1684                 :            :                      enum ovsdb_idl_change change)
    1685                 :            : {
    1686                 :     114148 :     return ovsdb_idl_row_change__(row, row_json, NULL, change);
    1687                 :            : }
    1688                 :            : 
    1689                 :            : static bool
    1690                 :      26376 : ovsdb_idl_row_apply_diff(struct ovsdb_idl_row *row,
    1691                 :            :                          const struct json *diff_json,
    1692                 :            :                          enum ovsdb_idl_change change)
    1693                 :            : {
    1694                 :      26376 :     return ovsdb_idl_row_change__(row, NULL, diff_json, change);
    1695                 :            : }
    1696                 :            : 
    1697                 :            : /* When a row A refers to row B through a column with a "refTable" constraint,
    1698                 :            :  * but row B does not exist, row B is called an "orphan row".  Orphan rows
    1699                 :            :  * should not persist, because the database enforces referential integrity, but
    1700                 :            :  * they can appear transiently as changes from the database are received (the
    1701                 :            :  * database doesn't try to topologically sort them and circular references mean
    1702                 :            :  * it isn't always possible anyhow).
    1703                 :            :  *
    1704                 :            :  * This function returns true if 'row' is an orphan row, otherwise false.
    1705                 :            :  */
    1706                 :            : static bool
    1707                 :     928412 : ovsdb_idl_row_is_orphan(const struct ovsdb_idl_row *row)
    1708                 :            : {
    1709 [ +  + ][ +  - ]:     928412 :     return !row->old && !row->new;
    1710                 :            : }
    1711                 :            : 
    1712                 :            : /* Returns true if 'row' is conceptually part of the database as modified by
    1713                 :            :  * the current transaction (if any), false otherwise.
    1714                 :            :  *
    1715                 :            :  * This function will return true if 'row' is not an orphan (see the comment on
    1716                 :            :  * ovsdb_idl_row_is_orphan()) and:
    1717                 :            :  *
    1718                 :            :  *   - 'row' exists in the database and has not been deleted within the
    1719                 :            :  *     current transaction (if any).
    1720                 :            :  *
    1721                 :            :  *   - 'row' was inserted within the current transaction and has not been
    1722                 :            :  *     deleted.  (In the latter case you should not have passed 'row' in at
    1723                 :            :  *     all, because ovsdb_idl_txn_delete() freed it.)
    1724                 :            :  *
    1725                 :            :  * This function will return false if 'row' is an orphan or if 'row' was
    1726                 :            :  * deleted within the current transaction.
    1727                 :            :  */
    1728                 :            : static bool
    1729                 :    2167612 : ovsdb_idl_row_exists(const struct ovsdb_idl_row *row)
    1730                 :            : {
    1731                 :    2167612 :     return row->new != NULL;
    1732                 :            : }
    1733                 :            : 
    1734                 :            : static void
    1735                 :     185975 : ovsdb_idl_row_parse(struct ovsdb_idl_row *row)
    1736                 :            : {
    1737                 :     185975 :     const struct ovsdb_idl_table_class *class = row->table->class;
    1738                 :            :     size_t i;
    1739                 :            : 
    1740         [ +  + ]:    4129755 :     for (i = 0; i < class->n_columns; i++) {
    1741                 :    3943780 :         const struct ovsdb_idl_column *c = &class->columns[i];
    1742                 :    3943780 :         (c->parse)(row, &row->old[i]);
    1743                 :            :     }
    1744                 :     185975 : }
    1745                 :            : 
    1746                 :            : static void
    1747                 :     202921 : ovsdb_idl_row_unparse(struct ovsdb_idl_row *row)
    1748                 :            : {
    1749                 :     202921 :     const struct ovsdb_idl_table_class *class = row->table->class;
    1750                 :            :     size_t i;
    1751                 :            : 
    1752         [ +  + ]:    4430887 :     for (i = 0; i < class->n_columns; i++) {
    1753                 :    4227966 :         const struct ovsdb_idl_column *c = &class->columns[i];
    1754                 :    4227966 :         (c->unparse)(row);
    1755                 :            :     }
    1756                 :     202921 : }
    1757                 :            : 
    1758                 :            : static void
    1759                 :     229478 : ovsdb_idl_row_clear_old(struct ovsdb_idl_row *row)
    1760                 :            : {
    1761         [ -  + ]:     229478 :     ovs_assert(row->old == row->new);
    1762         [ +  + ]:     229478 :     if (!ovsdb_idl_row_is_orphan(row)) {
    1763                 :     114131 :         const struct ovsdb_idl_table_class *class = row->table->class;
    1764                 :            :         size_t i;
    1765                 :            : 
    1766         [ +  + ]:    2448542 :         for (i = 0; i < class->n_columns; i++) {
    1767                 :    2334411 :             ovsdb_datum_destroy(&row->old[i], &class->columns[i].type);
    1768                 :            :         }
    1769                 :     114131 :         free(row->old);
    1770                 :     114131 :         row->old = row->new = NULL;
    1771                 :            :     }
    1772                 :     229478 : }
    1773                 :            : 
    1774                 :            : static void
    1775                 :      82117 : ovsdb_idl_row_clear_new(struct ovsdb_idl_row *row)
    1776                 :            : {
    1777         [ +  + ]:      82117 :     if (row->old != row->new) {
    1778         [ +  + ]:      51740 :         if (row->new) {
    1779                 :      48198 :             const struct ovsdb_idl_table_class *class = row->table->class;
    1780                 :            :             size_t i;
    1781                 :            : 
    1782         [ +  + ]:      48198 :             if (row->written) {
    1783         [ +  + ]:     184719 :                 BITMAP_FOR_EACH_1 (i, class->n_columns, row->written) {
    1784                 :     137245 :                     ovsdb_datum_destroy(&row->new[i], &class->columns[i].type);
    1785                 :            :                 }
    1786                 :            :             }
    1787                 :      48198 :             free(row->new);
    1788                 :      48198 :             free(row->written);
    1789                 :      48198 :             row->written = NULL;
    1790                 :            :         }
    1791                 :      51740 :         row->new = row->old;
    1792                 :            :     }
    1793                 :      82117 : }
    1794                 :            : 
    1795                 :            : static void
    1796                 :      76623 : ovsdb_idl_row_clear_arcs(struct ovsdb_idl_row *row, bool destroy_dsts)
    1797                 :            : {
    1798                 :            :     struct ovsdb_idl_arc *arc, *next;
    1799                 :            : 
    1800                 :            :     /* Delete all forward arcs.  If 'destroy_dsts', destroy any orphaned rows
    1801                 :            :      * that this causes to be unreferenced, if tracking is not enabled.
    1802                 :            :      * If tracking is enabled, orphaned nodes are removed from hmap but not
    1803                 :            :      * freed.
    1804                 :            :      */
    1805 [ +  + ][ +  + ]:     349864 :     LIST_FOR_EACH_SAFE (arc, next, src_node, &row->src_arcs) {
    1806                 :     273241 :         ovs_list_remove(&arc->dst_node);
    1807         [ +  + ]:     273241 :         if (destroy_dsts
    1808         [ +  + ]:      65669 :             && ovsdb_idl_row_is_orphan(arc->dst)
    1809         [ +  + ]:       4131 :             && ovs_list_is_empty(&arc->dst->dst_arcs)) {
    1810                 :       3507 :             ovsdb_idl_row_destroy(arc->dst);
    1811                 :            :         }
    1812                 :     273241 :         free(arc);
    1813                 :            :     }
    1814                 :      76623 :     ovs_list_init(&row->src_arcs);
    1815                 :      76623 : }
    1816                 :            : 
    1817                 :            : /* Force nodes that reference 'row' to reparse. */
    1818                 :            : static void
    1819                 :     117594 : ovsdb_idl_row_reparse_backrefs(struct ovsdb_idl_row *row)
    1820                 :            : {
    1821                 :            :     struct ovsdb_idl_arc *arc, *next;
    1822                 :            : 
    1823                 :            :     /* This is trickier than it looks.  ovsdb_idl_row_clear_arcs() will destroy
    1824                 :            :      * 'arc', so we need to use the "safe" variant of list traversal.  However,
    1825                 :            :      * calling an ovsdb_idl_column's 'parse' function will add an arc
    1826                 :            :      * equivalent to 'arc' to row->arcs.  That could be a problem for
    1827                 :            :      * traversal, but it adds it at the beginning of the list to prevent us
    1828                 :            :      * from stumbling upon it again.
    1829                 :            :      *
    1830                 :            :      * (If duplicate arcs were possible then we would need to make sure that
    1831                 :            :      * 'next' didn't also point into 'arc''s destination, but we forbid
    1832                 :            :      * duplicate arcs.) */
    1833 [ +  + ][ +  + ]:     131825 :     LIST_FOR_EACH_SAFE (arc, next, dst_node, &row->dst_arcs) {
    1834                 :      14231 :         struct ovsdb_idl_row *ref = arc->src;
    1835                 :            : 
    1836                 :      14231 :         ovsdb_idl_row_unparse(ref);
    1837                 :      14231 :         ovsdb_idl_row_clear_arcs(ref, false);
    1838                 :      14231 :         ovsdb_idl_row_parse(ref);
    1839                 :            :     }
    1840                 :     117594 : }
    1841                 :            : 
    1842                 :            : static struct ovsdb_idl_row *
    1843                 :     131396 : ovsdb_idl_row_create__(const struct ovsdb_idl_table_class *class)
    1844                 :            : {
    1845                 :     131396 :     struct ovsdb_idl_row *row = xzalloc(class->allocation_size);
    1846                 :     131396 :     class->row_init(row);
    1847                 :     131396 :     ovs_list_init(&row->src_arcs);
    1848                 :     131396 :     ovs_list_init(&row->dst_arcs);
    1849                 :     131396 :     hmap_node_nullify(&row->txn_node);
    1850                 :     131396 :     ovs_list_init(&row->track_node);
    1851                 :     131396 :     return row;
    1852                 :            : }
    1853                 :            : 
    1854                 :            : static struct ovsdb_idl_row *
    1855                 :     114447 : ovsdb_idl_row_create(struct ovsdb_idl_table *table, const struct uuid *uuid)
    1856                 :            : {
    1857                 :     114447 :     struct ovsdb_idl_row *row = ovsdb_idl_row_create__(table->class);
    1858                 :     114447 :     hmap_insert(&table->rows, &row->hmap_node, uuid_hash(uuid));
    1859                 :     114447 :     row->uuid = *uuid;
    1860                 :     114447 :     row->table = table;
    1861                 :     114447 :     row->map_op_written = NULL;
    1862                 :     114447 :     row->map_op_lists = NULL;
    1863                 :     114447 :     row->set_op_written = NULL;
    1864                 :     114447 :     row->set_op_lists = NULL;
    1865                 :     114447 :     return row;
    1866                 :            : }
    1867                 :            : 
    1868                 :            : static void
    1869                 :     114444 : ovsdb_idl_row_destroy(struct ovsdb_idl_row *row)
    1870                 :            : {
    1871         [ +  - ]:     114444 :     if (row) {
    1872                 :     114444 :         ovsdb_idl_row_clear_old(row);
    1873                 :     114444 :         hmap_remove(&row->table->rows, &row->hmap_node);
    1874                 :     114444 :         ovsdb_idl_destroy_all_map_op_lists(row);
    1875                 :     114444 :         ovsdb_idl_destroy_all_set_op_lists(row);
    1876         [ +  + ]:     114444 :         if (ovsdb_idl_track_is_set(row->table)) {
    1877                 :            :             row->change_seqno[OVSDB_IDL_CHANGE_DELETE]
    1878                 :       9011 :                 = row->table->change_seqno[OVSDB_IDL_CHANGE_DELETE]
    1879                 :       9011 :                 = row->table->idl->change_seqno + 1;
    1880                 :            :         }
    1881         [ +  + ]:     114444 :         if (!ovs_list_is_empty(&row->track_node)) {
    1882                 :        131 :             ovs_list_remove(&row->track_node);
    1883                 :            :         }
    1884                 :     114444 :         ovs_list_push_back(&row->table->track_list, &row->track_node);
    1885                 :            :     }
    1886                 :     114444 : }
    1887                 :            : 
    1888                 :            : static void
    1889                 :     192996 : ovsdb_idl_destroy_all_map_op_lists(struct ovsdb_idl_row *row)
    1890                 :            : {
    1891         [ +  + ]:     192996 :     if (row->map_op_written) {
    1892                 :            :         /* Clear Map Operation Lists */
    1893                 :            :         size_t idx, n_columns;
    1894                 :            :         const struct ovsdb_idl_column *columns;
    1895                 :            :         const struct ovsdb_type *type;
    1896                 :          4 :         n_columns = row->table->class->n_columns;
    1897                 :          4 :         columns = row->table->class->columns;
    1898         [ +  + ]:          9 :         BITMAP_FOR_EACH_1 (idx, n_columns, row->map_op_written) {
    1899                 :          5 :             type = &columns[idx].type;
    1900                 :          5 :             map_op_list_destroy(row->map_op_lists[idx], type);
    1901                 :            :         }
    1902                 :          4 :         free(row->map_op_lists);
    1903                 :          4 :         bitmap_free(row->map_op_written);
    1904                 :          4 :         row->map_op_lists = NULL;
    1905                 :          4 :         row->map_op_written = NULL;
    1906                 :            :     }
    1907                 :     192996 : }
    1908                 :            : 
    1909                 :            : static void
    1910                 :     192996 : ovsdb_idl_destroy_all_set_op_lists(struct ovsdb_idl_row *row)
    1911                 :            : {
    1912         [ +  + ]:     192996 :     if (row->set_op_written) {
    1913                 :            :         /* Clear Set Operation Lists */
    1914                 :            :         size_t idx, n_columns;
    1915                 :            :         const struct ovsdb_idl_column *columns;
    1916                 :            :         const struct ovsdb_type *type;
    1917                 :         54 :         n_columns = row->table->class->n_columns;
    1918                 :         54 :         columns = row->table->class->columns;
    1919         [ +  + ]:        108 :         BITMAP_FOR_EACH_1 (idx, n_columns, row->set_op_written) {
    1920                 :         54 :             type = &columns[idx].type;
    1921                 :         54 :             set_op_list_destroy(row->set_op_lists[idx], type);
    1922                 :            :         }
    1923                 :         54 :         free(row->set_op_lists);
    1924                 :         54 :         bitmap_free(row->set_op_written);
    1925                 :         54 :         row->set_op_lists = NULL;
    1926                 :         54 :         row->set_op_written = NULL;
    1927                 :            :     }
    1928                 :     192996 : }
    1929                 :            : 
    1930                 :            : static void
    1931                 :     147927 : ovsdb_idl_row_destroy_postprocess(struct ovsdb_idl *idl)
    1932                 :            : {
    1933                 :            :     size_t i;
    1934                 :            : 
    1935         [ +  + ]:    2444816 :     for (i = 0; i < idl->class->n_tables; i++) {
    1936                 :    2296889 :         struct ovsdb_idl_table *table = &idl->tables[i];
    1937                 :            : 
    1938         [ +  + ]:    2296889 :         if (!ovs_list_is_empty(&table->track_list)) {
    1939                 :            :             struct ovsdb_idl_row *row, *next;
    1940                 :            : 
    1941 [ +  + ][ +  + ]:      23886 :             LIST_FOR_EACH_SAFE(row, next, track_node, &table->track_list) {
    1942         [ +  + ]:      20361 :                 if (!ovsdb_idl_track_is_set(row->table)) {
    1943                 :       4192 :                     ovs_list_remove(&row->track_node);
    1944                 :       4192 :                     free(row);
    1945                 :            :                 }
    1946                 :            :             }
    1947                 :            :         }
    1948                 :            :     }
    1949                 :     147927 : }
    1950                 :            : 
    1951                 :            : static void
    1952                 :     114134 : ovsdb_idl_insert_row(struct ovsdb_idl_row *row, const struct json *row_json)
    1953                 :            : {
    1954                 :     114134 :     const struct ovsdb_idl_table_class *class = row->table->class;
    1955                 :            :     size_t i;
    1956                 :            : 
    1957 [ +  - ][ -  + ]:     114134 :     ovs_assert(!row->old && !row->new);
    1958                 :     114134 :     row->old = row->new = xmalloc(class->n_columns * sizeof *row->old);
    1959         [ +  + ]:    2448552 :     for (i = 0; i < class->n_columns; i++) {
    1960                 :    2334418 :         ovsdb_datum_init_default(&row->old[i], &class->columns[i].type);
    1961                 :            :     }
    1962                 :     114134 :     ovsdb_idl_row_update(row, row_json, OVSDB_IDL_CHANGE_INSERT);
    1963                 :     114134 :     ovsdb_idl_row_parse(row);
    1964                 :            : 
    1965                 :     114134 :     ovsdb_idl_row_reparse_backrefs(row);
    1966                 :     114134 : }
    1967                 :            : 
    1968                 :            : static void
    1969                 :       4782 : ovsdb_idl_delete_row(struct ovsdb_idl_row *row)
    1970                 :            : {
    1971                 :       4782 :     ovsdb_idl_row_unparse(row);
    1972                 :       4782 :     ovsdb_idl_row_clear_arcs(row, true);
    1973                 :       4782 :     ovsdb_idl_row_clear_old(row);
    1974         [ +  + ]:       4782 :     if (ovs_list_is_empty(&row->dst_arcs)) {
    1975                 :       1322 :         ovsdb_idl_row_destroy(row);
    1976                 :            :     } else {
    1977                 :       3460 :         ovsdb_idl_row_reparse_backrefs(row);
    1978                 :            :     }
    1979                 :       4782 : }
    1980                 :            : 
    1981                 :            : /* Returns true if a column with mode OVSDB_IDL_MODE_RW changed, false
    1982                 :            :  * otherwise. */
    1983                 :            : static bool
    1984                 :         14 : ovsdb_idl_modify_row(struct ovsdb_idl_row *row, const struct json *row_json)
    1985                 :            : {
    1986                 :            :     bool changed;
    1987                 :            : 
    1988                 :         14 :     ovsdb_idl_row_unparse(row);
    1989                 :         14 :     ovsdb_idl_row_clear_arcs(row, true);
    1990                 :         14 :     changed = ovsdb_idl_row_update(row, row_json, OVSDB_IDL_CHANGE_MODIFY);
    1991                 :         14 :     ovsdb_idl_row_parse(row);
    1992                 :            : 
    1993                 :         14 :     return changed;
    1994                 :            : }
    1995                 :            : 
    1996                 :            : static bool
    1997                 :      26376 : ovsdb_idl_modify_row_by_diff(struct ovsdb_idl_row *row,
    1998                 :            :                              const struct json *diff_json)
    1999                 :            : {
    2000                 :            :     bool changed;
    2001                 :            : 
    2002                 :      26376 :     ovsdb_idl_row_unparse(row);
    2003                 :      26376 :     ovsdb_idl_row_clear_arcs(row, true);
    2004                 :      26376 :     changed = ovsdb_idl_row_apply_diff(row, diff_json,
    2005                 :            :                                        OVSDB_IDL_CHANGE_MODIFY);
    2006                 :      26376 :     ovsdb_idl_row_parse(row);
    2007                 :            : 
    2008                 :      26376 :     return changed;
    2009                 :            : }
    2010                 :            : 
    2011                 :            : static bool
    2012                 :     365472 : may_add_arc(const struct ovsdb_idl_row *src, const struct ovsdb_idl_row *dst)
    2013                 :            : {
    2014                 :            :     const struct ovsdb_idl_arc *arc;
    2015                 :            : 
    2016                 :            :     /* No self-arcs. */
    2017         [ +  + ]:     365472 :     if (src == dst) {
    2018                 :         29 :         return false;
    2019                 :            :     }
    2020                 :            : 
    2021                 :            :     /* No duplicate arcs.
    2022                 :            :      *
    2023                 :            :      * We only need to test whether the first arc in dst->dst_arcs originates
    2024                 :            :      * at 'src', since we add all of the arcs from a given source in a clump
    2025                 :            :      * (in a single call to ovsdb_idl_row_parse()) and new arcs are always
    2026                 :            :      * added at the front of the dst_arcs list. */
    2027         [ +  + ]:     365443 :     if (ovs_list_is_empty(&dst->dst_arcs)) {
    2028                 :     339864 :         return true;
    2029                 :            :     }
    2030                 :      25579 :     arc = CONTAINER_OF(dst->dst_arcs.next, struct ovsdb_idl_arc, dst_node);
    2031                 :      25579 :     return arc->src != src;
    2032                 :            : }
    2033                 :            : 
    2034                 :            : static struct ovsdb_idl_table *
    2035                 :    1024783 : ovsdb_idl_table_from_class(const struct ovsdb_idl *idl,
    2036                 :            :                            const struct ovsdb_idl_table_class *table_class)
    2037                 :            : {
    2038                 :    1024783 :     return &idl->tables[table_class - idl->class->tables];
    2039                 :            : }
    2040                 :            : 
    2041                 :            : /* Called by ovsdb-idlc generated code. */
    2042                 :            : struct ovsdb_idl_row *
    2043                 :     538974 : ovsdb_idl_get_row_arc(struct ovsdb_idl_row *src,
    2044                 :            :                       struct ovsdb_idl_table_class *dst_table_class,
    2045                 :            :                       const struct uuid *dst_uuid)
    2046                 :            : {
    2047                 :     538974 :     struct ovsdb_idl *idl = src->table->idl;
    2048                 :            :     struct ovsdb_idl_table *dst_table;
    2049                 :            :     struct ovsdb_idl_arc *arc;
    2050                 :            :     struct ovsdb_idl_row *dst;
    2051                 :            : 
    2052                 :     538974 :     dst_table = ovsdb_idl_table_from_class(idl, dst_table_class);
    2053                 :     538974 :     dst = ovsdb_idl_get_row(dst_table, dst_uuid);
    2054         [ +  + ]:     538974 :     if (idl->txn) {
    2055                 :            :         /* We're being called from ovsdb_idl_txn_write().  We must not update
    2056                 :            :          * any arcs, because the transaction will be backed out at commit or
    2057                 :            :          * abort time and we don't want our graph screwed up.
    2058                 :            :          *
    2059                 :            :          * Just return the destination row, if there is one and it has not been
    2060                 :            :          * deleted. */
    2061 [ +  + ][ +  + ]:     173502 :         if (dst && (hmap_node_is_null(&dst->txn_node) || dst->new)) {
                 [ +  - ]
    2062                 :     173430 :             return dst;
    2063                 :            :         }
    2064                 :         72 :         return NULL;
    2065                 :            :     } else {
    2066                 :            :         /* We're being called from some other context.  Update the graph. */
    2067         [ +  + ]:     365472 :         if (!dst) {
    2068                 :       7620 :             dst = ovsdb_idl_row_create(dst_table, dst_uuid);
    2069                 :            :         }
    2070                 :            : 
    2071                 :            :         /* Add a new arc, if it wouldn't be a self-arc or a duplicate arc. */
    2072         [ +  + ]:     365472 :         if (may_add_arc(src, dst)) {
    2073                 :            :             /* The arc *must* be added at the front of the dst_arcs list.  See
    2074                 :            :              * ovsdb_idl_row_reparse_backrefs() for details. */
    2075                 :     365212 :             arc = xmalloc(sizeof *arc);
    2076                 :     365212 :             ovs_list_push_front(&src->src_arcs, &arc->src_node);
    2077                 :     365212 :             ovs_list_push_front(&dst->dst_arcs, &arc->dst_node);
    2078                 :     365212 :             arc->src = src;
    2079                 :     365212 :             arc->dst = dst;
    2080                 :            :         }
    2081                 :            : 
    2082         [ +  + ]:     365472 :         return !ovsdb_idl_row_is_orphan(dst) ? dst : NULL;
    2083                 :            :     }
    2084                 :            : }
    2085                 :            : 
    2086                 :            : /* Searches 'tc''s table in 'idl' for a row with UUID 'uuid'.  Returns a
    2087                 :            :  * pointer to the row if there is one, otherwise a null pointer.  */
    2088                 :            : const struct ovsdb_idl_row *
    2089                 :       2761 : ovsdb_idl_get_row_for_uuid(const struct ovsdb_idl *idl,
    2090                 :            :                            const struct ovsdb_idl_table_class *tc,
    2091                 :            :                            const struct uuid *uuid)
    2092                 :            : {
    2093                 :       2761 :     return ovsdb_idl_get_row(ovsdb_idl_table_from_class(idl, tc), uuid);
    2094                 :            : }
    2095                 :            : 
    2096                 :            : static struct ovsdb_idl_row *
    2097                 :    2271381 : next_real_row(struct ovsdb_idl_table *table, struct hmap_node *node)
    2098                 :            : {
    2099         [ +  + ]:    2271403 :     for (; node; node = hmap_next(&table->rows, node)) {
    2100                 :            :         struct ovsdb_idl_row *row;
    2101                 :            : 
    2102                 :    2167612 :         row = CONTAINER_OF(node, struct ovsdb_idl_row, hmap_node);
    2103         [ +  + ]:    2167612 :         if (ovsdb_idl_row_exists(row)) {
    2104                 :    2167590 :             return row;
    2105                 :            :         }
    2106                 :            :     }
    2107                 :     103791 :     return NULL;
    2108                 :            : }
    2109                 :            : 
    2110                 :            : /* Returns a row in 'table_class''s table in 'idl', or a null pointer if that
    2111                 :            :  * table is empty.
    2112                 :            :  *
    2113                 :            :  * Database tables are internally maintained as hash tables, so adding or
    2114                 :            :  * removing rows while traversing the same table can cause some rows to be
    2115                 :            :  * visited twice or not at apply. */
    2116                 :            : const struct ovsdb_idl_row *
    2117                 :     466056 : ovsdb_idl_first_row(const struct ovsdb_idl *idl,
    2118                 :            :                     const struct ovsdb_idl_table_class *table_class)
    2119                 :            : {
    2120                 :     466056 :     struct ovsdb_idl_table *table
    2121                 :            :         = ovsdb_idl_table_from_class(idl, table_class);
    2122                 :     466056 :     return next_real_row(table, hmap_first(&table->rows));
    2123                 :            : }
    2124                 :            : 
    2125                 :            : /* Returns a row following 'row' within its table, or a null pointer if 'row'
    2126                 :            :  * is the last row in its table. */
    2127                 :            : const struct ovsdb_idl_row *
    2128                 :    1805325 : ovsdb_idl_next_row(const struct ovsdb_idl_row *row)
    2129                 :            : {
    2130                 :    1805325 :     struct ovsdb_idl_table *table = row->table;
    2131                 :            : 
    2132                 :    1805325 :     return next_real_row(table, hmap_next(&table->rows, &row->hmap_node));
    2133                 :            : }
    2134                 :            : 
    2135                 :            : /* Reads and returns the value of 'column' within 'row'.  If an ongoing
    2136                 :            :  * transaction has changed 'column''s value, the modified value is returned.
    2137                 :            :  *
    2138                 :            :  * The caller must not modify or free the returned value.
    2139                 :            :  *
    2140                 :            :  * Various kinds of changes can invalidate the returned value: writing to the
    2141                 :            :  * same 'column' in 'row' (e.g. with ovsdb_idl_txn_write()), deleting 'row'
    2142                 :            :  * (e.g. with ovsdb_idl_txn_delete()), or completing an ongoing transaction
    2143                 :            :  * (e.g. with ovsdb_idl_txn_commit() or ovsdb_idl_txn_abort()).  If the
    2144                 :            :  * returned value is needed for a long time, it is best to make a copy of it
    2145                 :            :  * with ovsdb_datum_clone(). */
    2146                 :            : const struct ovsdb_datum *
    2147                 :    1077395 : ovsdb_idl_read(const struct ovsdb_idl_row *row,
    2148                 :            :                const struct ovsdb_idl_column *column)
    2149                 :            : {
    2150                 :            :     const struct ovsdb_idl_table_class *class;
    2151                 :            :     size_t column_idx;
    2152                 :            : 
    2153         [ -  + ]:    1077395 :     ovs_assert(!ovsdb_idl_row_is_synthetic(row));
    2154                 :            : 
    2155                 :    1077395 :     class = row->table->class;
    2156                 :    1077395 :     column_idx = column - class->columns;
    2157                 :            : 
    2158         [ -  + ]:    1077395 :     ovs_assert(row->new != NULL);
    2159         [ -  + ]:    1077395 :     ovs_assert(column_idx < class->n_columns);
    2160                 :            : 
    2161 [ +  + ][ +  + ]:    1077395 :     if (row->written && bitmap_is_set(row->written, column_idx)) {
    2162                 :       5453 :         return &row->new[column_idx];
    2163         [ +  + ]:    1071942 :     } else if (row->old) {
    2164                 :    1036048 :         return &row->old[column_idx];
    2165                 :            :     } else {
    2166                 :      35894 :         return ovsdb_datum_default(&column->type);
    2167                 :            :     }
    2168                 :            : }
    2169                 :            : 
    2170                 :            : /* Same as ovsdb_idl_read(), except that it also asserts that 'column' has key
    2171                 :            :  * type 'key_type' and value type 'value_type'.  (Scalar and set types will
    2172                 :            :  * have a value type of OVSDB_TYPE_VOID.)
    2173                 :            :  *
    2174                 :            :  * This is useful in code that "knows" that a particular column has a given
    2175                 :            :  * type, so that it will abort if someone changes the column's type without
    2176                 :            :  * updating the code that uses it. */
    2177                 :            : const struct ovsdb_datum *
    2178                 :      35022 : ovsdb_idl_get(const struct ovsdb_idl_row *row,
    2179                 :            :               const struct ovsdb_idl_column *column,
    2180                 :            :               enum ovsdb_atomic_type key_type OVS_UNUSED,
    2181                 :            :               enum ovsdb_atomic_type value_type OVS_UNUSED)
    2182                 :            : {
    2183         [ -  + ]:      35022 :     ovs_assert(column->type.key.type == key_type);
    2184         [ -  + ]:      35022 :     ovs_assert(column->type.value.type == value_type);
    2185                 :            : 
    2186                 :      35022 :     return ovsdb_idl_read(row, column);
    2187                 :            : }
    2188                 :            : 
    2189                 :            : /* Returns true if the field represented by 'column' in 'row' may be modified,
    2190                 :            :  * false if it is immutable.
    2191                 :            :  *
    2192                 :            :  * Normally, whether a field is mutable is controlled by its column's schema.
    2193                 :            :  * However, an immutable column can be set to any initial value at the time of
    2194                 :            :  * insertion, so if 'row' is a new row (one that is being added as part of the
    2195                 :            :  * current transaction, supposing that a transaction is in progress) then even
    2196                 :            :  * its "immutable" fields are actually mutable. */
    2197                 :            : bool
    2198                 :       8456 : ovsdb_idl_is_mutable(const struct ovsdb_idl_row *row,
    2199                 :            :                      const struct ovsdb_idl_column *column)
    2200                 :            : {
    2201 [ +  + ][ +  - ]:       8456 :     return column->mutable || (row->new && !row->old);
                 [ +  + ]
    2202                 :            : }
    2203                 :            : 
    2204                 :            : /* Returns false if 'row' was obtained from the IDL, true if it was initialized
    2205                 :            :  * to all-zero-bits by some other entity.  If 'row' was set up some other way
    2206                 :            :  * then the return value is indeterminate. */
    2207                 :            : bool
    2208                 :    2468273 : ovsdb_idl_row_is_synthetic(const struct ovsdb_idl_row *row)
    2209                 :            : {
    2210                 :    2468273 :     return row->table == NULL;
    2211                 :            : }
    2212                 :            : 
    2213                 :            : /* Transactions. */
    2214                 :            : 
    2215                 :            : static void ovsdb_idl_txn_complete(struct ovsdb_idl_txn *txn,
    2216                 :            :                                    enum ovsdb_idl_txn_status);
    2217                 :            : 
    2218                 :            : /* Returns a string representation of 'status'.  The caller must not modify or
    2219                 :            :  * free the returned string.
    2220                 :            :  *
    2221                 :            :  * The return value is probably useful only for debug log messages and unit
    2222                 :            :  * tests. */
    2223                 :            : const char *
    2224                 :       6141 : ovsdb_idl_txn_status_to_string(enum ovsdb_idl_txn_status status)
    2225                 :            : {
    2226   [ -  +  -  +  :       6141 :     switch (status) {
             +  +  -  -  
                      - ]
    2227                 :            :     case TXN_UNCOMMITTED:
    2228                 :          0 :         return "uncommitted";
    2229                 :            :     case TXN_UNCHANGED:
    2230                 :       2165 :         return "unchanged";
    2231                 :            :     case TXN_INCOMPLETE:
    2232                 :          0 :         return "incomplete";
    2233                 :            :     case TXN_ABORTED:
    2234                 :          1 :         return "aborted";
    2235                 :            :     case TXN_SUCCESS:
    2236                 :       3974 :         return "success";
    2237                 :            :     case TXN_TRY_AGAIN:
    2238                 :          1 :         return "try again";
    2239                 :            :     case TXN_NOT_LOCKED:
    2240                 :          0 :         return "not locked";
    2241                 :            :     case TXN_ERROR:
    2242                 :          0 :         return "error";
    2243                 :            :     }
    2244                 :          0 :     return "<unknown>";
    2245                 :            : }
    2246                 :            : 
    2247                 :            : /* Starts a new transaction on 'idl'.  A given ovsdb_idl may only have a single
    2248                 :            :  * active transaction at a time.  See the large comment in ovsdb-idl.h for
    2249                 :            :  * general information on transactions. */
    2250                 :            : struct ovsdb_idl_txn *
    2251                 :      29266 : ovsdb_idl_txn_create(struct ovsdb_idl *idl)
    2252                 :            : {
    2253                 :            :     struct ovsdb_idl_txn *txn;
    2254                 :            : 
    2255         [ -  + ]:      29266 :     ovs_assert(!idl->txn);
    2256                 :      29266 :     idl->txn = txn = xmalloc(sizeof *txn);
    2257                 :      29266 :     txn->request_id = NULL;
    2258                 :      29266 :     txn->idl = idl;
    2259                 :      29266 :     hmap_init(&txn->txn_rows);
    2260                 :      29266 :     txn->status = TXN_UNCOMMITTED;
    2261                 :      29266 :     txn->error = NULL;
    2262                 :      29266 :     txn->dry_run = false;
    2263                 :      29266 :     ds_init(&txn->comment);
    2264                 :            : 
    2265                 :      29266 :     txn->inc_table = NULL;
    2266                 :      29266 :     txn->inc_column = NULL;
    2267                 :            : 
    2268                 :      29266 :     hmap_init(&txn->inserted_rows);
    2269                 :            : 
    2270                 :      29266 :     return txn;
    2271                 :            : }
    2272                 :            : 
    2273                 :            : /* Appends 's', which is treated as a printf()-type format string, to the
    2274                 :            :  * comments that will be passed to the OVSDB server when 'txn' is committed.
    2275                 :            :  * (The comment will be committed to the OVSDB log, which "ovsdb-tool
    2276                 :            :  * show-log" can print in a relatively human-readable form.) */
    2277                 :            : void
    2278                 :      10636 : ovsdb_idl_txn_add_comment(struct ovsdb_idl_txn *txn, const char *s, ...)
    2279                 :            : {
    2280                 :            :     va_list args;
    2281                 :            : 
    2282         [ +  + ]:      10636 :     if (txn->comment.length) {
    2283                 :        733 :         ds_put_char(&txn->comment, '\n');
    2284                 :            :     }
    2285                 :            : 
    2286                 :      10636 :     va_start(args, s);
    2287                 :      10636 :     ds_put_format_valist(&txn->comment, s, args);
    2288                 :      10636 :     va_end(args);
    2289                 :      10636 : }
    2290                 :            : 
    2291                 :            : /* Marks 'txn' as a transaction that will not actually modify the database.  In
    2292                 :            :  * almost every way, the transaction is treated like other transactions.  It
    2293                 :            :  * must be committed or aborted like other transactions, it will be sent to the
    2294                 :            :  * database server like other transactions, and so on.  The only difference is
    2295                 :            :  * that the operations sent to the database server will include, as the last
    2296                 :            :  * step, an "abort" operation, so that any changes made by the transaction will
    2297                 :            :  * not actually take effect. */
    2298                 :            : void
    2299                 :          0 : ovsdb_idl_txn_set_dry_run(struct ovsdb_idl_txn *txn)
    2300                 :            : {
    2301                 :          0 :     txn->dry_run = true;
    2302                 :          0 : }
    2303                 :            : 
    2304                 :            : /* Causes 'txn', when committed, to increment the value of 'column' within
    2305                 :            :  * 'row' by 1.  'column' must have an integer type.  After 'txn' commits
    2306                 :            :  * successfully, the client may retrieve the final (incremented) value of
    2307                 :            :  * 'column' with ovsdb_idl_txn_get_increment_new_value().
    2308                 :            :  *
    2309                 :            :  * If at time of commit the transaction is otherwise empty, that is, it doesn't
    2310                 :            :  * change the database, then 'force' is important.  If 'force' is false in this
    2311                 :            :  * case, the IDL suppresses the increment and skips a round trip to the
    2312                 :            :  * database server.  If 'force' is true, the IDL will still increment the
    2313                 :            :  * column.
    2314                 :            :  *
    2315                 :            :  * The client could accomplish something similar with ovsdb_idl_read(),
    2316                 :            :  * ovsdb_idl_txn_verify() and ovsdb_idl_txn_write(), or with ovsdb-idlc
    2317                 :            :  * generated wrappers for these functions.  However, ovsdb_idl_txn_increment()
    2318                 :            :  * will never (by itself) fail because of a verify error.
    2319                 :            :  *
    2320                 :            :  * The intended use is for incrementing the "next_cfg" column in the
    2321                 :            :  * Open_vSwitch table. */
    2322                 :            : void
    2323                 :       3145 : ovsdb_idl_txn_increment(struct ovsdb_idl_txn *txn,
    2324                 :            :                         const struct ovsdb_idl_row *row,
    2325                 :            :                         const struct ovsdb_idl_column *column,
    2326                 :            :                         bool force)
    2327                 :            : {
    2328         [ -  + ]:       3145 :     ovs_assert(!txn->inc_table);
    2329         [ -  + ]:       3145 :     ovs_assert(column->type.key.type == OVSDB_TYPE_INTEGER);
    2330         [ -  + ]:       3145 :     ovs_assert(column->type.value.type == OVSDB_TYPE_VOID);
    2331                 :            : 
    2332                 :       3145 :     txn->inc_table = row->table->class->name;
    2333                 :       3145 :     txn->inc_column = column->name;
    2334                 :       3145 :     txn->inc_row = row->uuid;
    2335                 :       3145 :     txn->inc_force = force;
    2336                 :       3145 : }
    2337                 :            : 
    2338                 :            : /* Destroys 'txn' and frees all associated memory.  If ovsdb_idl_txn_commit()
    2339                 :            :  * has been called for 'txn' but the commit is still incomplete (that is, the
    2340                 :            :  * last call returned TXN_INCOMPLETE) then the transaction may or may not still
    2341                 :            :  * end up committing at the database server, but the client will not be able to
    2342                 :            :  * get any further status information back. */
    2343                 :            : void
    2344                 :      29266 : ovsdb_idl_txn_destroy(struct ovsdb_idl_txn *txn)
    2345                 :            : {
    2346                 :            :     struct ovsdb_idl_txn_insert *insert, *next;
    2347                 :            : 
    2348                 :      29266 :     json_destroy(txn->request_id);
    2349         [ +  + ]:      29266 :     if (txn->status == TXN_INCOMPLETE) {
    2350                 :       2335 :         hmap_remove(&txn->idl->outstanding_txns, &txn->hmap_node);
    2351                 :            :     }
    2352                 :      29266 :     ovsdb_idl_txn_abort(txn);
    2353                 :      29266 :     ds_destroy(&txn->comment);
    2354                 :      29266 :     free(txn->error);
    2355 [ +  + ][ -  + ]:      46192 :     HMAP_FOR_EACH_SAFE (insert, next, hmap_node, &txn->inserted_rows) {
                 [ +  + ]
    2356                 :      16926 :         free(insert);
    2357                 :            :     }
    2358                 :      29266 :     hmap_destroy(&txn->inserted_rows);
    2359                 :      29266 :     free(txn);
    2360                 :      29266 : }
    2361                 :            : 
    2362                 :            : /* Causes poll_block() to wake up if 'txn' has completed committing. */
    2363                 :            : void
    2364                 :       9211 : ovsdb_idl_txn_wait(const struct ovsdb_idl_txn *txn)
    2365                 :            : {
    2366 [ +  - ][ +  + ]:       9211 :     if (txn->status != TXN_UNCOMMITTED && txn->status != TXN_INCOMPLETE) {
    2367                 :       3981 :         poll_immediate_wake();
    2368                 :            :     }
    2369                 :       9211 : }
    2370                 :            : 
    2371                 :            : static struct json *
    2372                 :      65755 : where_uuid_equals(const struct uuid *uuid)
    2373                 :            : {
    2374                 :            :     return
    2375                 :      65755 :         json_array_create_1(
    2376                 :            :             json_array_create_3(
    2377                 :            :                 json_string_create("_uuid"),
    2378                 :            :                 json_string_create("=="),
    2379                 :            :                 json_array_create_2(
    2380                 :            :                     json_string_create("uuid"),
    2381                 :            :                     json_string_create_nocopy(
    2382                 :     197265 :                         xasprintf(UUID_FMT, UUID_ARGS(uuid))))));
    2383                 :            : }
    2384                 :            : 
    2385                 :            : static char *
    2386                 :      29131 : uuid_name_from_uuid(const struct uuid *uuid)
    2387                 :            : {
    2388                 :            :     char *name;
    2389                 :            :     char *p;
    2390                 :            : 
    2391                 :      29131 :     name = xasprintf("row"UUID_FMT, UUID_ARGS(uuid));
    2392         [ +  + ]:    1165240 :     for (p = name; *p != '\0'; p++) {
    2393         [ +  + ]:    1136109 :         if (*p == '-') {
    2394                 :     116524 :             *p = '_';
    2395                 :            :         }
    2396                 :            :     }
    2397                 :            : 
    2398                 :      29131 :     return name;
    2399                 :            : }
    2400                 :            : 
    2401                 :            : static const struct ovsdb_idl_row *
    2402                 :      43890 : ovsdb_idl_txn_get_row(const struct ovsdb_idl_txn *txn, const struct uuid *uuid)
    2403                 :            : {
    2404                 :            :     const struct ovsdb_idl_row *row;
    2405                 :            : 
    2406 [ +  + ][ -  + ]:      43890 :     HMAP_FOR_EACH_WITH_HASH (row, txn_node, uuid_hash(uuid), &txn->txn_rows) {
    2407         [ +  - ]:      38010 :         if (uuid_equals(&row->uuid, uuid)) {
    2408                 :      38010 :             return row;
    2409                 :            :         }
    2410                 :            :     }
    2411                 :       5880 :     return NULL;
    2412                 :            : }
    2413                 :            : 
    2414                 :            : /* XXX there must be a cleaner way to do this */
    2415                 :            : static struct json *
    2416                 :     424809 : substitute_uuids(struct json *json, const struct ovsdb_idl_txn *txn)
    2417                 :            : {
    2418         [ +  + ]:     424809 :     if (json->type == JSON_ARRAY) {
    2419                 :            :         struct uuid uuid;
    2420                 :            :         size_t i;
    2421                 :            : 
    2422         [ +  + ]:     133187 :         if (json->u.array.n == 2
    2423         [ +  + ]:     108004 :             && json->u.array.elems[0]->type == JSON_STRING
    2424         [ +  + ]:     105386 :             && json->u.array.elems[1]->type == JSON_STRING
    2425         [ +  + ]:      59422 :             && !strcmp(json->u.array.elems[0]->u.string, "uuid")
    2426         [ +  - ]:      43782 :             && uuid_from_string(&uuid, json->u.array.elems[1]->u.string)) {
    2427                 :            :             const struct ovsdb_idl_row *row;
    2428                 :            : 
    2429                 :      43782 :             row = ovsdb_idl_txn_get_row(txn, &uuid);
    2430 [ +  + ][ +  + ]:      43782 :             if (row && !row->old && row->new) {
                 [ +  - ]
    2431                 :      12205 :                 json_destroy(json);
    2432                 :            : 
    2433                 :      12205 :                 return json_array_create_2(
    2434                 :            :                     json_string_create("named-uuid"),
    2435                 :            :                     json_string_create_nocopy(uuid_name_from_uuid(&uuid)));
    2436                 :            :             }
    2437                 :            :         }
    2438                 :            : 
    2439         [ +  + ]:     406842 :         for (i = 0; i < json->u.array.n; i++) {
    2440                 :     285860 :             json->u.array.elems[i] = substitute_uuids(json->u.array.elems[i],
    2441                 :            :                                                       txn);
    2442                 :            :         }
    2443         [ +  + ]:     291622 :     } else if (json->type == JSON_OBJECT) {
    2444                 :            :         struct shash_node *node;
    2445                 :            : 
    2446 [ +  + ][ -  + ]:        275 :         SHASH_FOR_EACH (node, json_object(json)) {
    2447                 :        220 :             node->data = substitute_uuids(node->data, txn);
    2448                 :            :         }
    2449                 :            :     }
    2450                 :     412604 :     return json;
    2451                 :            : }
    2452                 :            : 
    2453                 :            : static void
    2454                 :      58531 : ovsdb_idl_txn_disassemble(struct ovsdb_idl_txn *txn)
    2455                 :            : {
    2456                 :            :     struct ovsdb_idl_row *row, *next;
    2457                 :            : 
    2458                 :            :     /* This must happen early.  Otherwise, ovsdb_idl_row_parse() will call an
    2459                 :            :      * ovsdb_idl_column's 'parse' function, which will call
    2460                 :            :      * ovsdb_idl_get_row_arc(), which will seen that the IDL is in a
    2461                 :            :      * transaction and fail to update the graph.  */
    2462                 :      58531 :     txn->idl->txn = NULL;
    2463                 :            : 
    2464 [ +  + ][ -  + ]:     137083 :     HMAP_FOR_EACH_SAFE (row, next, txn_node, &txn->txn_rows) {
                 [ +  + ]
    2465                 :      78552 :         ovsdb_idl_destroy_all_map_op_lists(row);
    2466                 :      78552 :         ovsdb_idl_destroy_all_set_op_lists(row);
    2467         [ +  + ]:      78552 :         if (row->old) {
    2468         [ +  + ]:      61626 :             if (row->written) {
    2469                 :      31220 :                 ovsdb_idl_row_unparse(row);
    2470                 :      31220 :                 ovsdb_idl_row_clear_arcs(row, false);
    2471                 :      61626 :                 ovsdb_idl_row_parse(row);
    2472                 :            :             }
    2473                 :            :         } else {
    2474                 :      16926 :             ovsdb_idl_row_unparse(row);
    2475                 :            :         }
    2476                 :      78552 :         ovsdb_idl_row_clear_new(row);
    2477                 :            : 
    2478                 :      78552 :         free(row->prereqs);
    2479                 :      78552 :         row->prereqs = NULL;
    2480                 :            : 
    2481                 :      78552 :         free(row->written);
    2482                 :      78552 :         row->written = NULL;
    2483                 :            : 
    2484                 :      78552 :         hmap_remove(&txn->txn_rows, &row->txn_node);
    2485                 :      78552 :         hmap_node_nullify(&row->txn_node);
    2486         [ +  + ]:      78552 :         if (!row->old) {
    2487                 :      16926 :             hmap_remove(&row->table->rows, &row->hmap_node);
    2488                 :      16926 :             free(row);
    2489                 :            :         }
    2490                 :            :     }
    2491                 :      58531 :     hmap_destroy(&txn->txn_rows);
    2492                 :      58531 :     hmap_init(&txn->txn_rows);
    2493                 :      58531 : }
    2494                 :            : 
    2495                 :            : static bool
    2496                 :         58 : ovsdb_idl_txn_extract_mutations(struct ovsdb_idl_row *row,
    2497                 :            :                                 struct json *mutations)
    2498                 :            : {
    2499                 :         58 :     const struct ovsdb_idl_table_class *class = row->table->class;
    2500                 :            :     size_t idx;
    2501                 :         58 :     bool any_mutations = false;
    2502                 :            : 
    2503         [ +  + ]:         58 :     if (row->map_op_written) {
    2504         [ +  + ]:          9 :         BITMAP_FOR_EACH_1(idx, class->n_columns, row->map_op_written) {
    2505                 :            :             struct map_op_list *map_op_list;
    2506                 :            :             const struct ovsdb_idl_column *column;
    2507                 :            :             const struct ovsdb_datum *old_datum;
    2508                 :            :             enum ovsdb_atomic_type key_type, value_type;
    2509                 :            :             struct json *mutation, *map, *col_name, *mutator;
    2510                 :            :             struct json *del_set, *ins_map;
    2511                 :            :             bool any_del, any_ins;
    2512                 :            : 
    2513                 :          5 :             map_op_list = row->map_op_lists[idx];
    2514                 :          5 :             column = &class->columns[idx];
    2515                 :          5 :             key_type = column->type.key.type;
    2516                 :          5 :             value_type = column->type.value.type;
    2517                 :            : 
    2518                 :            :             /* Get the value to be changed */
    2519 [ +  - ][ +  + ]:          5 :             if (row->new && row->written && bitmap_is_set(row->written,idx)) {
                 [ -  + ]
    2520                 :          0 :                 old_datum = &row->new[idx];
    2521         [ +  - ]:          5 :             } else if (row->old != NULL) {
    2522                 :          5 :                 old_datum = &row->old[idx];
    2523                 :            :             } else {
    2524                 :          0 :                 old_datum = ovsdb_datum_default(&column->type);
    2525                 :            :             }
    2526                 :            : 
    2527                 :          5 :             del_set = json_array_create_empty();
    2528                 :          5 :             ins_map = json_array_create_empty();
    2529                 :          5 :             any_del = false;
    2530                 :          5 :             any_ins = false;
    2531                 :            : 
    2532         [ +  + ]:         10 :             for (struct map_op *map_op = map_op_list_first(map_op_list); map_op;
    2533                 :          5 :                  map_op = map_op_list_next(map_op_list, map_op)) {
    2534                 :            : 
    2535         [ +  + ]:          5 :                 if (map_op_type(map_op) == MAP_OP_UPDATE) {
    2536                 :            :                     /* Find out if value really changed. */
    2537                 :            :                     struct ovsdb_datum *new_datum;
    2538                 :            :                     unsigned int pos;
    2539                 :          2 :                     new_datum = map_op_datum(map_op);
    2540                 :          2 :                     pos = ovsdb_datum_find_key(old_datum,
    2541                 :          2 :                                                &new_datum->keys[0],
    2542                 :            :                                                key_type);
    2543         [ +  + ]:          2 :                     if (ovsdb_atom_equals(&new_datum->values[0],
    2544                 :          4 :                                           &old_datum->values[pos],
    2545                 :            :                                           value_type)) {
    2546                 :            :                         /* No change in value. Move on to next update. */
    2547                 :          2 :                         continue;
    2548                 :            :                     }
    2549         [ +  + ]:          3 :                 } else if (map_op_type(map_op) == MAP_OP_DELETE){
    2550                 :            :                     /* Verify that there is a key to delete. */
    2551                 :            :                     unsigned int pos;
    2552                 :          2 :                     pos = ovsdb_datum_find_key(old_datum,
    2553                 :          2 :                                                &map_op_datum(map_op)->keys[0],
    2554                 :            :                                                key_type);
    2555         [ +  + ]:          2 :                     if (pos == UINT_MAX) {
    2556                 :            :                         /* No key to delete.  Move on to next update. */
    2557         [ +  - ]:          1 :                         VLOG_WARN("Trying to delete a key that doesn't "
    2558                 :            :                                   "exist in the map.");
    2559                 :          1 :                         continue;
    2560                 :            :                     }
    2561                 :            :                 }
    2562                 :            : 
    2563         [ +  + ]:          3 :                 if (map_op_type(map_op) == MAP_OP_INSERT) {
    2564                 :          2 :                     map = json_array_create_2(
    2565                 :          1 :                         ovsdb_atom_to_json(&map_op_datum(map_op)->keys[0],
    2566                 :            :                                            key_type),
    2567                 :          1 :                         ovsdb_atom_to_json(&map_op_datum(map_op)->values[0],
    2568                 :            :                                            value_type));
    2569                 :          1 :                     json_array_add(ins_map, map);
    2570                 :          1 :                     any_ins = true;
    2571                 :            :                 } else { /* MAP_OP_UPDATE or MAP_OP_DELETE */
    2572                 :          2 :                     map = ovsdb_atom_to_json(&map_op_datum(map_op)->keys[0],
    2573                 :            :                                              key_type);
    2574                 :          2 :                     json_array_add(del_set, map);
    2575                 :          2 :                     any_del = true;
    2576                 :            :                 }
    2577                 :            : 
    2578                 :            :                 /* Generate an additional insert mutate for updates. */
    2579         [ +  + ]:          3 :                 if (map_op_type(map_op) == MAP_OP_UPDATE) {
    2580                 :          2 :                     map = json_array_create_2(
    2581                 :          1 :                         ovsdb_atom_to_json(&map_op_datum(map_op)->keys[0],
    2582                 :            :                                            key_type),
    2583                 :          1 :                         ovsdb_atom_to_json(&map_op_datum(map_op)->values[0],
    2584                 :            :                                            value_type));
    2585                 :          1 :                     json_array_add(ins_map, map);
    2586                 :          1 :                     any_ins = true;
    2587                 :            :                 }
    2588                 :            :             }
    2589                 :            : 
    2590         [ +  + ]:          5 :             if (any_del) {
    2591                 :          2 :                 col_name = json_string_create(column->name);
    2592                 :          2 :                 mutator = json_string_create("delete");
    2593                 :          2 :                 map = json_array_create_2(json_string_create("set"), del_set);
    2594                 :          2 :                 mutation = json_array_create_3(col_name, mutator, map);
    2595                 :          2 :                 json_array_add(mutations, mutation);
    2596                 :          2 :                 any_mutations = true;
    2597                 :            :             } else {
    2598                 :          3 :                 json_destroy(del_set);
    2599                 :            :             }
    2600         [ +  + ]:          5 :             if (any_ins) {
    2601                 :          2 :                 col_name = json_string_create(column->name);
    2602                 :          2 :                 mutator = json_string_create("insert");
    2603                 :          2 :                 map = json_array_create_2(json_string_create("map"), ins_map);
    2604                 :          2 :                 mutation = json_array_create_3(col_name, mutator, map);
    2605                 :          2 :                 json_array_add(mutations, mutation);
    2606                 :          2 :                 any_mutations = true;
    2607                 :            :             } else {
    2608                 :          3 :                 json_destroy(ins_map);
    2609                 :            :             }
    2610                 :            :         }
    2611                 :            :     }
    2612         [ +  + ]:         58 :     if (row->set_op_written) {
    2613         [ +  + ]:        108 :         BITMAP_FOR_EACH_1(idx, class->n_columns, row->set_op_written) {
    2614                 :            :             struct set_op_list *set_op_list;
    2615                 :            :             const struct ovsdb_idl_column *column;
    2616                 :            :             const struct ovsdb_datum *old_datum;
    2617                 :            :             enum ovsdb_atomic_type key_type;
    2618                 :            :             struct json *mutation, *set, *col_name, *mutator;
    2619                 :            :             struct json *del_set, *ins_set;
    2620                 :            :             bool any_del, any_ins;
    2621                 :            : 
    2622                 :         54 :             set_op_list = row->set_op_lists[idx];
    2623                 :         54 :             column = &class->columns[idx];
    2624                 :         54 :             key_type = column->type.key.type;
    2625                 :            : 
    2626                 :            :             /* Get the value to be changed */
    2627 [ +  - ][ +  + ]:         54 :             if (row->new && row->written && bitmap_is_set(row->written,idx)) {
                 [ +  + ]
    2628                 :          5 :                 old_datum = &row->new[idx];
    2629         [ +  - ]:         49 :             } else if (row->old != NULL) {
    2630                 :         49 :                 old_datum = &row->old[idx];
    2631                 :            :             } else {
    2632                 :          0 :                 old_datum = ovsdb_datum_default(&column->type);
    2633                 :            :             }
    2634                 :            : 
    2635                 :         54 :             del_set = json_array_create_empty();
    2636                 :         54 :             ins_set = json_array_create_empty();
    2637                 :         54 :             any_del = false;
    2638                 :         54 :             any_ins = false;
    2639                 :            : 
    2640         [ +  + ]:        114 :             for (struct set_op *set_op = set_op_list_first(set_op_list); set_op;
    2641                 :         60 :                  set_op = set_op_list_next(set_op_list, set_op)) {
    2642         [ +  + ]:         60 :                 if (set_op_type(set_op) == SET_OP_INSERT) {
    2643                 :         40 :                     set = ovsdb_atom_to_json(&set_op_datum(set_op)->keys[0],
    2644                 :            :                                              key_type);
    2645                 :         40 :                     json_array_add(ins_set, set);
    2646                 :         40 :                     any_ins = true;
    2647                 :            :                 } else { /* SETP_OP_DELETE */
    2648                 :            :                     /* Verify that there is a key to delete. */
    2649                 :            :                     unsigned int pos;
    2650                 :         20 :                     pos = ovsdb_datum_find_key(old_datum,
    2651                 :         20 :                                                &set_op_datum(set_op)->keys[0],
    2652                 :            :                                                key_type);
    2653         [ +  + ]:         20 :                     if (pos == UINT_MAX) {
    2654                 :            :                         /* No key to delete.  Move on to next update. */
    2655         [ +  - ]:          1 :                         VLOG_WARN("Trying to delete a key that doesn't "
    2656                 :            :                                   "exist in the set.");
    2657                 :          1 :                         continue;
    2658                 :            :                     }
    2659                 :         19 :                     set = ovsdb_atom_to_json(&set_op_datum(set_op)->keys[0],
    2660                 :            :                                              key_type);
    2661                 :         19 :                     json_array_add(del_set, set);
    2662                 :         19 :                     any_del = true;
    2663                 :            :                 }
    2664                 :            :             }
    2665         [ +  + ]:         54 :             if (any_del) {
    2666                 :         19 :                 col_name = json_string_create(column->name);
    2667                 :         19 :                 mutator = json_string_create("delete");
    2668                 :         19 :                 set = json_array_create_2(json_string_create("set"), del_set);
    2669                 :         19 :                 mutation = json_array_create_3(col_name, mutator, set);
    2670                 :         19 :                 json_array_add(mutations, mutation);
    2671                 :         19 :                 any_mutations = true;
    2672                 :            :             } else {
    2673                 :         35 :                 json_destroy(del_set);
    2674                 :            :             }
    2675         [ +  + ]:         54 :             if (any_ins) {
    2676                 :         37 :                 col_name = json_string_create(column->name);
    2677                 :         37 :                 mutator = json_string_create("insert");
    2678                 :         37 :                 set = json_array_create_2(json_string_create("set"), ins_set);
    2679                 :         37 :                 mutation = json_array_create_3(col_name, mutator, set);
    2680                 :         37 :                 json_array_add(mutations, mutation);
    2681                 :         37 :                 any_mutations = true;
    2682                 :            :             } else {
    2683                 :         17 :                 json_destroy(ins_set);
    2684                 :            :             }
    2685                 :            :         }
    2686                 :            :     }
    2687                 :         58 :     return any_mutations;
    2688                 :            : }
    2689                 :            : 
    2690                 :            : /* Attempts to commit 'txn'.  Returns the status of the commit operation, one
    2691                 :            :  * of the following TXN_* constants:
    2692                 :            :  *
    2693                 :            :  *   TXN_INCOMPLETE:
    2694                 :            :  *
    2695                 :            :  *       The transaction is in progress, but not yet complete.  The caller
    2696                 :            :  *       should call again later, after calling ovsdb_idl_run() to let the IDL
    2697                 :            :  *       do OVSDB protocol processing.
    2698                 :            :  *
    2699                 :            :  *   TXN_UNCHANGED:
    2700                 :            :  *
    2701                 :            :  *       The transaction is complete.  (It didn't actually change the database,
    2702                 :            :  *       so the IDL didn't send any request to the database server.)
    2703                 :            :  *
    2704                 :            :  *   TXN_ABORTED:
    2705                 :            :  *
    2706                 :            :  *       The caller previously called ovsdb_idl_txn_abort().
    2707                 :            :  *
    2708                 :            :  *   TXN_SUCCESS:
    2709                 :            :  *
    2710                 :            :  *       The transaction was successful.  The update made by the transaction
    2711                 :            :  *       (and possibly other changes made by other database clients) should
    2712                 :            :  *       already be visible in the IDL.
    2713                 :            :  *
    2714                 :            :  *   TXN_TRY_AGAIN:
    2715                 :            :  *
    2716                 :            :  *       The transaction failed for some transient reason, e.g. because a
    2717                 :            :  *       "verify" operation reported an inconsistency or due to a network
    2718                 :            :  *       problem.  The caller should wait for a change to the database, then
    2719                 :            :  *       compose a new transaction, and commit the new transaction.
    2720                 :            :  *
    2721                 :            :  *       Use the return value of ovsdb_idl_get_seqno() to wait for a change in
    2722                 :            :  *       the database.  It is important to use its return value *before* the
    2723                 :            :  *       initial call to ovsdb_idl_txn_commit() as the baseline for this
    2724                 :            :  *       purpose, because the change that one should wait for can happen after
    2725                 :            :  *       the initial call but before the call that returns TXN_TRY_AGAIN, and
    2726                 :            :  *       using some other baseline value in that situation could cause an
    2727                 :            :  *       indefinite wait if the database rarely changes.
    2728                 :            :  *
    2729                 :            :  *   TXN_NOT_LOCKED:
    2730                 :            :  *
    2731                 :            :  *       The transaction failed because the IDL has been configured to require
    2732                 :            :  *       a database lock (with ovsdb_idl_set_lock()) but didn't get it yet or
    2733                 :            :  *       has already lost it.
    2734                 :            :  *
    2735                 :            :  * Committing a transaction rolls back all of the changes that it made to the
    2736                 :            :  * IDL's copy of the database.  If the transaction commits successfully, then
    2737                 :            :  * the database server will send an update and, thus, the IDL will be updated
    2738                 :            :  * with the committed changes. */
    2739                 :            : enum ovsdb_idl_txn_status
    2740                 :      40574 : ovsdb_idl_txn_commit(struct ovsdb_idl_txn *txn)
    2741                 :            : {
    2742                 :            :     struct ovsdb_idl_row *row;
    2743                 :            :     struct json *operations;
    2744                 :            :     bool any_updates;
    2745                 :            : 
    2746         [ +  + ]:      40574 :     if (txn != txn->idl->txn) {
    2747                 :      11512 :         goto coverage_out;
    2748                 :            :     }
    2749                 :            : 
    2750                 :            :     /* If we need a lock but don't have it, give up quickly. */
    2751 [ +  + ][ -  + ]:      29062 :     if (txn->idl->lock_name && !ovsdb_idl_has_lock(txn->idl)) {
    2752                 :          0 :         txn->status = TXN_NOT_LOCKED;
    2753                 :          0 :         goto disassemble_out;
    2754                 :            :     }
    2755                 :            : 
    2756                 :      29062 :     operations = json_array_create_1(
    2757                 :      29062 :         json_string_create(txn->idl->class->database));
    2758                 :            : 
    2759                 :            :     /* Assert that we have the required lock (avoiding a race). */
    2760         [ +  + ]:      29062 :     if (txn->idl->lock_name) {
    2761                 :      11109 :         struct json *op = json_object_create();
    2762                 :      11109 :         json_array_add(operations, op);
    2763                 :      11109 :         json_object_put_string(op, "op", "assert");
    2764                 :      11109 :         json_object_put_string(op, "lock", txn->idl->lock_name);
    2765                 :            :     }
    2766                 :            : 
    2767                 :            :     /* Add prerequisites and declarations of new rows. */
    2768 [ +  + ][ -  + ]:     107532 :     HMAP_FOR_EACH (row, txn_node, &txn->txn_rows) {
    2769                 :            :         /* XXX check that deleted rows exist even if no prereqs? */
    2770         [ +  + ]:      78470 :         if (row->prereqs) {
    2771                 :      29526 :             const struct ovsdb_idl_table_class *class = row->table->class;
    2772                 :      29526 :             size_t n_columns = class->n_columns;
    2773                 :            :             struct json *op, *columns, *row_json;
    2774                 :            :             size_t idx;
    2775                 :            : 
    2776                 :      29526 :             op = json_object_create();
    2777                 :      29526 :             json_array_add(operations, op);
    2778                 :      29526 :             json_object_put_string(op, "op", "wait");
    2779                 :      29526 :             json_object_put_string(op, "table", class->name);
    2780                 :      29526 :             json_object_put(op, "timeout", json_integer_create(0));
    2781                 :      29526 :             json_object_put(op, "where", where_uuid_equals(&row->uuid));
    2782                 :      29526 :             json_object_put_string(op, "until", "==");
    2783                 :      29526 :             columns = json_array_create_empty();
    2784                 :      29526 :             json_object_put(op, "columns", columns);
    2785                 :      29526 :             row_json = json_object_create();
    2786                 :      29526 :             json_object_put(op, "rows", json_array_create_1(row_json));
    2787                 :            : 
    2788         [ +  + ]:      59122 :             BITMAP_FOR_EACH_1 (idx, n_columns, row->prereqs) {
    2789                 :      29596 :                 const struct ovsdb_idl_column *column = &class->columns[idx];
    2790                 :      29596 :                 json_array_add(columns, json_string_create(column->name));
    2791                 :      29596 :                 json_object_put(row_json, column->name,
    2792                 :      29596 :                                 ovsdb_datum_to_json(&row->old[idx],
    2793                 :            :                                                     &column->type));
    2794                 :            :             }
    2795                 :            :         }
    2796                 :            :     }
    2797                 :            : 
    2798                 :            :     /* Add updates. */
    2799                 :      29062 :     any_updates = false;
    2800 [ +  + ][ -  + ]:     107532 :     HMAP_FOR_EACH (row, txn_node, &txn->txn_rows) {
    2801                 :      78470 :         const struct ovsdb_idl_table_class *class = row->table->class;
    2802                 :            : 
    2803         [ +  + ]:      78470 :         if (!row->new) {
    2804         [ +  + ]:       3542 :             if (class->is_root) {
    2805                 :        623 :                 struct json *op = json_object_create();
    2806                 :        623 :                 json_object_put_string(op, "op", "delete");
    2807                 :        623 :                 json_object_put_string(op, "table", class->name);
    2808                 :        623 :                 json_object_put(op, "where", where_uuid_equals(&row->uuid));
    2809                 :        623 :                 json_array_add(operations, op);
    2810                 :        623 :                 any_updates = true;
    2811                 :            :             } else {
    2812                 :            :                 /* Let ovsdb-server decide whether to really delete it. */
    2813                 :            :             }
    2814         [ +  + ]:      74928 :         } else if (row->old != row->new) {
    2815                 :            :             struct json *row_json;
    2816                 :            :             struct json *op;
    2817                 :            :             size_t idx;
    2818                 :            : 
    2819                 :      48144 :             op = json_object_create();
    2820         [ +  + ]:      48144 :             json_object_put_string(op, "op", row->old ? "update" : "insert");
    2821                 :      48144 :             json_object_put_string(op, "table", class->name);
    2822         [ +  + ]:      48144 :             if (row->old) {
    2823                 :      31218 :                 json_object_put(op, "where", where_uuid_equals(&row->uuid));
    2824                 :            :             } else {
    2825                 :            :                 struct ovsdb_idl_txn_insert *insert;
    2826                 :            : 
    2827                 :      16926 :                 any_updates = true;
    2828                 :            : 
    2829                 :      16926 :                 json_object_put(op, "uuid-name",
    2830                 :            :                                 json_string_create_nocopy(
    2831                 :      16926 :                                     uuid_name_from_uuid(&row->uuid)));
    2832                 :            : 
    2833                 :      16926 :                 insert = xmalloc(sizeof *insert);
    2834                 :      16926 :                 insert->dummy = row->uuid;
    2835                 :      16926 :                 insert->op_index = operations->u.array.n - 1;
    2836                 :      16926 :                 uuid_zero(&insert->real);
    2837                 :      16926 :                 hmap_insert(&txn->inserted_rows, &insert->hmap_node,
    2838                 :            :                             uuid_hash(&insert->dummy));
    2839                 :            :             }
    2840                 :      48144 :             row_json = json_object_create();
    2841                 :      48144 :             json_object_put(op, "row", row_json);
    2842                 :            : 
    2843         [ +  + ]:      48144 :             if (row->written) {
    2844         [ +  + ]:     184599 :                 BITMAP_FOR_EACH_1 (idx, class->n_columns, row->written) {
    2845                 :     137179 :                     const struct ovsdb_idl_column *column =
    2846                 :     137179 :                                                         &class->columns[idx];
    2847                 :            : 
    2848         [ +  + ]:     137179 :                     if (row->old
    2849         [ +  + ]:      62047 :                         || !ovsdb_datum_is_default(&row->new[idx],
    2850                 :            :                                                   &column->type)) {
    2851                 :     134344 :                         json_object_put(row_json, column->name,
    2852                 :            :                                         substitute_uuids(
    2853                 :     134344 :                                             ovsdb_datum_to_json(&row->new[idx],
    2854                 :            :                                                                 &column->type),
    2855                 :            :                                             txn));
    2856                 :            : 
    2857                 :            :                         /* If anything really changed, consider it an update.
    2858                 :            :                          * We can't suppress not-really-changed values earlier
    2859                 :            :                          * or transactions would become nonatomic (see the big
    2860                 :            :                          * comment inside ovsdb_idl_txn_write()). */
    2861         [ +  + ]:     167098 :                         if (!any_updates && row->old &&
           [ +  -  +  + ]
    2862                 :      32754 :                             !ovsdb_datum_equals(&row->old[idx], &row->new[idx],
    2863                 :            :                                                 &column->type)) {
    2864                 :       7568 :                             any_updates = true;
    2865                 :            :                         }
    2866                 :            :                     }
    2867                 :            :                 }
    2868                 :            :             }
    2869                 :            : 
    2870 [ +  + ][ +  - ]:      48144 :             if (!row->old || !shash_is_empty(json_object(row_json))) {
    2871                 :      48144 :                 json_array_add(operations, op);
    2872                 :            :             } else {
    2873                 :          0 :                 json_destroy(op);
    2874                 :            :             }
    2875                 :            :         }
    2876                 :            : 
    2877                 :            :         /* Add mutate operation, for partial map or partial set updates. */
    2878 [ +  + ][ +  + ]:      78470 :         if (row->map_op_written || row->set_op_written) {
    2879                 :            :             struct json *op, *mutations;
    2880                 :            :             bool any_mutations;
    2881                 :            : 
    2882                 :         58 :             op = json_object_create();
    2883                 :         58 :             json_object_put_string(op, "op", "mutate");
    2884                 :         58 :             json_object_put_string(op, "table", class->name);
    2885                 :         58 :             json_object_put(op, "where", where_uuid_equals(&row->uuid));
    2886                 :         58 :             mutations = json_array_create_empty();
    2887                 :         58 :             any_mutations = ovsdb_idl_txn_extract_mutations(row, mutations);
    2888                 :         58 :             json_object_put(op, "mutations", mutations);
    2889                 :            : 
    2890         [ +  + ]:         58 :             if (any_mutations) {
    2891                 :         55 :                 op = substitute_uuids(op, txn);
    2892                 :         55 :                 json_array_add(operations, op);
    2893                 :         55 :                 any_updates = true;
    2894                 :            :             } else {
    2895                 :          3 :                 json_destroy(op);
    2896                 :            :             }
    2897                 :            :         }
    2898                 :            :     }
    2899                 :            : 
    2900                 :            :     /* Add increment. */
    2901 [ +  + ][ +  + ]:      29062 :     if (txn->inc_table && (any_updates || txn->inc_force)) {
                 [ +  + ]
    2902                 :       2165 :         any_updates = true;
    2903                 :       2165 :         txn->inc_index = operations->u.array.n - 1;
    2904                 :            : 
    2905                 :       2165 :         struct json *op = json_object_create();
    2906                 :       2165 :         json_object_put_string(op, "op", "mutate");
    2907                 :       2165 :         json_object_put_string(op, "table", txn->inc_table);
    2908                 :       2165 :         json_object_put(op, "where",
    2909                 :       2165 :                         substitute_uuids(where_uuid_equals(&txn->inc_row),
    2910                 :            :                                          txn));
    2911                 :       2165 :         json_object_put(op, "mutations",
    2912                 :            :                         json_array_create_1(
    2913                 :            :                             json_array_create_3(
    2914                 :            :                                 json_string_create(txn->inc_column),
    2915                 :            :                                 json_string_create("+="),
    2916                 :            :                                 json_integer_create(1))));
    2917                 :       2165 :         json_array_add(operations, op);
    2918                 :            : 
    2919                 :       2165 :         op = json_object_create();
    2920                 :       2165 :         json_object_put_string(op, "op", "select");
    2921                 :       2165 :         json_object_put_string(op, "table", txn->inc_table);
    2922                 :       2165 :         json_object_put(op, "where",
    2923                 :       2165 :                         substitute_uuids(where_uuid_equals(&txn->inc_row),
    2924                 :            :                                          txn));
    2925                 :       2165 :         json_object_put(op, "columns",
    2926                 :            :                         json_array_create_1(json_string_create(
    2927                 :            :                                                 txn->inc_column)));
    2928                 :       2165 :         json_array_add(operations, op);
    2929                 :            :     }
    2930                 :            : 
    2931         [ +  + ]:      29062 :     if (txn->comment.length) {
    2932                 :       9701 :         struct json *op = json_object_create();
    2933                 :       9701 :         json_object_put_string(op, "op", "comment");
    2934                 :       9701 :         json_object_put_string(op, "comment", ds_cstr(&txn->comment));
    2935                 :       9701 :         json_array_add(operations, op);
    2936                 :            :     }
    2937                 :            : 
    2938         [ -  + ]:      29062 :     if (txn->dry_run) {
    2939                 :          0 :         struct json *op = json_object_create();
    2940                 :          0 :         json_object_put_string(op, "op", "abort");
    2941                 :          0 :         json_array_add(operations, op);
    2942                 :            :     }
    2943                 :            : 
    2944         [ +  + ]:      29062 :     if (!any_updates) {
    2945                 :      17733 :         txn->status = TXN_UNCHANGED;
    2946                 :      17733 :         json_destroy(operations);
    2947         [ +  - ]:      11329 :     } else if (!jsonrpc_session_send(
    2948                 :      11329 :                    txn->idl->session,
    2949                 :            :                    jsonrpc_create_request(
    2950                 :            :                        "transact", operations, &txn->request_id))) {
    2951                 :      11329 :         hmap_insert(&txn->idl->outstanding_txns, &txn->hmap_node,
    2952                 :            :                     json_hash(txn->request_id, 0));
    2953                 :      11329 :         txn->status = TXN_INCOMPLETE;
    2954                 :            :     } else {
    2955                 :          0 :         txn->status = TXN_TRY_AGAIN;
    2956                 :            :     }
    2957                 :            : 
    2958                 :            : disassemble_out:
    2959                 :      29062 :     ovsdb_idl_txn_disassemble(txn);
    2960                 :            : coverage_out:
    2961   [ -  +  +  +  :      40574 :     switch (txn->status) {
             +  +  -  -  
                      - ]
    2962                 :          0 :     case TXN_UNCOMMITTED:   COVERAGE_INC(txn_uncommitted);    break;
    2963                 :      17733 :     case TXN_UNCHANGED:     COVERAGE_INC(txn_unchanged);      break;
    2964                 :      13846 :     case TXN_INCOMPLETE:    COVERAGE_INC(txn_incomplete);     break;
    2965                 :          1 :     case TXN_ABORTED:       COVERAGE_INC(txn_aborted);        break;
    2966                 :       8993 :     case TXN_SUCCESS:       COVERAGE_INC(txn_success);        break;
    2967                 :          1 :     case TXN_TRY_AGAIN:     COVERAGE_INC(txn_try_again);      break;
    2968                 :          0 :     case TXN_NOT_LOCKED:    COVERAGE_INC(txn_not_locked);     break;
    2969                 :          0 :     case TXN_ERROR:         COVERAGE_INC(txn_error);          break;
    2970                 :            :     }
    2971                 :            : 
    2972                 :      40574 :     return txn->status;
    2973                 :            : }
    2974                 :            : 
    2975                 :            : /* Attempts to commit 'txn', blocking until the commit either succeeds or
    2976                 :            :  * fails.  Returns the final commit status, which may be any TXN_* value other
    2977                 :            :  * than TXN_INCOMPLETE.
    2978                 :            :  *
    2979                 :            :  * This function calls ovsdb_idl_run() on 'txn''s IDL, so it may cause the
    2980                 :            :  * return value of ovsdb_idl_get_seqno() to change. */
    2981                 :            : enum ovsdb_idl_txn_status
    2982                 :       6150 : ovsdb_idl_txn_commit_block(struct ovsdb_idl_txn *txn)
    2983                 :            : {
    2984                 :            :     enum ovsdb_idl_txn_status status;
    2985                 :            : 
    2986                 :       6150 :     fatal_signal_run();
    2987         [ +  + ]:      11068 :     while ((status = ovsdb_idl_txn_commit(txn)) == TXN_INCOMPLETE) {
    2988                 :       4918 :         ovsdb_idl_run(txn->idl);
    2989                 :       4918 :         ovsdb_idl_wait(txn->idl);
    2990                 :       4918 :         ovsdb_idl_txn_wait(txn);
    2991                 :       4918 :         poll_block();
    2992                 :            :     }
    2993                 :       6150 :     return status;
    2994                 :            : }
    2995                 :            : 
    2996                 :            : /* Returns the final (incremented) value of the column in 'txn' that was set to
    2997                 :            :  * be incremented by ovsdb_idl_txn_increment().  'txn' must have committed
    2998                 :            :  * successfully. */
    2999                 :            : int64_t
    3000                 :       2165 : ovsdb_idl_txn_get_increment_new_value(const struct ovsdb_idl_txn *txn)
    3001                 :            : {
    3002         [ -  + ]:       2165 :     ovs_assert(txn->status == TXN_SUCCESS);
    3003                 :       2165 :     return txn->inc_new_value;
    3004                 :            : }
    3005                 :            : 
    3006                 :            : /* Aborts 'txn' without sending it to the database server.  This is effective
    3007                 :            :  * only if ovsdb_idl_txn_commit() has not yet been called for 'txn'.
    3008                 :            :  * Otherwise, it has no effect.
    3009                 :            :  *
    3010                 :            :  * Aborting a transaction doesn't free its memory.  Use
    3011                 :            :  * ovsdb_idl_txn_destroy() to do that. */
    3012                 :            : void
    3013                 :      29469 : ovsdb_idl_txn_abort(struct ovsdb_idl_txn *txn)
    3014                 :            : {
    3015                 :      29469 :     ovsdb_idl_txn_disassemble(txn);
    3016 [ +  + ][ +  + ]:      29469 :     if (txn->status == TXN_UNCOMMITTED || txn->status == TXN_INCOMPLETE) {
    3017                 :       2539 :         txn->status = TXN_ABORTED;
    3018                 :            :     }
    3019                 :      29469 : }
    3020                 :            : 
    3021                 :            : /* Returns a string that reports the error status for 'txn'.  The caller must
    3022                 :            :  * not modify or free the returned string.  A call to ovsdb_idl_txn_destroy()
    3023                 :            :  * for 'txn' may free the returned string.
    3024                 :            :  *
    3025                 :            :  * The return value is ordinarily one of the strings that
    3026                 :            :  * ovsdb_idl_txn_status_to_string() would return, but if the transaction failed
    3027                 :            :  * due to an error reported by the database server, the return value is that
    3028                 :            :  * error. */
    3029                 :            : const char *
    3030                 :       6132 : ovsdb_idl_txn_get_error(const struct ovsdb_idl_txn *txn)
    3031                 :            : {
    3032         [ +  - ]:       6132 :     if (txn->status != TXN_ERROR) {
    3033                 :       6132 :         return ovsdb_idl_txn_status_to_string(txn->status);
    3034         [ #  # ]:          0 :     } else if (txn->error) {
    3035                 :          0 :         return txn->error;
    3036                 :            :     } else {
    3037                 :          0 :         return "no error details available";
    3038                 :            :     }
    3039                 :            : }
    3040                 :            : 
    3041                 :            : static void
    3042                 :          0 : ovsdb_idl_txn_set_error_json(struct ovsdb_idl_txn *txn,
    3043                 :            :                              const struct json *json)
    3044                 :            : {
    3045         [ #  # ]:          0 :     if (txn->error == NULL) {
    3046                 :          0 :         txn->error = json_to_string(json, JSSF_SORT);
    3047                 :            :     }
    3048                 :          0 : }
    3049                 :            : 
    3050                 :            : /* For transaction 'txn' that completed successfully, finds and returns the
    3051                 :            :  * permanent UUID that the database assigned to a newly inserted row, given the
    3052                 :            :  * 'uuid' that ovsdb_idl_txn_insert() assigned locally to that row.
    3053                 :            :  *
    3054                 :            :  * Returns NULL if 'uuid' is not a UUID assigned by ovsdb_idl_txn_insert() or
    3055                 :            :  * if it was assigned by that function and then deleted by
    3056                 :            :  * ovsdb_idl_txn_delete() within the same transaction.  (Rows that are inserted
    3057                 :            :  * and then deleted within a single transaction are never sent to the database
    3058                 :            :  * server, so it never assigns them a permanent UUID.) */
    3059                 :            : const struct uuid *
    3060                 :       2396 : ovsdb_idl_txn_get_insert_uuid(const struct ovsdb_idl_txn *txn,
    3061                 :            :                               const struct uuid *uuid)
    3062                 :            : {
    3063                 :            :     const struct ovsdb_idl_txn_insert *insert;
    3064                 :            : 
    3065 [ -  + ][ #  # ]:       2396 :     ovs_assert(txn->status == TXN_SUCCESS || txn->status == TXN_UNCHANGED);
    3066 [ +  - ][ #  # ]:       3141 :     HMAP_FOR_EACH_IN_BUCKET (insert, hmap_node,
    3067                 :            :                              uuid_hash(uuid), &txn->inserted_rows) {
    3068         [ +  + ]:       3141 :         if (uuid_equals(uuid, &insert->dummy)) {
    3069                 :       2396 :             return &insert->real;
    3070                 :            :         }
    3071                 :            :     }
    3072                 :          0 :     return NULL;
    3073                 :            : }
    3074                 :            : 
    3075                 :            : static void
    3076                 :       8994 : ovsdb_idl_txn_complete(struct ovsdb_idl_txn *txn,
    3077                 :            :                        enum ovsdb_idl_txn_status status)
    3078                 :            : {
    3079                 :       8994 :     txn->status = status;
    3080                 :       8994 :     hmap_remove(&txn->idl->outstanding_txns, &txn->hmap_node);
    3081                 :       8994 : }
    3082                 :            : 
    3083                 :            : /* Writes 'datum' to the specified 'column' in 'row_'.  Updates both 'row_'
    3084                 :            :  * itself and the structs derived from it (e.g. the "struct ovsrec_*", for
    3085                 :            :  * ovs-vswitchd).
    3086                 :            :  *
    3087                 :            :  * 'datum' must have the correct type for its column.  The IDL does not check
    3088                 :            :  * that it meets schema constraints, but ovsdb-server will do so at commit time
    3089                 :            :  * so it had better be correct.
    3090                 :            :  *
    3091                 :            :  * A transaction must be in progress.  Replication of 'column' must not have
    3092                 :            :  * been disabled (by calling ovsdb_idl_omit()).
    3093                 :            :  *
    3094                 :            :  * Usually this function is used indirectly through one of the "set" functions
    3095                 :            :  * generated by ovsdb-idlc.
    3096                 :            :  *
    3097                 :            :  * Takes ownership of what 'datum' points to (and in some cases destroys that
    3098                 :            :  * data before returning) but makes a copy of 'datum' itself.  (Commonly
    3099                 :            :  * 'datum' is on the caller's stack.) */
    3100                 :            : static void
    3101                 :    1086194 : ovsdb_idl_txn_write__(const struct ovsdb_idl_row *row_,
    3102                 :            :                       const struct ovsdb_idl_column *column,
    3103                 :            :                       struct ovsdb_datum *datum, bool owns_datum)
    3104                 :            : {
    3105                 :    1086194 :     struct ovsdb_idl_row *row = CONST_CAST(struct ovsdb_idl_row *, row_);
    3106                 :            :     const struct ovsdb_idl_table_class *class;
    3107                 :            :     size_t column_idx;
    3108                 :            :     bool write_only;
    3109                 :            : 
    3110         [ +  + ]:    1086194 :     if (ovsdb_idl_row_is_synthetic(row)) {
    3111                 :          7 :         goto discard_datum;
    3112                 :            :     }
    3113                 :            : 
    3114                 :    1086187 :     class = row->table->class;
    3115                 :    1086187 :     column_idx = column - class->columns;
    3116                 :    1086187 :     write_only = row->table->modes[column_idx] == OVSDB_IDL_MONITOR;
    3117                 :            : 
    3118         [ -  + ]:    1086187 :     ovs_assert(row->new != NULL);
    3119         [ -  + ]:    1086187 :     ovs_assert(column_idx < class->n_columns);
    3120 [ +  + ][ -  + ]:    1086187 :     ovs_assert(row->old == NULL ||
    3121                 :            :                row->table->modes[column_idx] & OVSDB_IDL_MONITOR);
    3122                 :            : 
    3123 [ +  + ][ -  + ]:    1086187 :     if (row->table->idl->verify_write_only && !write_only) {
    3124         [ #  # ]:          0 :         VLOG_ERR("Bug: Attempt to write to a read/write column (%s:%s) when"
    3125                 :            :                  " explicitly configured not to.", class->name, column->name);
    3126                 :          0 :         goto discard_datum;
    3127                 :            :     }
    3128                 :            : 
    3129                 :            :     /* If this is a write-only column and the datum being written is the same
    3130                 :            :      * as the one already there, just skip the update entirely.  This is worth
    3131                 :            :      * optimizing because we have a lot of columns that get periodically
    3132                 :            :      * refreshed into the database but don't actually change that often.
    3133                 :            :      *
    3134                 :            :      * We don't do this for read/write columns because that would break
    3135                 :            :      * atomicity of transactions--some other client might have written a
    3136                 :            :      * different value in that column since we read it.  (But if a whole
    3137                 :            :      * transaction only does writes of existing values, without making any real
    3138                 :            :      * changes, we will drop the whole transaction later in
    3139                 :            :      * ovsdb_idl_txn_commit().) */
    3140 [ +  + ][ +  + ]:    1086187 :     if (write_only && ovsdb_datum_equals(ovsdb_idl_read(row, column),
    3141                 :            :                                          datum, &column->type)) {
    3142                 :     944103 :         goto discard_datum;
    3143                 :            :     }
    3144                 :            : 
    3145         [ +  + ]:     142084 :     if (hmap_node_is_null(&row->txn_node)) {
    3146                 :      28537 :         hmap_insert(&row->table->idl->txn->txn_rows, &row->txn_node,
    3147                 :            :                     uuid_hash(&row->uuid));
    3148                 :            :     }
    3149         [ +  + ]:     142084 :     if (row->old == row->new) {
    3150                 :      31249 :         row->new = xmalloc(class->n_columns * sizeof *row->new);
    3151                 :            :     }
    3152         [ +  + ]:     142084 :     if (!row->written) {
    3153                 :      47474 :         row->written = bitmap_allocate(class->n_columns);
    3154                 :            :     }
    3155         [ +  + ]:     142084 :     if (bitmap_is_set(row->written, column_idx)) {
    3156                 :       4839 :         ovsdb_datum_destroy(&row->new[column_idx], &column->type);
    3157                 :            :     } else {
    3158                 :     137245 :         bitmap_set1(row->written, column_idx);
    3159                 :            :     }
    3160         [ +  + ]:     142084 :     if (owns_datum) {
    3161                 :      34419 :         row->new[column_idx] = *datum;
    3162                 :            :     } else {
    3163                 :     107665 :         ovsdb_datum_clone(&row->new[column_idx], datum, &column->type);
    3164                 :            :     }
    3165                 :     142084 :     (column->unparse)(row);
    3166                 :     142084 :     (column->parse)(row, &row->new[column_idx]);
    3167                 :     142084 :     return;
    3168                 :            : 
    3169                 :            : discard_datum:
    3170         [ +  + ]:     944110 :     if (owns_datum) {
    3171                 :     339378 :         ovsdb_datum_destroy(datum, &column->type);
    3172                 :            :     }
    3173                 :            : }
    3174                 :            : 
    3175                 :            : void
    3176                 :     373797 : ovsdb_idl_txn_write(const struct ovsdb_idl_row *row,
    3177                 :            :                     const struct ovsdb_idl_column *column,
    3178                 :            :                     struct ovsdb_datum *datum)
    3179                 :            : {
    3180                 :     373797 :     ovsdb_idl_txn_write__(row, column, datum, true);
    3181                 :     373797 : }
    3182                 :            : 
    3183                 :            : void
    3184                 :     712397 : ovsdb_idl_txn_write_clone(const struct ovsdb_idl_row *row,
    3185                 :            :                           const struct ovsdb_idl_column *column,
    3186                 :            :                           const struct ovsdb_datum *datum)
    3187                 :            : {
    3188                 :     712397 :     ovsdb_idl_txn_write__(row, column,
    3189                 :            :                           CONST_CAST(struct ovsdb_datum *, datum), false);
    3190                 :     712397 : }
    3191                 :            : 
    3192                 :            : /* Causes the original contents of 'column' in 'row_' to be verified as a
    3193                 :            :  * prerequisite to completing the transaction.  That is, if 'column' in 'row_'
    3194                 :            :  * changed (or if 'row_' was deleted) between the time that the IDL originally
    3195                 :            :  * read its contents and the time that the transaction commits, then the
    3196                 :            :  * transaction aborts and ovsdb_idl_txn_commit() returns TXN_AGAIN_WAIT or
    3197                 :            :  * TXN_AGAIN_NOW (depending on whether the database change has already been
    3198                 :            :  * received).
    3199                 :            :  *
    3200                 :            :  * The intention is that, to ensure that no transaction commits based on dirty
    3201                 :            :  * reads, an application should call ovsdb_idl_txn_verify() on each data item
    3202                 :            :  * read as part of a read-modify-write operation.
    3203                 :            :  *
    3204                 :            :  * In some cases ovsdb_idl_txn_verify() reduces to a no-op, because the current
    3205                 :            :  * value of 'column' is already known:
    3206                 :            :  *
    3207                 :            :  *   - If 'row_' is a row created by the current transaction (returned by
    3208                 :            :  *     ovsdb_idl_txn_insert()).
    3209                 :            :  *
    3210                 :            :  *   - If 'column' has already been modified (with ovsdb_idl_txn_write())
    3211                 :            :  *     within the current transaction.
    3212                 :            :  *
    3213                 :            :  * Because of the latter property, always call ovsdb_idl_txn_verify() *before*
    3214                 :            :  * ovsdb_idl_txn_write() for a given read-modify-write.
    3215                 :            :  *
    3216                 :            :  * A transaction must be in progress.
    3217                 :            :  *
    3218                 :            :  * Usually this function is used indirectly through one of the "verify"
    3219                 :            :  * functions generated by ovsdb-idlc. */
    3220                 :            : void
    3221                 :     107674 : ovsdb_idl_txn_verify(const struct ovsdb_idl_row *row_,
    3222                 :            :                      const struct ovsdb_idl_column *column)
    3223                 :            : {
    3224                 :     107674 :     struct ovsdb_idl_row *row = CONST_CAST(struct ovsdb_idl_row *, row_);
    3225                 :            :     const struct ovsdb_idl_table_class *class;
    3226                 :            :     size_t column_idx;
    3227                 :            : 
    3228         [ -  + ]:     107674 :     if (ovsdb_idl_row_is_synthetic(row)) {
    3229                 :          0 :         return;
    3230                 :            :     }
    3231                 :            : 
    3232                 :     107674 :     class = row->table->class;
    3233                 :     107674 :     column_idx = column - class->columns;
    3234                 :            : 
    3235         [ -  + ]:     107674 :     ovs_assert(row->new != NULL);
    3236 [ +  + ][ -  + ]:     107674 :     ovs_assert(row->old == NULL ||
    3237                 :            :                row->table->modes[column_idx] & OVSDB_IDL_MONITOR);
    3238         [ +  + ]:     107674 :     if (!row->old
    3239 [ +  + ][ +  + ]:      35809 :         || (row->written && bitmap_is_set(row->written, column_idx))) {
    3240                 :      75786 :         return;
    3241                 :            :     }
    3242                 :            : 
    3243         [ +  + ]:      31888 :     if (hmap_node_is_null(&row->txn_node)) {
    3244                 :      29582 :         hmap_insert(&row->table->idl->txn->txn_rows, &row->txn_node,
    3245                 :            :                     uuid_hash(&row->uuid));
    3246                 :            :     }
    3247         [ +  + ]:      31888 :     if (!row->prereqs) {
    3248                 :      29606 :         row->prereqs = bitmap_allocate(class->n_columns);
    3249                 :            :     }
    3250                 :      31888 :     bitmap_set1(row->prereqs, column_idx);
    3251                 :            : }
    3252                 :            : 
    3253                 :            : /* Deletes 'row_' from its table.  May free 'row_', so it must not be
    3254                 :            :  * accessed afterward.
    3255                 :            :  *
    3256                 :            :  * A transaction must be in progress.
    3257                 :            :  *
    3258                 :            :  * Usually this function is used indirectly through one of the "delete"
    3259                 :            :  * functions generated by ovsdb-idlc. */
    3260                 :            : void
    3261                 :       3565 : ovsdb_idl_txn_delete(const struct ovsdb_idl_row *row_)
    3262                 :            : {
    3263                 :       3565 :     struct ovsdb_idl_row *row = CONST_CAST(struct ovsdb_idl_row *, row_);
    3264                 :            : 
    3265         [ -  + ]:       3565 :     if (ovsdb_idl_row_is_synthetic(row)) {
    3266                 :          0 :         return;
    3267                 :            :     }
    3268                 :            : 
    3269         [ -  + ]:       3565 :     ovs_assert(row->new != NULL);
    3270         [ +  + ]:       3565 :     if (!row->old) {
    3271                 :         23 :         ovsdb_idl_row_unparse(row);
    3272                 :         23 :         ovsdb_idl_row_clear_new(row);
    3273         [ -  + ]:         23 :         ovs_assert(!row->prereqs);
    3274                 :         23 :         hmap_remove(&row->table->rows, &row->hmap_node);
    3275                 :         23 :         hmap_remove(&row->table->idl->txn->txn_rows, &row->txn_node);
    3276                 :         23 :         free(row);
    3277                 :         23 :         return;
    3278                 :            :     }
    3279         [ +  + ]:       3542 :     if (hmap_node_is_null(&row->txn_node)) {
    3280                 :       3449 :         hmap_insert(&row->table->idl->txn->txn_rows, &row->txn_node,
    3281                 :            :                     uuid_hash(&row->uuid));
    3282                 :            :     }
    3283                 :       3542 :     ovsdb_idl_row_clear_new(row);
    3284                 :       3542 :     row->new = NULL;
    3285                 :            : }
    3286                 :            : 
    3287                 :            : /* Inserts and returns a new row in the table with the specified 'class' in the
    3288                 :            :  * database with open transaction 'txn'.
    3289                 :            :  *
    3290                 :            :  * The new row is assigned a provisional UUID.  If 'uuid' is null then one is
    3291                 :            :  * randomly generated; otherwise 'uuid' should specify a randomly generated
    3292                 :            :  * UUID not otherwise in use.  ovsdb-server will assign a different UUID when
    3293                 :            :  * 'txn' is committed, but the IDL will replace any uses of the provisional
    3294                 :            :  * UUID in the data to be to be committed by the UUID assigned by
    3295                 :            :  * ovsdb-server.
    3296                 :            :  *
    3297                 :            :  * Usually this function is used indirectly through one of the "insert"
    3298                 :            :  * functions generated by ovsdb-idlc. */
    3299                 :            : const struct ovsdb_idl_row *
    3300                 :      16949 : ovsdb_idl_txn_insert(struct ovsdb_idl_txn *txn,
    3301                 :            :                      const struct ovsdb_idl_table_class *class,
    3302                 :            :                      const struct uuid *uuid)
    3303                 :            : {
    3304                 :      16949 :     struct ovsdb_idl_row *row = ovsdb_idl_row_create__(class);
    3305                 :            : 
    3306         [ +  + ]:      16949 :     if (uuid) {
    3307         [ -  + ]:        108 :         ovs_assert(!ovsdb_idl_txn_get_row(txn, uuid));
    3308                 :        108 :         row->uuid = *uuid;
    3309                 :            :     } else {
    3310                 :      16841 :         uuid_generate(&row->uuid);
    3311                 :            :     }
    3312                 :            : 
    3313                 :      16949 :     row->table = ovsdb_idl_table_from_class(txn->idl, class);
    3314                 :      16949 :     row->new = xmalloc(class->n_columns * sizeof *row->new);
    3315                 :      16949 :     hmap_insert(&row->table->rows, &row->hmap_node, uuid_hash(&row->uuid));
    3316                 :      16949 :     hmap_insert(&txn->txn_rows, &row->txn_node, uuid_hash(&row->uuid));
    3317                 :      16949 :     return row;
    3318                 :            : }
    3319                 :            : 
    3320                 :            : static void
    3321                 :       7152 : ovsdb_idl_txn_abort_all(struct ovsdb_idl *idl)
    3322                 :            : {
    3323                 :            :     struct ovsdb_idl_txn *txn;
    3324                 :            : 
    3325 [ -  + ][ -  + ]:       7152 :     HMAP_FOR_EACH (txn, hmap_node, &idl->outstanding_txns) {
    3326                 :          0 :         ovsdb_idl_txn_complete(txn, TXN_TRY_AGAIN);
    3327                 :            :     }
    3328                 :       7152 : }
    3329                 :            : 
    3330                 :            : static struct ovsdb_idl_txn *
    3331                 :      11338 : ovsdb_idl_txn_find(struct ovsdb_idl *idl, const struct json *id)
    3332                 :            : {
    3333                 :            :     struct ovsdb_idl_txn *txn;
    3334                 :            : 
    3335 [ +  + ][ -  + ]:      11338 :     HMAP_FOR_EACH_WITH_HASH (txn, hmap_node,
    3336                 :            :                              json_hash(id, 0), &idl->outstanding_txns) {
    3337         [ +  - ]:       8994 :         if (json_equal(id, txn->request_id)) {
    3338                 :       8994 :             return txn;
    3339                 :            :         }
    3340                 :            :     }
    3341                 :       2344 :     return NULL;
    3342                 :            : }
    3343                 :            : 
    3344                 :            : static bool
    3345                 :      25586 : check_json_type(const struct json *json, enum json_type type, const char *name)
    3346                 :            : {
    3347         [ -  + ]:      25586 :     if (!json) {
    3348         [ #  # ]:          0 :         VLOG_WARN_RL(&syntax_rl, "%s is missing", name);
    3349                 :          0 :         return false;
    3350         [ -  + ]:      25586 :     } else if (json->type != type) {
    3351         [ #  # ]:          0 :         VLOG_WARN_RL(&syntax_rl, "%s is %s instead of %s",
    3352                 :            :                      name, json_type_to_string(json->type),
    3353                 :            :                      json_type_to_string(type));
    3354                 :          0 :         return false;
    3355                 :            :     } else {
    3356                 :      25586 :         return true;
    3357                 :            :     }
    3358                 :            : }
    3359                 :            : 
    3360                 :            : static bool
    3361                 :       2165 : ovsdb_idl_txn_process_inc_reply(struct ovsdb_idl_txn *txn,
    3362                 :            :                                 const struct json_array *results)
    3363                 :            : {
    3364                 :            :     struct json *count, *rows, *row, *column;
    3365                 :            :     struct shash *mutate, *select;
    3366                 :            : 
    3367         [ -  + ]:       2165 :     if (txn->inc_index + 2 > results->n) {
    3368         [ #  # ]:          0 :         VLOG_WARN_RL(&syntax_rl, "reply does not contain enough operations "
    3369                 :            :                      "for increment (has %"PRIuSIZE", needs %u)",
    3370                 :            :                      results->n, txn->inc_index + 2);
    3371                 :          0 :         return false;
    3372                 :            :     }
    3373                 :            : 
    3374                 :            :     /* We know that this is a JSON object because the loop in
    3375                 :            :      * ovsdb_idl_txn_process_reply() checked. */
    3376                 :       2165 :     mutate = json_object(results->elems[txn->inc_index]);
    3377                 :       2165 :     count = shash_find_data(mutate, "count");
    3378         [ -  + ]:       2165 :     if (!check_json_type(count, JSON_INTEGER, "\"mutate\" reply \"count\"")) {
    3379                 :          0 :         return false;
    3380                 :            :     }
    3381         [ -  + ]:       2165 :     if (count->u.integer != 1) {
    3382         [ #  # ]:          0 :         VLOG_WARN_RL(&syntax_rl,
    3383                 :            :                      "\"mutate\" reply \"count\" is %lld instead of 1",
    3384                 :            :                      count->u.integer);
    3385                 :          0 :         return false;
    3386                 :            :     }
    3387                 :            : 
    3388                 :       2165 :     select = json_object(results->elems[txn->inc_index + 1]);
    3389                 :       2165 :     rows = shash_find_data(select, "rows");
    3390         [ -  + ]:       2165 :     if (!check_json_type(rows, JSON_ARRAY, "\"select\" reply \"rows\"")) {
    3391                 :          0 :         return false;
    3392                 :            :     }
    3393         [ -  + ]:       2165 :     if (rows->u.array.n != 1) {
    3394         [ #  # ]:          0 :         VLOG_WARN_RL(&syntax_rl, "\"select\" reply \"rows\" has %"PRIuSIZE" elements "
    3395                 :            :                      "instead of 1",
    3396                 :            :                      rows->u.array.n);
    3397                 :          0 :         return false;
    3398                 :            :     }
    3399                 :       2165 :     row = rows->u.array.elems[0];
    3400         [ -  + ]:       2165 :     if (!check_json_type(row, JSON_OBJECT, "\"select\" reply row")) {
    3401                 :          0 :         return false;
    3402                 :            :     }
    3403                 :       2165 :     column = shash_find_data(json_object(row), txn->inc_column);
    3404         [ -  + ]:       2165 :     if (!check_json_type(column, JSON_INTEGER,
    3405                 :            :                          "\"select\" reply inc column")) {
    3406                 :          0 :         return false;
    3407                 :            :     }
    3408                 :       2165 :     txn->inc_new_value = column->u.integer;
    3409                 :       2165 :     return true;
    3410                 :            : }
    3411                 :            : 
    3412                 :            : static bool
    3413                 :      16926 : ovsdb_idl_txn_process_insert_reply(struct ovsdb_idl_txn_insert *insert,
    3414                 :            :                                    const struct json_array *results)
    3415                 :            : {
    3416                 :            :     static const struct ovsdb_base_type uuid_type = OVSDB_BASE_UUID_INIT;
    3417                 :            :     struct ovsdb_error *error;
    3418                 :            :     struct json *json_uuid;
    3419                 :            :     union ovsdb_atom uuid;
    3420                 :            :     struct shash *reply;
    3421                 :            : 
    3422         [ -  + ]:      16926 :     if (insert->op_index >= results->n) {
    3423         [ #  # ]:          0 :         VLOG_WARN_RL(&syntax_rl, "reply does not contain enough operations "
    3424                 :            :                      "for insert (has %"PRIuSIZE", needs %u)",
    3425                 :            :                      results->n, insert->op_index);
    3426                 :          0 :         return false;
    3427                 :            :     }
    3428                 :            : 
    3429                 :            :     /* We know that this is a JSON object because the loop in
    3430                 :            :      * ovsdb_idl_txn_process_reply() checked. */
    3431                 :      16926 :     reply = json_object(results->elems[insert->op_index]);
    3432                 :      16926 :     json_uuid = shash_find_data(reply, "uuid");
    3433         [ -  + ]:      16926 :     if (!check_json_type(json_uuid, JSON_ARRAY, "\"insert\" reply \"uuid\"")) {
    3434                 :          0 :         return false;
    3435                 :            :     }
    3436                 :            : 
    3437                 :      16926 :     error = ovsdb_atom_from_json(&uuid, &uuid_type, json_uuid, NULL);
    3438         [ -  + ]:      16926 :     if (error) {
    3439                 :          0 :         char *s = ovsdb_error_to_string(error);
    3440         [ #  # ]:          0 :         VLOG_WARN_RL(&syntax_rl, "\"insert\" reply \"uuid\" is not a JSON "
    3441                 :            :                      "UUID: %s", s);
    3442                 :          0 :         free(s);
    3443                 :          0 :         ovsdb_error_destroy(error);
    3444                 :          0 :         return false;
    3445                 :            :     }
    3446                 :            : 
    3447                 :      16926 :     insert->real = uuid.uuid;
    3448                 :            : 
    3449                 :      16926 :     return true;
    3450                 :            : }
    3451                 :            : 
    3452                 :            : static bool
    3453                 :      11338 : ovsdb_idl_txn_process_reply(struct ovsdb_idl *idl,
    3454                 :            :                             const struct jsonrpc_msg *msg)
    3455                 :            : {
    3456                 :            :     struct ovsdb_idl_txn *txn;
    3457                 :            :     enum ovsdb_idl_txn_status status;
    3458                 :            : 
    3459                 :      11338 :     txn = ovsdb_idl_txn_find(idl, msg->id);
    3460         [ +  + ]:      11338 :     if (!txn) {
    3461                 :       2344 :         return false;
    3462                 :            :     }
    3463                 :            : 
    3464         [ -  + ]:       8994 :     if (msg->type == JSONRPC_ERROR) {
    3465                 :          0 :         status = TXN_ERROR;
    3466         [ -  + ]:       8994 :     } else if (msg->result->type != JSON_ARRAY) {
    3467         [ #  # ]:          0 :         VLOG_WARN_RL(&syntax_rl, "reply to \"transact\" is not JSON array");
    3468                 :          0 :         status = TXN_ERROR;
    3469                 :            :     } else {
    3470                 :       8994 :         struct json_array *ops = &msg->result->u.array;
    3471                 :       8994 :         int hard_errors = 0;
    3472                 :       8994 :         int soft_errors = 0;
    3473                 :       8994 :         int lock_errors = 0;
    3474                 :            :         size_t i;
    3475                 :            : 
    3476         [ +  + ]:      78059 :         for (i = 0; i < ops->n; i++) {
    3477                 :      69065 :             struct json *op = ops->elems[i];
    3478                 :            : 
    3479         [ +  + ]:      69065 :             if (op->type == JSON_NULL) {
    3480                 :            :                 /* This isn't an error in itself but indicates that some prior
    3481                 :            :                  * operation failed, so make sure that we know about it. */
    3482                 :          1 :                 soft_errors++;
    3483         [ +  - ]:      69064 :             } else if (op->type == JSON_OBJECT) {
    3484                 :            :                 struct json *error;
    3485                 :            : 
    3486                 :      69064 :                 error = shash_find_data(json_object(op), "error");
    3487         [ +  + ]:      69064 :                 if (error) {
    3488         [ +  - ]:          1 :                     if (error->type == JSON_STRING) {
    3489         [ +  - ]:          1 :                         if (!strcmp(error->u.string, "timed out")) {
    3490                 :          1 :                             soft_errors++;
    3491         [ #  # ]:          0 :                         } else if (!strcmp(error->u.string, "not owner")) {
    3492                 :          0 :                             lock_errors++;
    3493         [ #  # ]:          0 :                         } else if (strcmp(error->u.string, "aborted")) {
    3494                 :          0 :                             hard_errors++;
    3495                 :          1 :                             ovsdb_idl_txn_set_error_json(txn, op);
    3496                 :            :                         }
    3497                 :            :                     } else {
    3498                 :          0 :                         hard_errors++;
    3499                 :          0 :                         ovsdb_idl_txn_set_error_json(txn, op);
    3500         [ #  # ]:      69064 :                         VLOG_WARN_RL(&syntax_rl,
    3501                 :            :                                      "\"error\" in reply is not JSON string");
    3502                 :            :                     }
    3503                 :            :                 }
    3504                 :            :             } else {
    3505                 :          0 :                 hard_errors++;
    3506                 :          0 :                 ovsdb_idl_txn_set_error_json(txn, op);
    3507         [ #  # ]:          0 :                 VLOG_WARN_RL(&syntax_rl,
    3508                 :            :                              "operation reply is not JSON null or object");
    3509                 :            :             }
    3510                 :            :         }
    3511                 :            : 
    3512 [ +  + ][ +  - ]:       8994 :         if (!soft_errors && !hard_errors && !lock_errors) {
                 [ +  - ]
    3513                 :            :             struct ovsdb_idl_txn_insert *insert;
    3514                 :            : 
    3515 [ +  + ][ -  + ]:       8993 :             if (txn->inc_table && !ovsdb_idl_txn_process_inc_reply(txn, ops)) {
    3516                 :          0 :                 hard_errors++;
    3517                 :            :             }
    3518                 :            : 
    3519 [ +  + ][ -  + ]:      25919 :             HMAP_FOR_EACH (insert, hmap_node, &txn->inserted_rows) {
    3520         [ -  + ]:      16926 :                 if (!ovsdb_idl_txn_process_insert_reply(insert, ops)) {
    3521                 :          0 :                     hard_errors++;
    3522                 :            :                 }
    3523                 :            :             }
    3524                 :            :         }
    3525                 :            : 
    3526 [ +  - ][ +  - ]:       8994 :         status = (hard_errors ? TXN_ERROR
                 [ +  + ]
    3527                 :            :                   : lock_errors ? TXN_NOT_LOCKED
    3528                 :            :                   : soft_errors ? TXN_TRY_AGAIN
    3529                 :            :                   : TXN_SUCCESS);
    3530                 :            :     }
    3531                 :            : 
    3532                 :       8994 :     ovsdb_idl_txn_complete(txn, status);
    3533                 :       8994 :     return true;
    3534                 :            : }
    3535                 :            : 
    3536                 :            : /* Returns the transaction currently active for 'row''s IDL.  A transaction
    3537                 :            :  * must currently be active. */
    3538                 :            : struct ovsdb_idl_txn *
    3539                 :          0 : ovsdb_idl_txn_get(const struct ovsdb_idl_row *row)
    3540                 :            : {
    3541                 :          0 :     struct ovsdb_idl_txn *txn = row->table->idl->txn;
    3542         [ #  # ]:          0 :     ovs_assert(txn != NULL);
    3543                 :          0 :     return txn;
    3544                 :            : }
    3545                 :            : 
    3546                 :            : /* Returns the IDL on which 'txn' acts. */
    3547                 :            : struct ovsdb_idl *
    3548                 :          0 : ovsdb_idl_txn_get_idl (struct ovsdb_idl_txn *txn)
    3549                 :            : {
    3550                 :          0 :     return txn->idl;
    3551                 :            : }
    3552                 :            : 
    3553                 :            : /* Blocks until 'idl' successfully connects to the remote database and
    3554                 :            :  * retrieves its contents. */
    3555                 :            : void
    3556                 :        113 : ovsdb_idl_get_initial_snapshot(struct ovsdb_idl *idl)
    3557                 :            : {
    3558                 :            :     while (1) {
    3559                 :        372 :         ovsdb_idl_run(idl);
    3560         [ +  + ]:        372 :         if (ovsdb_idl_has_ever_connected(idl)) {
    3561                 :        113 :             return;
    3562                 :            :         }
    3563                 :        259 :         ovsdb_idl_wait(idl);
    3564                 :        259 :         poll_block();
    3565                 :        259 :     }
    3566                 :            : }
    3567                 :            : 
    3568                 :            : /* If 'lock_name' is nonnull, configures 'idl' to obtain the named lock from
    3569                 :            :  * the database server and to avoid modifying the database when the lock cannot
    3570                 :            :  * be acquired (that is, when another client has the same lock).
    3571                 :            :  *
    3572                 :            :  * If 'lock_name' is NULL, drops the locking requirement and releases the
    3573                 :            :  * lock. */
    3574                 :            : void
    3575                 :        617 : ovsdb_idl_set_lock(struct ovsdb_idl *idl, const char *lock_name)
    3576                 :            : {
    3577         [ -  + ]:        617 :     ovs_assert(!idl->txn);
    3578         [ -  + ]:        617 :     ovs_assert(hmap_is_empty(&idl->outstanding_txns));
    3579                 :            : 
    3580 [ -  + ][ #  # ]:        617 :     if (idl->lock_name && (!lock_name || strcmp(lock_name, idl->lock_name))) {
                 [ #  # ]
    3581                 :            :         /* Release previous lock. */
    3582                 :          0 :         ovsdb_idl_send_unlock_request(idl);
    3583                 :          0 :         free(idl->lock_name);
    3584                 :          0 :         idl->lock_name = NULL;
    3585                 :          0 :         idl->is_lock_contended = false;
    3586                 :            :     }
    3587                 :            : 
    3588 [ +  - ][ +  - ]:        617 :     if (lock_name && !idl->lock_name) {
    3589                 :            :         /* Acquire new lock. */
    3590                 :        617 :         idl->lock_name = xstrdup(lock_name);
    3591                 :        617 :         ovsdb_idl_send_lock_request(idl);
    3592                 :            :     }
    3593                 :        617 : }
    3594                 :            : 
    3595                 :            : /* Returns true if 'idl' is configured to obtain a lock and owns that lock.
    3596                 :            :  *
    3597                 :            :  * Locking and unlocking happens asynchronously from the database client's
    3598                 :            :  * point of view, so the information is only useful for optimization (e.g. if
    3599                 :            :  * the client doesn't have the lock then there's no point in trying to write to
    3600                 :            :  * the database). */
    3601                 :            : bool
    3602                 :     116278 : ovsdb_idl_has_lock(const struct ovsdb_idl *idl)
    3603                 :            : {
    3604                 :     116278 :     return idl->has_lock;
    3605                 :            : }
    3606                 :            : 
    3607                 :            : /* Returns true if 'idl' is configured to obtain a lock but the database server
    3608                 :            :  * has indicated that some other client already owns the requested lock. */
    3609                 :            : bool
    3610                 :     105174 : ovsdb_idl_is_lock_contended(const struct ovsdb_idl *idl)
    3611                 :            : {
    3612                 :     105174 :     return idl->is_lock_contended;
    3613                 :            : }
    3614                 :            : 
    3615                 :            : static void
    3616                 :       1855 : ovsdb_idl_update_has_lock(struct ovsdb_idl *idl, bool new_has_lock)
    3617                 :            : {
    3618 [ +  + ][ +  + ]:       1855 :     if (new_has_lock && !idl->has_lock) {
    3619 [ +  - ][ +  + ]:        617 :         if (idl->state == IDL_S_MONITORING ||
    3620                 :        617 :             idl->state == IDL_S_MONITORING_COND) {
    3621                 :          1 :             idl->change_seqno++;
    3622                 :            :         } else {
    3623                 :            :             /* We're setting up a session, so don't signal that the database
    3624                 :            :              * changed.  Finalizing the session will increment change_seqno
    3625                 :            :              * anyhow. */
    3626                 :            :         }
    3627                 :        617 :         idl->is_lock_contended = false;
    3628                 :            :     }
    3629                 :       1855 :     idl->has_lock = new_has_lock;
    3630                 :       1855 : }
    3631                 :            : 
    3632                 :            : static void
    3633                 :       1235 : ovsdb_idl_send_lock_request__(struct ovsdb_idl *idl, const char *method,
    3634                 :            :                               struct json **idp)
    3635                 :            : {
    3636                 :       1235 :     ovsdb_idl_update_has_lock(idl, false);
    3637                 :            : 
    3638                 :       1235 :     json_destroy(idl->lock_request_id);
    3639                 :       1235 :     idl->lock_request_id = NULL;
    3640                 :            : 
    3641         [ +  + ]:       1235 :     if (jsonrpc_session_is_connected(idl->session)) {
    3642                 :            :         struct json *params;
    3643                 :            : 
    3644                 :        618 :         params = json_array_create_1(json_string_create(idl->lock_name));
    3645                 :        618 :         jsonrpc_session_send(idl->session,
    3646                 :            :                              jsonrpc_create_request(method, params, idp));
    3647                 :            :     }
    3648                 :       1235 : }
    3649                 :            : 
    3650                 :            : static void
    3651                 :       1235 : ovsdb_idl_send_lock_request(struct ovsdb_idl *idl)
    3652                 :            : {
    3653                 :       1235 :     ovsdb_idl_send_lock_request__(idl, "lock", &idl->lock_request_id);
    3654                 :       1235 : }
    3655                 :            : 
    3656                 :            : static void
    3657                 :          0 : ovsdb_idl_send_unlock_request(struct ovsdb_idl *idl)
    3658                 :            : {
    3659                 :          0 :     ovsdb_idl_send_lock_request__(idl, "unlock", NULL);
    3660                 :          0 : }
    3661                 :            : 
    3662                 :            : static void
    3663                 :        618 : ovsdb_idl_parse_lock_reply(struct ovsdb_idl *idl, const struct json *result)
    3664                 :            : {
    3665                 :            :     bool got_lock;
    3666                 :            : 
    3667                 :        618 :     json_destroy(idl->lock_request_id);
    3668                 :        618 :     idl->lock_request_id = NULL;
    3669                 :            : 
    3670         [ +  - ]:        618 :     if (result->type == JSON_OBJECT) {
    3671                 :            :         const struct json *locked;
    3672                 :            : 
    3673                 :        618 :         locked = shash_find_data(json_object(result), "locked");
    3674 [ +  - ][ +  + ]:        618 :         got_lock = locked && locked->type == JSON_TRUE;
    3675                 :            :     } else {
    3676                 :          0 :         got_lock = false;
    3677                 :            :     }
    3678                 :            : 
    3679                 :        618 :     ovsdb_idl_update_has_lock(idl, got_lock);
    3680         [ +  + ]:        618 :     if (!got_lock) {
    3681                 :          2 :         idl->is_lock_contended = true;
    3682                 :            :     }
    3683                 :        618 : }
    3684                 :            : 
    3685                 :            : static void
    3686                 :          2 : ovsdb_idl_parse_lock_notify(struct ovsdb_idl *idl,
    3687                 :            :                             const struct json *params,
    3688                 :            :                             bool new_has_lock)
    3689                 :            : {
    3690         [ +  - ]:          2 :     if (idl->lock_name
    3691         [ +  - ]:          2 :         && params->type == JSON_ARRAY
    3692         [ +  - ]:          2 :         && json_array(params)->n > 0
    3693         [ +  - ]:          2 :         && json_array(params)->elems[0]->type == JSON_STRING) {
    3694                 :          2 :         const char *lock_name = json_string(json_array(params)->elems[0]);
    3695                 :            : 
    3696         [ +  - ]:          2 :         if (!strcmp(idl->lock_name, lock_name)) {
    3697                 :          2 :             ovsdb_idl_update_has_lock(idl, new_has_lock);
    3698         [ -  + ]:          2 :             if (!new_has_lock) {
    3699                 :          0 :                 idl->is_lock_contended = true;
    3700                 :            :             }
    3701                 :            :         }
    3702                 :            :     }
    3703                 :          2 : }
    3704                 :            : 
    3705                 :            : /* Inserts a new Map Operation into current transaction. */
    3706                 :            : static void
    3707                 :          5 : ovsdb_idl_txn_add_map_op(struct ovsdb_idl_row *row,
    3708                 :            :                          const struct ovsdb_idl_column *column,
    3709                 :            :                          struct ovsdb_datum *datum,
    3710                 :            :                          enum map_op_type op_type)
    3711                 :            : {
    3712                 :            :     const struct ovsdb_idl_table_class *class;
    3713                 :            :     size_t column_idx;
    3714                 :            :     struct map_op *map_op;
    3715                 :            : 
    3716                 :          5 :     class = row->table->class;
    3717                 :          5 :     column_idx = column - class->columns;
    3718                 :            : 
    3719                 :            :     /* Check if a map operation list exists for this column. */
    3720         [ +  + ]:          5 :     if (!row->map_op_written) {
    3721                 :          4 :         row->map_op_written = bitmap_allocate(class->n_columns);
    3722                 :          4 :         row->map_op_lists = xzalloc(class->n_columns *
    3723                 :            :                                     sizeof *row->map_op_lists);
    3724                 :            :     }
    3725         [ +  - ]:          5 :     if (!row->map_op_lists[column_idx]) {
    3726                 :          5 :         row->map_op_lists[column_idx] = map_op_list_create();
    3727                 :            :     }
    3728                 :            : 
    3729                 :            :     /* Add a map operation to the corresponding list. */
    3730                 :          5 :     map_op = map_op_create(datum, op_type);
    3731                 :          5 :     bitmap_set1(row->map_op_written, column_idx);
    3732                 :          5 :     map_op_list_add(row->map_op_lists[column_idx], map_op, &column->type);
    3733                 :            : 
    3734                 :            :     /* Add this row to transaction's list of rows. */
    3735         [ +  + ]:          5 :     if (hmap_node_is_null(&row->txn_node)) {
    3736                 :          4 :         hmap_insert(&row->table->idl->txn->txn_rows, &row->txn_node,
    3737                 :            :                     uuid_hash(&row->uuid));
    3738                 :            :     }
    3739                 :          5 : }
    3740                 :            : 
    3741                 :            : /* Inserts a new Set Operation into current transaction. */
    3742                 :            : static void
    3743                 :         60 : ovsdb_idl_txn_add_set_op(struct ovsdb_idl_row *row,
    3744                 :            :                          const struct ovsdb_idl_column *column,
    3745                 :            :                          struct ovsdb_datum *datum,
    3746                 :            :                          enum set_op_type op_type)
    3747                 :            : {
    3748                 :            :     const struct ovsdb_idl_table_class *class;
    3749                 :            :     size_t column_idx;
    3750                 :            :     struct set_op *set_op;
    3751                 :            : 
    3752                 :         60 :     class = row->table->class;
    3753                 :         60 :     column_idx = column - class->columns;
    3754                 :            : 
    3755                 :            :     /* Check if a set operation list exists for this column. */
    3756         [ +  + ]:         60 :     if (!row->set_op_written) {
    3757                 :         54 :         row->set_op_written = bitmap_allocate(class->n_columns);
    3758                 :         54 :         row->set_op_lists = xzalloc(class->n_columns *
    3759                 :            :                                     sizeof *row->set_op_lists);
    3760                 :            :     }
    3761         [ +  + ]:         60 :     if (!row->set_op_lists[column_idx]) {
    3762                 :         54 :         row->set_op_lists[column_idx] = set_op_list_create();
    3763                 :            :     }
    3764                 :            : 
    3765                 :            :     /* Add a set operation to the corresponding list. */
    3766                 :         60 :     set_op = set_op_create(datum, op_type);
    3767                 :         60 :     bitmap_set1(row->set_op_written, column_idx);
    3768                 :         60 :     set_op_list_add(row->set_op_lists[column_idx], set_op, &column->type);
    3769                 :            : 
    3770                 :            :     /* Add this row to the transactions's list of rows. */
    3771         [ +  + ]:         60 :     if (hmap_node_is_null(&row->txn_node)) {
    3772                 :         54 :         hmap_insert(&row->table->idl->txn->txn_rows, &row->txn_node,
    3773                 :            :                     uuid_hash(&row->uuid));
    3774                 :            :     }
    3775                 :         60 : }
    3776                 :            : 
    3777                 :            : static bool
    3778                 :         65 : is_valid_partial_update(const struct ovsdb_idl_row *row,
    3779                 :            :                         const struct ovsdb_idl_column *column,
    3780                 :            :                         struct ovsdb_datum *datum)
    3781                 :            : {
    3782                 :            :     /* Verify that this column is being monitored. */
    3783                 :         65 :     unsigned int column_idx = column - row->table->class->columns;
    3784         [ -  + ]:         65 :     if (!(row->table->modes[column_idx] & OVSDB_IDL_MONITOR)) {
    3785         [ #  # ]:          0 :         VLOG_WARN("cannot partially update non-monitored column");
    3786                 :          0 :         return false;
    3787                 :            :     }
    3788                 :            : 
    3789                 :            :     /* Verify that the update affects a single element. */
    3790         [ -  + ]:         65 :     if (datum->n != 1) {
    3791         [ #  # ]:          0 :         VLOG_WARN("invalid datum for partial update");
    3792                 :          0 :         return false;
    3793                 :            :     }
    3794                 :            : 
    3795                 :         65 :     return true;
    3796                 :            : }
    3797                 :            : 
    3798                 :            : /* Inserts the value described in 'datum' into the map in 'column' in
    3799                 :            :  * 'row_'. If the value doesn't already exist in 'column' then it's value
    3800                 :            :  * is added.  The value in 'datum' must be of the same type as the values
    3801                 :            :  * in 'column'.  This function takes ownership of 'datum'.
    3802                 :            :  *
    3803                 :            :  * Usually this function is used indirectly through one of the "update"
    3804                 :            :  * functions generated by vswitch-idl. */
    3805                 :            : void
    3806                 :         40 : ovsdb_idl_txn_write_partial_set(const struct ovsdb_idl_row *row_,
    3807                 :            :                                 const struct ovsdb_idl_column *column,
    3808                 :            :                                 struct ovsdb_datum *datum)
    3809                 :            : {
    3810                 :         40 :     struct ovsdb_idl_row *row = CONST_CAST(struct ovsdb_idl_row *, row_);
    3811                 :            :     enum set_op_type op_type;
    3812                 :            : 
    3813         [ -  + ]:         40 :     if (!is_valid_partial_update(row, column, datum)) {
    3814                 :          0 :         ovsdb_datum_destroy(datum, &column->type);
    3815                 :          0 :         free(datum);
    3816                 :          0 :         return;
    3817                 :            :     }
    3818                 :            : 
    3819                 :         40 :     op_type = SET_OP_INSERT;
    3820                 :            : 
    3821                 :         40 :     ovsdb_idl_txn_add_set_op(row, column, datum, op_type);
    3822                 :            : }
    3823                 :            : 
    3824                 :            : /* Deletes the value specified in 'datum' from the set in 'column' in 'row_'.
    3825                 :            :  * The value in 'datum' must be of the same type as the keys in 'column'.
    3826                 :            :  * This function takes ownership of 'datum'.
    3827                 :            :  *
    3828                 :            :  * Usually this function is used indirectly through one of the "update"
    3829                 :            :  * functions generated by vswitch-idl. */
    3830                 :            : void
    3831                 :         20 : ovsdb_idl_txn_delete_partial_set(const struct ovsdb_idl_row *row_,
    3832                 :            :                                  const struct ovsdb_idl_column *column,
    3833                 :            :                                  struct ovsdb_datum *datum)
    3834                 :            : {
    3835                 :         20 :     struct ovsdb_idl_row *row = CONST_CAST(struct ovsdb_idl_row *, row_);
    3836                 :            : 
    3837         [ -  + ]:         20 :     if (!is_valid_partial_update(row, column, datum)) {
    3838                 :          0 :         struct ovsdb_type type_ = column->type;
    3839                 :          0 :         type_.value.type = OVSDB_TYPE_VOID;
    3840                 :          0 :         ovsdb_datum_destroy(datum, &type_);
    3841                 :          0 :         free(datum);
    3842                 :          0 :         return;
    3843                 :            :     }
    3844                 :         20 :     ovsdb_idl_txn_add_set_op(row, column, datum, SET_OP_DELETE);
    3845                 :            : }
    3846                 :            : 
    3847                 :            : /* Inserts the key-value specified in 'datum' into the map in 'column' in
    3848                 :            :  * 'row_'. If the key already exist in 'column', then it's value is updated
    3849                 :            :  * with the value in 'datum'. The key-value in 'datum' must be of the same type
    3850                 :            :  * as the keys-values in 'column'. This function takes ownership of 'datum'.
    3851                 :            :  *
    3852                 :            :  * Usually this function is used indirectly through one of the "update"
    3853                 :            :  * functions generated by vswitch-idl. */
    3854                 :            : void
    3855                 :          3 : ovsdb_idl_txn_write_partial_map(const struct ovsdb_idl_row *row_,
    3856                 :            :                                 const struct ovsdb_idl_column *column,
    3857                 :            :                                 struct ovsdb_datum *datum)
    3858                 :            : {
    3859                 :          3 :     struct ovsdb_idl_row *row = CONST_CAST(struct ovsdb_idl_row *, row_);
    3860                 :            :     enum ovsdb_atomic_type key_type;
    3861                 :            :     enum map_op_type op_type;
    3862                 :            :     unsigned int pos;
    3863                 :            :     const struct ovsdb_datum *old_datum;
    3864                 :            : 
    3865         [ -  + ]:          3 :     if (!is_valid_partial_update(row, column, datum)) {
    3866                 :          0 :         ovsdb_datum_destroy(datum, &column->type);
    3867                 :          0 :         free(datum);
    3868                 :          0 :         return;
    3869                 :            :     }
    3870                 :            : 
    3871                 :            :     /* Find out if this is an insert or an update. */
    3872                 :          3 :     key_type = column->type.key.type;
    3873                 :          3 :     old_datum = ovsdb_idl_read(row, column);
    3874                 :          3 :     pos = ovsdb_datum_find_key(old_datum, &datum->keys[0], key_type);
    3875                 :          3 :     op_type = pos == UINT_MAX ? MAP_OP_INSERT : MAP_OP_UPDATE;
    3876                 :            : 
    3877                 :          3 :     ovsdb_idl_txn_add_map_op(row, column, datum, op_type);
    3878                 :            : }
    3879                 :            : 
    3880                 :            : /* Deletes the key specified in 'datum' from the map in 'column' in 'row_'.
    3881                 :            :  * The key in 'datum' must be of the same type as the keys in 'column'.
    3882                 :            :  * The value in 'datum' must be NULL. This function takes ownership of
    3883                 :            :  * 'datum'.
    3884                 :            :  *
    3885                 :            :  * Usually this function is used indirectly through one of the "update"
    3886                 :            :  * functions generated by vswitch-idl. */
    3887                 :            : void
    3888                 :          2 : ovsdb_idl_txn_delete_partial_map(const struct ovsdb_idl_row *row_,
    3889                 :            :                                  const struct ovsdb_idl_column *column,
    3890                 :            :                                  struct ovsdb_datum *datum)
    3891                 :            : {
    3892                 :          2 :     struct ovsdb_idl_row *row = CONST_CAST(struct ovsdb_idl_row *, row_);
    3893                 :            : 
    3894         [ -  + ]:          2 :     if (!is_valid_partial_update(row, column, datum)) {
    3895                 :          0 :         struct ovsdb_type type_ = column->type;
    3896                 :          0 :         type_.value.type = OVSDB_TYPE_VOID;
    3897                 :          0 :         ovsdb_datum_destroy(datum, &type_);
    3898                 :          0 :         free(datum);
    3899                 :          0 :         return;
    3900                 :            :     }
    3901                 :          2 :     ovsdb_idl_txn_add_map_op(row, column, datum, MAP_OP_DELETE);
    3902                 :            : }
    3903                 :            : 
    3904                 :            : void
    3905                 :        180 : ovsdb_idl_loop_destroy(struct ovsdb_idl_loop *loop)
    3906                 :            : {
    3907         [ +  - ]:        180 :     if (loop) {
    3908                 :        180 :         ovsdb_idl_destroy(loop->idl);
    3909                 :            :     }
    3910                 :        180 : }
    3911                 :            : 
    3912                 :            : struct ovsdb_idl_txn *
    3913                 :      14310 : ovsdb_idl_loop_run(struct ovsdb_idl_loop *loop)
    3914                 :            : {
    3915                 :      14310 :     ovsdb_idl_run(loop->idl);
    3916                 :      28620 :     loop->open_txn = (loop->committing_txn
    3917         [ +  + ]:      12010 :                       || ovsdb_idl_get_seqno(loop->idl) == loop->skip_seqno
    3918                 :            :                       ? NULL
    3919         [ +  + ]:      26320 :                       : ovsdb_idl_txn_create(loop->idl));
    3920                 :      14310 :     return loop->open_txn;
    3921                 :            : }
    3922                 :            : 
    3923                 :            : void
    3924                 :      14310 : ovsdb_idl_loop_commit_and_wait(struct ovsdb_idl_loop *loop)
    3925                 :            : {
    3926         [ +  + ]:      14310 :     if (loop->open_txn) {
    3927                 :      11804 :         loop->committing_txn = loop->open_txn;
    3928                 :      11804 :         loop->open_txn = NULL;
    3929                 :            : 
    3930                 :      11804 :         loop->precommit_seqno = ovsdb_idl_get_seqno(loop->idl);
    3931                 :            :     }
    3932                 :            : 
    3933                 :      14310 :     struct ovsdb_idl_txn *txn = loop->committing_txn;
    3934         [ +  + ]:      14310 :     if (txn) {
    3935                 :      14104 :         enum ovsdb_idl_txn_status status = ovsdb_idl_txn_commit(txn);
    3936         [ +  + ]:      14104 :         if (status != TXN_INCOMPLETE) {
    3937   [ -  +  +  -  :      11804 :             switch (status) {
                   -  - ]
    3938                 :            :             case TXN_TRY_AGAIN:
    3939                 :            :                 /* We want to re-evaluate the database when it's changed from
    3940                 :            :                  * the contents that it had when we started the commit.  (That
    3941                 :            :                  * might have already happened.) */
    3942                 :          0 :                 loop->skip_seqno = loop->precommit_seqno;
    3943         [ #  # ]:          0 :                 if (ovsdb_idl_get_seqno(loop->idl) != loop->skip_seqno) {
    3944                 :          0 :                     poll_immediate_wake();
    3945                 :            :                 }
    3946                 :          0 :                 break;
    3947                 :            : 
    3948                 :            :             case TXN_SUCCESS:
    3949                 :            :                 /* Possibly some work on the database was deferred because no
    3950                 :            :                  * further transaction could proceed.  Wake up again. */
    3951                 :       1912 :                 loop->cur_cfg = loop->next_cfg;
    3952                 :       1912 :                 poll_immediate_wake();
    3953                 :       1912 :                 break;
    3954                 :            : 
    3955                 :            :             case TXN_UNCHANGED:
    3956                 :       9892 :                 loop->cur_cfg = loop->next_cfg;
    3957                 :       9892 :                 break;
    3958                 :            : 
    3959                 :            :             case TXN_ABORTED:
    3960                 :            :             case TXN_NOT_LOCKED:
    3961                 :            :             case TXN_ERROR:
    3962                 :          0 :                 break;
    3963                 :            : 
    3964                 :            :             case TXN_UNCOMMITTED:
    3965                 :            :             case TXN_INCOMPLETE:
    3966                 :          0 :                 OVS_NOT_REACHED();
    3967                 :            :             }
    3968                 :      11804 :             ovsdb_idl_txn_destroy(txn);
    3969                 :      11804 :             loop->committing_txn = NULL;
    3970                 :            :         }
    3971                 :            :     }
    3972                 :            : 
    3973                 :      14310 :     ovsdb_idl_wait(loop->idl);
    3974                 :      14310 : }

Generated by: LCOV version 1.12