LCOV - code coverage report
Current view: top level - ovsdb - ovsdb.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 167 177 94.4 %
Date: 2016-09-14 01:02:56 Functions: 18 18 100.0 %
Branches: 83 104 79.8 %

           Branch data     Line data    Source code
       1                 :            : /* Copyright (c) 2009, 2010, 2011, 2012, 2013 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.h"
      19                 :            : 
      20                 :            : #include "column.h"
      21                 :            : #include "openvswitch/json.h"
      22                 :            : #include "ovsdb-error.h"
      23                 :            : #include "ovsdb-parser.h"
      24                 :            : #include "ovsdb-types.h"
      25                 :            : #include "simap.h"
      26                 :            : #include "table.h"
      27                 :            : #include "transaction.h"
      28                 :            : 
      29                 :            : struct ovsdb_schema *
      30                 :       3045 : ovsdb_schema_create(const char *name, const char *version, const char *cksum)
      31                 :            : {
      32                 :            :     struct ovsdb_schema *schema;
      33                 :            : 
      34                 :       3045 :     schema = xzalloc(sizeof *schema);
      35                 :       3045 :     schema->name = xstrdup(name);
      36                 :       3045 :     schema->version = xstrdup(version);
      37                 :       3045 :     schema->cksum = xstrdup(cksum);
      38                 :       3045 :     shash_init(&schema->tables);
      39                 :            : 
      40                 :       3045 :     return schema;
      41                 :            : }
      42                 :            : 
      43                 :            : struct ovsdb_schema *
      44                 :          2 : ovsdb_schema_clone(const struct ovsdb_schema *old)
      45                 :            : {
      46                 :            :     struct ovsdb_schema *new;
      47                 :            :     struct shash_node *node;
      48                 :            : 
      49                 :          2 :     new = ovsdb_schema_create(old->name, old->version, old->cksum);
      50 [ +  + ][ -  + ]:          4 :     SHASH_FOR_EACH (node, &old->tables) {
      51                 :          2 :         const struct ovsdb_table_schema *ts = node->data;
      52                 :            : 
      53                 :          2 :         shash_add(&new->tables, node->name, ovsdb_table_schema_clone(ts));
      54                 :            :     }
      55                 :          2 :     return new;
      56                 :            : }
      57                 :            : 
      58                 :            : void
      59                 :       3015 : ovsdb_schema_destroy(struct ovsdb_schema *schema)
      60                 :            : {
      61                 :            :     struct shash_node *node;
      62                 :            : 
      63         [ -  + ]:       3015 :     if (!schema) {
      64                 :          0 :         return;
      65                 :            :     }
      66                 :            : 
      67 [ +  + ][ -  + ]:      18185 :     SHASH_FOR_EACH (node, &schema->tables) {
      68                 :      15170 :         ovsdb_table_schema_destroy(node->data);
      69                 :            :     }
      70                 :       3015 :     shash_destroy(&schema->tables);
      71                 :       3015 :     free(schema->name);
      72                 :       3015 :     free(schema->version);
      73                 :       3015 :     free(schema->cksum);
      74                 :       3015 :     free(schema);
      75                 :            : }
      76                 :            : 
      77                 :            : struct ovsdb_error *
      78                 :       1263 : ovsdb_schema_from_file(const char *file_name, struct ovsdb_schema **schemap)
      79                 :            : {
      80                 :            :     struct ovsdb_schema *schema;
      81                 :            :     struct ovsdb_error *error;
      82                 :            :     struct json *json;
      83                 :            : 
      84                 :       1263 :     *schemap = NULL;
      85                 :       1263 :     json = json_from_file(file_name);
      86         [ -  + ]:       1263 :     if (json->type == JSON_STRING) {
      87                 :          0 :         error = ovsdb_error("failed to read schema",
      88                 :            :                            "\"%s\" could not be read as JSON (%s)",
      89                 :            :                            file_name, json_string(json));
      90                 :          0 :         json_destroy(json);
      91                 :          0 :         return error;
      92                 :            :     }
      93                 :            : 
      94                 :       1263 :     error = ovsdb_schema_from_json(json, &schema);
      95                 :       1263 :     json_destroy(json);
      96         [ -  + ]:       1263 :     if (error) {
      97                 :          0 :         return ovsdb_wrap_error(error,
      98                 :            :                                 "failed to parse \"%s\" as ovsdb schema",
      99                 :            :                                 file_name);
     100                 :            :     }
     101                 :            : 
     102                 :       1263 :     *schemap = schema;
     103                 :       1263 :     return NULL;
     104                 :            : }
     105                 :            : 
     106                 :            : static struct ovsdb_error * OVS_WARN_UNUSED_RESULT
     107                 :     671625 : ovsdb_schema_check_ref_table(struct ovsdb_column *column,
     108                 :            :                              const struct shash *tables,
     109                 :            :                              const struct ovsdb_base_type *base,
     110                 :            :                              const char *base_name)
     111                 :            : {
     112                 :            :     struct ovsdb_table_schema *refTable;
     113                 :            : 
     114 [ +  + ][ +  + ]:     671625 :     if (base->type != OVSDB_TYPE_UUID || !base->u.uuid.refTableName) {
     115                 :     637072 :         return NULL;
     116                 :            :     }
     117                 :            : 
     118                 :      34553 :     refTable = shash_find_data(tables, base->u.uuid.refTableName);
     119         [ +  + ]:      34553 :     if (!refTable) {
     120                 :          1 :         return ovsdb_syntax_error(NULL, NULL,
     121                 :            :                                   "column %s %s refers to undefined table %s",
     122                 :            :                                   column->name, base_name,
     123                 :            :                                   base->u.uuid.refTableName);
     124                 :            :     }
     125                 :            : 
     126 [ +  + ][ +  + ]:      34552 :     if (ovsdb_base_type_is_strong_ref(base) && !refTable->is_root) {
     127                 :            :         /* We cannot allow a strong reference to a non-root table to be
     128                 :            :          * ephemeral: if it is the only reference to a row, then replaying the
     129                 :            :          * database log from disk will cause the referenced row to be deleted,
     130                 :            :          * even though it did exist in memory.  If there are references to that
     131                 :            :          * row later in the log (to modify it, to delete it, or just to point
     132                 :            :          * to it), then this will yield a transaction error. */
     133                 :      22754 :         column->persistent = true;
     134                 :            :     }
     135                 :            : 
     136                 :      34552 :     return NULL;
     137                 :            : }
     138                 :            : 
     139                 :            : static bool
     140                 :       2695 : is_valid_version(const char *s)
     141                 :            : {
     142                 :       2695 :     int n = -1;
     143                 :       2695 :     ignore(ovs_scan(s, "%*[0-9].%*[0-9].%*[0-9]%n", &n));
     144 [ +  + ][ +  - ]:       2695 :     return n != -1 && s[n] == '\0';
     145                 :            : }
     146                 :            : 
     147                 :            : /* Returns the number of tables in 'schema''s root set. */
     148                 :            : static size_t
     149                 :      11492 : root_set_size(const struct ovsdb_schema *schema)
     150                 :            : {
     151                 :            :     struct shash_node *node;
     152                 :      11492 :     size_t n_root = 0;
     153                 :            : 
     154 [ +  + ][ -  + ]:     164459 :     SHASH_FOR_EACH (node, &schema->tables) {
     155                 :     152967 :         struct ovsdb_table_schema *table = node->data;
     156                 :            : 
     157                 :     152967 :         n_root += table->is_root;
     158                 :            :     }
     159                 :      11492 :     return n_root;
     160                 :            : }
     161                 :            : 
     162                 :            : struct ovsdb_error *
     163                 :       3044 : ovsdb_schema_from_json(struct json *json, struct ovsdb_schema **schemap)
     164                 :            : {
     165                 :            :     struct ovsdb_schema *schema;
     166                 :            :     const struct json *name, *tables, *version_json, *cksum;
     167                 :            :     struct ovsdb_error *error;
     168                 :            :     struct shash_node *node;
     169                 :            :     struct ovsdb_parser parser;
     170                 :            :     const char *version;
     171                 :            : 
     172                 :       3044 :     *schemap = NULL;
     173                 :            : 
     174                 :       3044 :     ovsdb_parser_init(&parser, json, "database schema");
     175                 :       3044 :     name = ovsdb_parser_member(&parser, "name", OP_ID);
     176                 :       3044 :     version_json = ovsdb_parser_member(&parser, "version",
     177                 :            :                                        OP_STRING | OP_OPTIONAL);
     178                 :       3044 :     cksum = ovsdb_parser_member(&parser, "cksum", OP_STRING | OP_OPTIONAL);
     179                 :       3044 :     tables = ovsdb_parser_member(&parser, "tables", OP_OBJECT);
     180                 :       3044 :     error = ovsdb_parser_finish(&parser);
     181         [ -  + ]:       3044 :     if (error) {
     182                 :          0 :         return error;
     183                 :            :     }
     184                 :            : 
     185         [ +  + ]:       3044 :     if (version_json) {
     186                 :       2695 :         version = json_string(version_json);
     187         [ +  + ]:       2695 :         if (!is_valid_version(version)) {
     188                 :          1 :             return ovsdb_syntax_error(json, NULL, "schema version \"%s\" not "
     189                 :            :                                       "in format x.y.z", version);
     190                 :            :         }
     191                 :            :     } else {
     192                 :            :         /* Backward compatibility with old databases. */
     193                 :        349 :         version = "";
     194                 :            :     }
     195                 :            : 
     196         [ +  + ]:       3043 :     schema = ovsdb_schema_create(json_string(name), version,
     197                 :            :                                  cksum ? json_string(cksum) : "");
     198 [ +  + ][ -  + ]:      33928 :     SHASH_FOR_EACH (node, json_object(tables)) {
     199                 :            :         struct ovsdb_table_schema *table;
     200                 :            : 
     201         [ -  + ]:      30885 :         if (node->name[0] == '_') {
     202                 :          0 :             error = ovsdb_syntax_error(json, NULL, "names beginning with "
     203                 :            :                                        "\"_\" are reserved");
     204         [ -  + ]:      30885 :         } else if (!ovsdb_parser_is_id(node->name)) {
     205                 :          0 :             error = ovsdb_syntax_error(json, NULL, "name must be a valid id");
     206                 :            :         } else {
     207                 :      30885 :             error = ovsdb_table_schema_from_json(node->data, node->name,
     208                 :            :                                                  &table);
     209                 :            :         }
     210         [ -  + ]:      30885 :         if (error) {
     211                 :          0 :             ovsdb_schema_destroy(schema);
     212                 :          0 :             return error;
     213                 :            :         }
     214                 :            : 
     215                 :      30885 :         shash_add(&schema->tables, table->name, table);
     216                 :            :     }
     217                 :            : 
     218                 :            :     /* "isRoot" was not part of the original schema definition.  Before it was
     219                 :            :      * added, there was no support for garbage collection.  So, for backward
     220                 :            :      * compatibility, if the root set is empty then assume that every table is
     221                 :            :      * in the root set. */
     222         [ +  + ]:       3043 :     if (root_set_size(schema) == 0) {
     223 [ +  + ][ -  + ]:       4654 :         SHASH_FOR_EACH (node, &schema->tables) {
     224                 :       3407 :             struct ovsdb_table_schema *table = node->data;
     225                 :            : 
     226                 :       3407 :             table->is_root = true;
     227                 :            :         }
     228                 :            :     }
     229                 :            : 
     230                 :            :     /* Validate that all refTables refer to the names of tables that exist.
     231                 :            :      *
     232                 :            :      * Also force certain columns to be persistent, as explained in
     233                 :            :      * ovsdb_schema_check_ref_table().  This requires 'is_root' to be known, so
     234                 :            :      * this must follow the loop updating 'is_root' above. */
     235 [ +  + ][ -  + ]:      33926 :     SHASH_FOR_EACH (node, &schema->tables) {
     236                 :      30884 :         struct ovsdb_table_schema *table = node->data;
     237                 :            :         struct shash_node *node2;
     238                 :            : 
     239 [ +  + ][ -  + ]:     366696 :         SHASH_FOR_EACH (node2, &table->columns) {
     240                 :     335813 :             struct ovsdb_column *column = node2->data;
     241                 :            : 
     242                 :     335813 :             error = ovsdb_schema_check_ref_table(column, &schema->tables,
     243                 :     335813 :                                                  &column->type.key, "key");
     244         [ +  + ]:     335813 :             if (!error) {
     245                 :     335812 :                 error = ovsdb_schema_check_ref_table(column, &schema->tables,
     246                 :     335812 :                                                      &column->type.value,
     247                 :            :                                                      "value");
     248                 :            :             }
     249         [ +  + ]:     335813 :             if (error) {
     250                 :          1 :                 ovsdb_schema_destroy(schema);
     251                 :          1 :                 return error;
     252                 :            :             }
     253                 :            :         }
     254                 :            :     }
     255                 :            : 
     256                 :       3042 :     *schemap = schema;
     257                 :       3044 :     return NULL;
     258                 :            : }
     259                 :            : 
     260                 :            : struct json *
     261                 :       8449 : ovsdb_schema_to_json(const struct ovsdb_schema *schema)
     262                 :            : {
     263                 :            :     struct json *json, *tables;
     264                 :            :     struct shash_node *node;
     265                 :            :     bool default_is_root;
     266                 :            : 
     267                 :       8449 :     json = json_object_create();
     268                 :       8449 :     json_object_put_string(json, "name", schema->name);
     269         [ +  + ]:       8449 :     if (schema->version[0]) {
     270                 :       8282 :         json_object_put_string(json, "version", schema->version);
     271                 :            :     }
     272         [ +  + ]:       8449 :     if (schema->cksum[0]) {
     273                 :       8073 :         json_object_put_string(json, "cksum", schema->cksum);
     274                 :            :     }
     275                 :            : 
     276                 :            :     /* "isRoot" was not part of the original schema definition.  Before it was
     277                 :            :      * added, there was no support for garbage collection.  So, for backward
     278                 :            :      * compatibility, if every table is in the root set then do not output
     279                 :            :      * "isRoot" in table schemas. */
     280                 :       8449 :     default_is_root = root_set_size(schema) == shash_count(&schema->tables);
     281                 :            : 
     282                 :       8449 :     tables = json_object_create();
     283                 :            : 
     284 [ +  + ][ -  + ]:     130531 :     SHASH_FOR_EACH (node, &schema->tables) {
     285                 :     122082 :         struct ovsdb_table_schema *table = node->data;
     286                 :     122082 :         json_object_put(tables, table->name,
     287                 :            :                         ovsdb_table_schema_to_json(table, default_is_root));
     288                 :            :     }
     289                 :       8449 :     json_object_put(json, "tables", tables);
     290                 :            : 
     291                 :       8449 :     return json;
     292                 :            : }
     293                 :            : 
     294                 :            : /* Returns true if 'a' and 'b' specify equivalent schemas, false if they
     295                 :            :  * differ. */
     296                 :            : bool
     297                 :         37 : ovsdb_schema_equal(const struct ovsdb_schema *a,
     298                 :            :                    const struct ovsdb_schema *b)
     299                 :            : {
     300                 :            :     /* This implementation is simple, stupid, and slow, but I doubt that it
     301                 :            :      * will ever require much maintenance. */
     302                 :         37 :     struct json *ja = ovsdb_schema_to_json(a);
     303                 :         37 :     struct json *jb = ovsdb_schema_to_json(b);
     304                 :         37 :     bool equals = json_equal(ja, jb);
     305                 :         37 :     json_destroy(ja);
     306                 :         37 :     json_destroy(jb);
     307                 :            : 
     308                 :         37 :     return equals;
     309                 :            : }
     310                 :            : 
     311                 :            : static void
     312                 :     338204 : ovsdb_set_ref_table(const struct shash *tables,
     313                 :            :                     struct ovsdb_base_type *base)
     314                 :            : {
     315 [ +  + ][ +  + ]:     338204 :     if (base->type == OVSDB_TYPE_UUID && base->u.uuid.refTableName) {
     316                 :            :         struct ovsdb_table *table;
     317                 :            : 
     318                 :      17744 :         table = shash_find_data(tables, base->u.uuid.refTableName);
     319                 :      17744 :         base->u.uuid.refTable = table;
     320                 :            :     }
     321                 :     338204 : }
     322                 :            : 
     323                 :            : struct ovsdb *
     324                 :       1567 : ovsdb_create(struct ovsdb_schema *schema)
     325                 :            : {
     326                 :            :     struct shash_node *node;
     327                 :            :     struct ovsdb *db;
     328                 :            : 
     329                 :       1567 :     db = xmalloc(sizeof *db);
     330                 :       1567 :     db->schema = schema;
     331                 :       1567 :     ovs_list_init(&db->replicas);
     332                 :       1567 :     ovs_list_init(&db->triggers);
     333                 :       1567 :     db->run_triggers = false;
     334                 :            : 
     335                 :       1567 :     shash_init(&db->tables);
     336 [ +  + ][ -  + ]:      17255 :     SHASH_FOR_EACH (node, &schema->tables) {
     337                 :      15688 :         struct ovsdb_table_schema *ts = node->data;
     338                 :      15688 :         shash_add(&db->tables, node->name, ovsdb_table_create(ts));
     339                 :            :     }
     340                 :            : 
     341                 :            :     /* Set all the refTables. */
     342 [ +  + ][ -  + ]:      17255 :     SHASH_FOR_EACH (node, &schema->tables) {
     343                 :      15688 :         struct ovsdb_table_schema *table = node->data;
     344                 :            :         struct shash_node *node2;
     345                 :            : 
     346 [ +  + ][ -  + ]:     184790 :         SHASH_FOR_EACH (node2, &table->columns) {
     347                 :     169102 :             struct ovsdb_column *column = node2->data;
     348                 :            : 
     349                 :     169102 :             ovsdb_set_ref_table(&db->tables, &column->type.key);
     350                 :     169102 :             ovsdb_set_ref_table(&db->tables, &column->type.value);
     351                 :            :         }
     352                 :            :     }
     353                 :            : 
     354                 :       1567 :     return db;
     355                 :            : }
     356                 :            : 
     357                 :            : void
     358                 :       1567 : ovsdb_destroy(struct ovsdb *db)
     359                 :            : {
     360         [ +  + ]:       1567 :     if (db) {
     361                 :            :         struct shash_node *node;
     362                 :            : 
     363                 :            :         /* Remove all the replicas. */
     364         [ +  + ]:       3077 :         while (!ovs_list_is_empty(&db->replicas)) {
     365                 :       1512 :             struct ovsdb_replica *r
     366                 :       1512 :                 = CONTAINER_OF(ovs_list_pop_back(&db->replicas),
     367                 :            :                                struct ovsdb_replica, node);
     368                 :       1512 :             ovsdb_remove_replica(db, r);
     369                 :            :         }
     370                 :            : 
     371                 :            :         /* Delete all the tables.  This also deletes their schemas. */
     372 [ +  + ][ -  + ]:      17221 :         SHASH_FOR_EACH (node, &db->tables) {
     373                 :      15656 :             struct ovsdb_table *table = node->data;
     374                 :      15656 :             ovsdb_table_destroy(table);
     375                 :            :         }
     376                 :       1565 :         shash_destroy(&db->tables);
     377                 :            : 
     378                 :            :         /* The schemas, but not the table that points to them, were deleted in
     379                 :            :          * the previous step, so we need to clear out the table.  We can't
     380                 :            :          * destroy the table, because ovsdb_schema_destroy() will do that. */
     381                 :       1565 :         shash_clear(&db->schema->tables);
     382                 :            : 
     383                 :       1565 :         ovsdb_schema_destroy(db->schema);
     384                 :       1565 :         free(db);
     385                 :            :     }
     386                 :       1567 : }
     387                 :            : 
     388                 :            : /* Adds some memory usage statistics for 'db' into 'usage', for use with
     389                 :            :  * memory_report(). */
     390                 :            : void
     391                 :         75 : ovsdb_get_memory_usage(const struct ovsdb *db, struct simap *usage)
     392                 :            : {
     393                 :            :     const struct shash_node *node;
     394                 :         75 :     unsigned int cells = 0;
     395                 :            : 
     396 [ +  + ][ -  + ]:       1191 :     SHASH_FOR_EACH (node, &db->tables) {
     397                 :       1116 :         const struct ovsdb_table *table = node->data;
     398                 :       1116 :         unsigned int n_columns = shash_count(&table->schema->columns);
     399                 :       1116 :         unsigned int n_rows = hmap_count(&table->rows);
     400                 :            : 
     401                 :       1116 :         cells += n_rows * n_columns;
     402                 :            :     }
     403                 :            : 
     404                 :         75 :     simap_increase(usage, "cells", cells);
     405                 :         75 : }
     406                 :            : 
     407                 :            : struct ovsdb_table *
     408                 :      44508 : ovsdb_get_table(const struct ovsdb *db, const char *name)
     409                 :            : {
     410                 :      44508 :     return shash_find_data(&db->tables, name);
     411                 :            : }
     412                 :            : 
     413                 :            : void
     414                 :       8654 : ovsdb_replica_init(struct ovsdb_replica *r,
     415                 :            :                    const struct ovsdb_replica_class *class)
     416                 :            : {
     417                 :       8654 :     r->class = class;
     418                 :       8654 : }
     419                 :            : 
     420                 :            : void
     421                 :       8654 : ovsdb_add_replica(struct ovsdb *db, struct ovsdb_replica *r)
     422                 :            : {
     423                 :       8654 :     ovs_list_push_back(&db->replicas, &r->node);
     424                 :       8654 : }
     425                 :            : 
     426                 :            : void
     427                 :       1512 : ovsdb_remove_replica(struct ovsdb *db OVS_UNUSED, struct ovsdb_replica *r)
     428                 :            : {
     429                 :       1512 :     ovs_list_remove(&r->node);
     430                 :       1512 :     (r->class->destroy)(r);
     431                 :       1512 : }

Generated by: LCOV version 1.12