2015-03-11 21:20:44 -07:00
|
|
|
/*
|
2017-05-26 20:48:45 -07:00
|
|
|
* Copyright (c) 2015, 2017 Nicira, Inc.
|
2015-03-11 21:20:44 -07:00
|
|
|
*
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
* You may obtain a copy of the License at:
|
|
|
|
*
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
*
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
* limitations under the License.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
|
|
|
#include <errno.h>
|
|
|
|
|
|
|
|
#include "bitmap.h"
|
|
|
|
#include "column.h"
|
2016-03-03 10:20:46 -08:00
|
|
|
#include "openvswitch/dynamic-string.h"
|
2016-07-12 16:37:34 -05:00
|
|
|
#include "openvswitch/json.h"
|
2015-03-11 21:20:44 -07:00
|
|
|
#include "jsonrpc.h"
|
|
|
|
#include "ovsdb-error.h"
|
|
|
|
#include "ovsdb-parser.h"
|
|
|
|
#include "ovsdb.h"
|
|
|
|
#include "row.h"
|
2016-07-18 11:45:52 +03:00
|
|
|
#include "condition.h"
|
2015-03-11 21:20:44 -07:00
|
|
|
#include "simap.h"
|
2015-03-14 00:40:18 -07:00
|
|
|
#include "hash.h"
|
2015-03-11 21:20:44 -07:00
|
|
|
#include "table.h"
|
2015-03-16 03:03:20 -07:00
|
|
|
#include "hash.h"
|
2015-03-11 21:20:44 -07:00
|
|
|
#include "timeval.h"
|
|
|
|
#include "transaction.h"
|
|
|
|
#include "jsonrpc-server.h"
|
|
|
|
#include "monitor.h"
|
2016-07-12 16:37:34 -05:00
|
|
|
#include "util.h"
|
2015-03-11 21:20:44 -07:00
|
|
|
#include "openvswitch/vlog.h"
|
|
|
|
|
2016-07-18 11:45:52 +03:00
|
|
|
VLOG_DEFINE_THIS_MODULE(ovsdb_monitor);
|
2015-03-11 21:20:44 -07:00
|
|
|
|
|
|
|
static const struct ovsdb_replica_class ovsdb_jsonrpc_replica_class;
|
2015-03-16 03:03:20 -07:00
|
|
|
static struct hmap ovsdb_monitors = HMAP_INITIALIZER(&ovsdb_monitors);
|
2015-03-11 21:20:44 -07:00
|
|
|
|
2016-07-18 11:45:52 +03:00
|
|
|
/* Keep state of session's conditions */
|
|
|
|
struct ovsdb_monitor_session_condition {
|
|
|
|
bool conditional;
|
|
|
|
size_t n_true_cnd;
|
|
|
|
struct shash tables; /* Contains
|
|
|
|
* "struct ovsdb_monitor_table_condition *"s. */
|
|
|
|
};
|
|
|
|
|
|
|
|
/* Monitored table session's conditions */
|
|
|
|
struct ovsdb_monitor_table_condition {
|
|
|
|
const struct ovsdb_table *table;
|
|
|
|
struct ovsdb_monitor_table *mt;
|
|
|
|
struct ovsdb_condition old_condition;
|
|
|
|
struct ovsdb_condition new_condition;
|
|
|
|
};
|
|
|
|
|
2015-03-11 21:20:44 -07:00
|
|
|
/* Backend monitor.
|
|
|
|
*
|
|
|
|
* ovsdb_monitor keep track of the ovsdb changes.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* A collection of tables being monitored. */
|
|
|
|
struct ovsdb_monitor {
|
|
|
|
struct ovsdb_replica replica;
|
|
|
|
struct shash tables; /* Holds "struct ovsdb_monitor_table"s. */
|
2015-04-09 16:39:58 -07:00
|
|
|
struct ovs_list jsonrpc_monitors; /* Contains "jsonrpc_monitor_node"s. */
|
2015-03-11 21:20:44 -07:00
|
|
|
struct ovsdb *db;
|
ovsdb-monitor: add transaction ids
With N:1 mappings, multiple jsonrpc server may be servicing the rpc
connection at a different pace. ovsdb-monitor thus needs to maintain
different change sets, depends on connection speed of each rpc
connections. Connections servicing at the same speed can share the
same change set.
Transaction ID is an concept added to describe the change set. One
possible view of the database state is a sequence of changes, more
precisely, commits be applied to it in order, starting from an
initial state, with commit 0. The logic can also be applied to the
jsonrpc monitor; each change it pushes corresponds to commits between
two transaction IDs.
This patch introduces transaction IDs. For ovsdb-monitor, it maintains
n_transactions, starting from 0. Each commit add 1 to the number.
Jsonrpc maintains and 'unflushed' transaction number, corresponding to
the next commit the remote has not seen. jsonrpc's job is simply to
notice there are changes in the ovsdb-monitor that it is interested in,
i.e. 'n_transactions' >= 'unflushed', get the changes in json format,
and push them to the remote site.
Signed-off-by: Andy Zhou <azhou@nicira.com>
Acked-by: Ben Pfaff <blp@nicira.com>
2015-03-12 23:15:56 -07:00
|
|
|
uint64_t n_transactions; /* Count number of committed transactions. */
|
2015-03-16 03:03:20 -07:00
|
|
|
struct hmap_node hmap_node; /* Elements within ovsdb_monitors. */
|
2015-03-16 15:45:27 -07:00
|
|
|
struct hmap json_cache; /* Contains "ovsdb_monitor_json_cache_node"s.*/
|
|
|
|
};
|
|
|
|
|
|
|
|
/* A json object of updates between 'from_txn' and 'dbmon->n_transactions'
|
|
|
|
* inclusive. */
|
|
|
|
struct ovsdb_monitor_json_cache_node {
|
|
|
|
struct hmap_node hmap_node; /* Elements in json cache. */
|
2015-12-17 22:23:22 -08:00
|
|
|
enum ovsdb_monitor_version version;
|
2015-03-16 15:45:27 -07:00
|
|
|
uint64_t from_txn;
|
|
|
|
struct json *json; /* Null, or a cloned of json */
|
2015-03-11 21:20:44 -07:00
|
|
|
};
|
|
|
|
|
2015-04-09 16:39:58 -07:00
|
|
|
struct jsonrpc_monitor_node {
|
|
|
|
struct ovs_list node;
|
2016-09-09 13:48:52 -07:00
|
|
|
struct ovsdb_jsonrpc_monitor *jsonrpc_monitor;
|
2015-04-09 16:39:58 -07:00
|
|
|
};
|
|
|
|
|
2015-03-11 21:20:44 -07:00
|
|
|
/* A particular column being monitored. */
|
|
|
|
struct ovsdb_monitor_column {
|
|
|
|
const struct ovsdb_column *column;
|
|
|
|
enum ovsdb_monitor_selection select;
|
2016-07-18 11:45:51 +03:00
|
|
|
bool monitored;
|
2015-03-11 21:20:44 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
/* A row that has changed in a monitored table. */
|
|
|
|
struct ovsdb_monitor_row {
|
|
|
|
struct hmap_node hmap_node; /* In ovsdb_jsonrpc_monitor_table.changes. */
|
|
|
|
struct uuid uuid; /* UUID of row that changed. */
|
|
|
|
struct ovsdb_datum *old; /* Old data, NULL for an inserted row. */
|
|
|
|
struct ovsdb_datum *new; /* New data, NULL for a deleted row. */
|
|
|
|
};
|
|
|
|
|
2015-03-13 16:35:49 -07:00
|
|
|
/* Contains 'struct ovsdb_monitor_row's for rows that have been
|
|
|
|
* updated but not yet flushed to all the jsonrpc connection.
|
|
|
|
*
|
|
|
|
* 'n_refs' represent the number of jsonrpc connections that have
|
|
|
|
* not received updates. Generate the update for the last jsonprc
|
|
|
|
* connection will also destroy the whole "struct ovsdb_monitor_changes"
|
|
|
|
* object.
|
|
|
|
*
|
|
|
|
* 'transaction' stores the first update's transaction id.
|
|
|
|
* */
|
|
|
|
struct ovsdb_monitor_changes {
|
2016-09-09 13:48:52 -07:00
|
|
|
struct hmap_node hmap_node; /* Element in ovsdb_monitor_tables' changes
|
|
|
|
hmap. */
|
2015-03-13 16:35:49 -07:00
|
|
|
struct ovsdb_monitor_table *mt;
|
|
|
|
struct hmap rows;
|
|
|
|
int n_refs;
|
|
|
|
uint64_t transaction;
|
|
|
|
};
|
|
|
|
|
2015-03-11 21:20:44 -07:00
|
|
|
/* A particular table being monitored. */
|
|
|
|
struct ovsdb_monitor_table {
|
|
|
|
const struct ovsdb_table *table;
|
|
|
|
|
|
|
|
/* This is the union (bitwise-OR) of the 'select' values in all of the
|
|
|
|
* members of 'columns' below. */
|
|
|
|
enum ovsdb_monitor_selection select;
|
|
|
|
|
|
|
|
/* Columns being monitored. */
|
|
|
|
struct ovsdb_monitor_column *columns;
|
|
|
|
size_t n_columns;
|
2016-07-18 11:45:51 +03:00
|
|
|
size_t n_monitored_columns;
|
|
|
|
size_t allocated_columns;
|
2015-03-11 21:20:44 -07:00
|
|
|
|
2016-07-18 11:45:49 +03:00
|
|
|
/* Columns in ovsdb_monitor_row have different indexes then in
|
|
|
|
* ovsdb_row. This field maps between column->index to the index in the
|
|
|
|
* ovsdb_monitor_row. It is used for condition evaluation. */
|
|
|
|
unsigned int *columns_index_map;
|
|
|
|
|
2015-03-14 00:40:18 -07:00
|
|
|
/* Contains 'ovsdb_monitor_changes' indexed by 'transaction'. */
|
|
|
|
struct hmap changes;
|
2015-03-11 21:20:44 -07:00
|
|
|
};
|
|
|
|
|
2016-07-18 11:45:53 +03:00
|
|
|
enum ovsdb_monitor_row_type {
|
|
|
|
OVSDB_ROW,
|
|
|
|
OVSDB_MONITOR_ROW
|
|
|
|
};
|
|
|
|
|
2015-10-15 14:07:43 -07:00
|
|
|
typedef struct json *
|
2016-07-18 11:45:52 +03:00
|
|
|
(*compose_row_update_cb_func)
|
|
|
|
(const struct ovsdb_monitor_table *mt,
|
|
|
|
const struct ovsdb_monitor_session_condition * condition,
|
2016-07-18 11:45:53 +03:00
|
|
|
enum ovsdb_monitor_row_type row_type,
|
|
|
|
const void *,
|
2016-07-18 11:45:52 +03:00
|
|
|
bool initial, unsigned long int *changed);
|
2015-10-15 14:07:43 -07:00
|
|
|
|
2015-04-09 16:39:58 -07:00
|
|
|
static void ovsdb_monitor_destroy(struct ovsdb_monitor *dbmon);
|
2015-03-16 03:03:20 -07:00
|
|
|
static struct ovsdb_monitor_changes * ovsdb_monitor_table_add_changes(
|
|
|
|
struct ovsdb_monitor_table *mt, uint64_t next_txn);
|
2015-03-14 00:40:18 -07:00
|
|
|
static struct ovsdb_monitor_changes *ovsdb_monitor_table_find_changes(
|
|
|
|
struct ovsdb_monitor_table *mt, uint64_t unflushed);
|
2015-03-13 16:35:49 -07:00
|
|
|
static void ovsdb_monitor_changes_destroy(
|
|
|
|
struct ovsdb_monitor_changes *changes);
|
|
|
|
static void ovsdb_monitor_table_track_changes(struct ovsdb_monitor_table *mt,
|
2015-03-14 00:40:18 -07:00
|
|
|
uint64_t unflushed);
|
2015-04-09 16:39:58 -07:00
|
|
|
|
2015-12-17 22:23:22 -08:00
|
|
|
static uint32_t
|
|
|
|
json_cache_hash(enum ovsdb_monitor_version version, uint64_t from_txn)
|
|
|
|
{
|
|
|
|
uint32_t hash;
|
|
|
|
|
|
|
|
hash = hash_uint64(version);
|
|
|
|
hash = hash_uint64_basis(from_txn, hash);
|
|
|
|
|
|
|
|
return hash;
|
|
|
|
}
|
|
|
|
|
2015-03-16 15:45:27 -07:00
|
|
|
static struct ovsdb_monitor_json_cache_node *
|
|
|
|
ovsdb_monitor_json_cache_search(const struct ovsdb_monitor *dbmon,
|
2015-12-17 22:23:22 -08:00
|
|
|
enum ovsdb_monitor_version version,
|
2015-03-16 15:45:27 -07:00
|
|
|
uint64_t from_txn)
|
|
|
|
{
|
|
|
|
struct ovsdb_monitor_json_cache_node *node;
|
2015-12-17 22:23:22 -08:00
|
|
|
uint32_t hash = json_cache_hash(version, from_txn);
|
2015-03-16 15:45:27 -07:00
|
|
|
|
|
|
|
HMAP_FOR_EACH_WITH_HASH(node, hmap_node, hash, &dbmon->json_cache) {
|
2015-12-17 22:23:22 -08:00
|
|
|
if (node->from_txn == from_txn && node->version == version) {
|
2015-03-16 15:45:27 -07:00
|
|
|
return node;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
ovsdb_monitor_json_cache_insert(struct ovsdb_monitor *dbmon,
|
2015-12-17 22:23:22 -08:00
|
|
|
enum ovsdb_monitor_version version,
|
2015-03-16 15:45:27 -07:00
|
|
|
uint64_t from_txn, struct json *json)
|
|
|
|
{
|
|
|
|
struct ovsdb_monitor_json_cache_node *node;
|
2015-12-17 22:23:22 -08:00
|
|
|
uint32_t hash = json_cache_hash(version, from_txn);
|
2015-03-16 15:45:27 -07:00
|
|
|
|
|
|
|
node = xmalloc(sizeof *node);
|
|
|
|
|
2015-12-17 22:23:22 -08:00
|
|
|
node->version = version;
|
2015-03-16 15:45:27 -07:00
|
|
|
node->from_txn = from_txn;
|
|
|
|
node->json = json ? json_clone(json) : NULL;
|
|
|
|
|
|
|
|
hmap_insert(&dbmon->json_cache, &node->hmap_node, hash);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
ovsdb_monitor_json_cache_flush(struct ovsdb_monitor *dbmon)
|
|
|
|
{
|
2016-04-06 18:53:59 -07:00
|
|
|
struct ovsdb_monitor_json_cache_node *node;
|
2015-03-16 15:45:27 -07:00
|
|
|
|
2016-04-06 18:53:59 -07:00
|
|
|
HMAP_FOR_EACH_POP(node, hmap_node, &dbmon->json_cache) {
|
2015-03-16 15:45:27 -07:00
|
|
|
json_destroy(node->json);
|
|
|
|
free(node);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-11 21:20:44 -07:00
|
|
|
static int
|
|
|
|
compare_ovsdb_monitor_column(const void *a_, const void *b_)
|
|
|
|
{
|
|
|
|
const struct ovsdb_monitor_column *a = a_;
|
|
|
|
const struct ovsdb_monitor_column *b = b_;
|
|
|
|
|
2016-07-18 11:45:51 +03:00
|
|
|
/* put all monitored columns at the begining */
|
|
|
|
if (a->monitored != b->monitored) {
|
|
|
|
return a->monitored ? -1 : 1;
|
|
|
|
}
|
|
|
|
|
2015-03-11 21:20:44 -07:00
|
|
|
return a->column < b->column ? -1 : a->column > b->column;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct ovsdb_monitor *
|
|
|
|
ovsdb_monitor_cast(struct ovsdb_replica *replica)
|
|
|
|
{
|
|
|
|
ovs_assert(replica->class == &ovsdb_jsonrpc_replica_class);
|
|
|
|
return CONTAINER_OF(replica, struct ovsdb_monitor, replica);
|
|
|
|
}
|
|
|
|
|
2015-03-13 16:35:49 -07:00
|
|
|
/* Finds and returns the ovsdb_monitor_row in 'mt->changes->rows' for the
|
2015-03-11 21:20:44 -07:00
|
|
|
* given 'uuid', or NULL if there is no such row. */
|
|
|
|
static struct ovsdb_monitor_row *
|
2015-03-14 00:40:18 -07:00
|
|
|
ovsdb_monitor_changes_row_find(const struct ovsdb_monitor_changes *changes,
|
|
|
|
const struct uuid *uuid)
|
2015-03-11 21:20:44 -07:00
|
|
|
{
|
|
|
|
struct ovsdb_monitor_row *row;
|
|
|
|
|
2015-03-13 16:35:49 -07:00
|
|
|
HMAP_FOR_EACH_WITH_HASH (row, hmap_node, uuid_hash(uuid),
|
2015-03-14 00:40:18 -07:00
|
|
|
&changes->rows) {
|
2015-03-11 21:20:44 -07:00
|
|
|
if (uuid_equals(uuid, &row->uuid)) {
|
|
|
|
return row;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Allocates an array of 'mt->n_columns' ovsdb_datums and initializes them as
|
|
|
|
* copies of the data in 'row' drawn from the columns represented by
|
|
|
|
* mt->columns[]. Returns the array.
|
|
|
|
*
|
|
|
|
* If 'row' is NULL, returns NULL. */
|
|
|
|
static struct ovsdb_datum *
|
|
|
|
clone_monitor_row_data(const struct ovsdb_monitor_table *mt,
|
|
|
|
const struct ovsdb_row *row)
|
|
|
|
{
|
|
|
|
struct ovsdb_datum *data;
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
if (!row) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
data = xmalloc(mt->n_columns * sizeof *data);
|
|
|
|
for (i = 0; i < mt->n_columns; i++) {
|
|
|
|
const struct ovsdb_column *c = mt->columns[i].column;
|
|
|
|
const struct ovsdb_datum *src = &row->fields[c->index];
|
|
|
|
struct ovsdb_datum *dst = &data[i];
|
|
|
|
const struct ovsdb_type *type = &c->type;
|
|
|
|
|
|
|
|
ovsdb_datum_clone(dst, src, type);
|
|
|
|
}
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Replaces the mt->n_columns ovsdb_datums in row[] by copies of the data from
|
|
|
|
* in 'row' drawn from the columns represented by mt->columns[]. */
|
|
|
|
static void
|
|
|
|
update_monitor_row_data(const struct ovsdb_monitor_table *mt,
|
|
|
|
const struct ovsdb_row *row,
|
|
|
|
struct ovsdb_datum *data)
|
|
|
|
{
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
for (i = 0; i < mt->n_columns; i++) {
|
|
|
|
const struct ovsdb_column *c = mt->columns[i].column;
|
|
|
|
const struct ovsdb_datum *src = &row->fields[c->index];
|
|
|
|
struct ovsdb_datum *dst = &data[i];
|
|
|
|
const struct ovsdb_type *type = &c->type;
|
|
|
|
|
|
|
|
if (!ovsdb_datum_equals(src, dst, type)) {
|
|
|
|
ovsdb_datum_destroy(dst, type);
|
|
|
|
ovsdb_datum_clone(dst, src, type);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Frees all of the mt->n_columns ovsdb_datums in data[], using the types taken
|
|
|
|
* from mt->columns[], plus 'data' itself. */
|
|
|
|
static void
|
|
|
|
free_monitor_row_data(const struct ovsdb_monitor_table *mt,
|
|
|
|
struct ovsdb_datum *data)
|
|
|
|
{
|
|
|
|
if (data) {
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
for (i = 0; i < mt->n_columns; i++) {
|
|
|
|
const struct ovsdb_column *c = mt->columns[i].column;
|
|
|
|
|
|
|
|
ovsdb_datum_destroy(&data[i], &c->type);
|
|
|
|
}
|
|
|
|
free(data);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Frees 'row', which must have been created from 'mt'. */
|
|
|
|
static void
|
|
|
|
ovsdb_monitor_row_destroy(const struct ovsdb_monitor_table *mt,
|
|
|
|
struct ovsdb_monitor_row *row)
|
|
|
|
{
|
|
|
|
if (row) {
|
|
|
|
free_monitor_row_data(mt, row->old);
|
|
|
|
free_monitor_row_data(mt, row->new);
|
|
|
|
free(row);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-18 11:45:49 +03:00
|
|
|
static void
|
|
|
|
ovsdb_monitor_columns_sort(struct ovsdb_monitor *dbmon)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
struct shash_node *node;
|
|
|
|
|
|
|
|
SHASH_FOR_EACH (node, &dbmon->tables) {
|
|
|
|
struct ovsdb_monitor_table *mt = node->data;
|
|
|
|
|
|
|
|
qsort(mt->columns, mt->n_columns, sizeof *mt->columns,
|
|
|
|
compare_ovsdb_monitor_column);
|
|
|
|
for (i = 0; i < mt->n_columns; i++) {
|
|
|
|
/* re-set index map due to sort */
|
|
|
|
mt->columns_index_map[mt->columns[i].column->index] = i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-16 03:03:20 -07:00
|
|
|
void
|
2015-03-15 16:31:41 -07:00
|
|
|
ovsdb_monitor_add_jsonrpc_monitor(struct ovsdb_monitor *dbmon,
|
|
|
|
struct ovsdb_jsonrpc_monitor *jsonrpc_monitor)
|
|
|
|
{
|
|
|
|
struct jsonrpc_monitor_node *jm;
|
|
|
|
|
|
|
|
jm = xzalloc(sizeof *jm);
|
|
|
|
jm->jsonrpc_monitor = jsonrpc_monitor;
|
2016-03-25 14:10:22 -07:00
|
|
|
ovs_list_push_back(&dbmon->jsonrpc_monitors, &jm->node);
|
2015-03-15 16:31:41 -07:00
|
|
|
}
|
|
|
|
|
2015-03-11 21:20:44 -07:00
|
|
|
struct ovsdb_monitor *
|
|
|
|
ovsdb_monitor_create(struct ovsdb *db,
|
|
|
|
struct ovsdb_jsonrpc_monitor *jsonrpc_monitor)
|
|
|
|
{
|
|
|
|
struct ovsdb_monitor *dbmon;
|
|
|
|
|
|
|
|
dbmon = xzalloc(sizeof *dbmon);
|
|
|
|
|
|
|
|
ovsdb_replica_init(&dbmon->replica, &ovsdb_jsonrpc_replica_class);
|
|
|
|
ovsdb_add_replica(db, &dbmon->replica);
|
2016-03-25 14:10:22 -07:00
|
|
|
ovs_list_init(&dbmon->jsonrpc_monitors);
|
2015-03-11 21:20:44 -07:00
|
|
|
dbmon->db = db;
|
ovsdb-monitor: add transaction ids
With N:1 mappings, multiple jsonrpc server may be servicing the rpc
connection at a different pace. ovsdb-monitor thus needs to maintain
different change sets, depends on connection speed of each rpc
connections. Connections servicing at the same speed can share the
same change set.
Transaction ID is an concept added to describe the change set. One
possible view of the database state is a sequence of changes, more
precisely, commits be applied to it in order, starting from an
initial state, with commit 0. The logic can also be applied to the
jsonrpc monitor; each change it pushes corresponds to commits between
two transaction IDs.
This patch introduces transaction IDs. For ovsdb-monitor, it maintains
n_transactions, starting from 0. Each commit add 1 to the number.
Jsonrpc maintains and 'unflushed' transaction number, corresponding to
the next commit the remote has not seen. jsonrpc's job is simply to
notice there are changes in the ovsdb-monitor that it is interested in,
i.e. 'n_transactions' >= 'unflushed', get the changes in json format,
and push them to the remote site.
Signed-off-by: Andy Zhou <azhou@nicira.com>
Acked-by: Ben Pfaff <blp@nicira.com>
2015-03-12 23:15:56 -07:00
|
|
|
dbmon->n_transactions = 0;
|
2015-03-11 21:20:44 -07:00
|
|
|
shash_init(&dbmon->tables);
|
2015-03-16 03:03:20 -07:00
|
|
|
hmap_node_nullify(&dbmon->hmap_node);
|
2015-03-16 15:45:27 -07:00
|
|
|
hmap_init(&dbmon->json_cache);
|
2015-03-11 21:20:44 -07:00
|
|
|
|
2015-03-15 16:31:41 -07:00
|
|
|
ovsdb_monitor_add_jsonrpc_monitor(dbmon, jsonrpc_monitor);
|
2015-03-11 21:20:44 -07:00
|
|
|
return dbmon;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ovsdb_monitor_add_table(struct ovsdb_monitor *m,
|
|
|
|
const struct ovsdb_table *table)
|
|
|
|
{
|
|
|
|
struct ovsdb_monitor_table *mt;
|
2016-07-18 11:45:49 +03:00
|
|
|
int i;
|
|
|
|
size_t n_columns = shash_count(&table->schema->columns);
|
2015-03-11 21:20:44 -07:00
|
|
|
|
|
|
|
mt = xzalloc(sizeof *mt);
|
|
|
|
mt->table = table;
|
|
|
|
shash_add(&m->tables, table->schema->name, mt);
|
2015-03-14 00:40:18 -07:00
|
|
|
hmap_init(&mt->changes);
|
2016-07-18 11:45:49 +03:00
|
|
|
mt->columns_index_map =
|
|
|
|
xmalloc(sizeof *mt->columns_index_map * n_columns);
|
|
|
|
for (i = 0; i < n_columns; i++) {
|
|
|
|
mt->columns_index_map[i] = -1;
|
|
|
|
}
|
2015-03-11 21:20:44 -07:00
|
|
|
}
|
|
|
|
|
2016-07-18 11:45:49 +03:00
|
|
|
const char *
|
2015-03-11 21:20:44 -07:00
|
|
|
ovsdb_monitor_add_column(struct ovsdb_monitor *dbmon,
|
|
|
|
const struct ovsdb_table *table,
|
|
|
|
const struct ovsdb_column *column,
|
|
|
|
enum ovsdb_monitor_selection select,
|
2016-07-18 11:45:51 +03:00
|
|
|
bool monitored)
|
2015-03-11 21:20:44 -07:00
|
|
|
{
|
|
|
|
struct ovsdb_monitor_table *mt;
|
|
|
|
struct ovsdb_monitor_column *c;
|
|
|
|
|
|
|
|
mt = shash_find_data(&dbmon->tables, table->schema->name);
|
|
|
|
|
2016-07-18 11:45:49 +03:00
|
|
|
/* Check for column duplication. Return duplicated column name. */
|
|
|
|
if (mt->columns_index_map[column->index] != -1) {
|
|
|
|
return column->name;
|
|
|
|
}
|
|
|
|
|
2016-07-18 11:45:51 +03:00
|
|
|
if (mt->n_columns >= mt->allocated_columns) {
|
|
|
|
mt->columns = x2nrealloc(mt->columns, &mt->allocated_columns,
|
2015-03-11 21:20:44 -07:00
|
|
|
sizeof *mt->columns);
|
|
|
|
}
|
|
|
|
|
|
|
|
mt->select |= select;
|
2016-07-18 11:45:49 +03:00
|
|
|
mt->columns_index_map[column->index] = mt->n_columns;
|
2015-03-11 21:20:44 -07:00
|
|
|
c = &mt->columns[mt->n_columns++];
|
|
|
|
c->column = column;
|
|
|
|
c->select = select;
|
2016-07-18 11:45:51 +03:00
|
|
|
c->monitored = monitored;
|
|
|
|
if (monitored) {
|
|
|
|
mt->n_monitored_columns++;
|
|
|
|
}
|
2015-03-11 21:20:44 -07:00
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2016-07-18 11:45:52 +03:00
|
|
|
static void
|
|
|
|
ovsdb_monitor_condition_add_columns(struct ovsdb_monitor *dbmon,
|
|
|
|
const struct ovsdb_table *table,
|
|
|
|
struct ovsdb_condition *condition)
|
|
|
|
{
|
|
|
|
size_t n_columns;
|
|
|
|
int i;
|
|
|
|
const struct ovsdb_column **columns =
|
|
|
|
ovsdb_condition_get_columns(condition, &n_columns);
|
|
|
|
|
|
|
|
for (i = 0; i < n_columns; i++) {
|
|
|
|
ovsdb_monitor_add_column(dbmon, table, columns[i],
|
|
|
|
OJMS_NONE, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
free(columns);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Bind this session's condition to ovsdb_monitor */
|
|
|
|
void
|
|
|
|
ovsdb_monitor_condition_bind(struct ovsdb_monitor *dbmon,
|
|
|
|
struct ovsdb_monitor_session_condition *cond)
|
|
|
|
{
|
|
|
|
struct shash_node *node;
|
|
|
|
|
|
|
|
SHASH_FOR_EACH(node, &cond->tables) {
|
|
|
|
struct ovsdb_monitor_table_condition *mtc = node->data;
|
|
|
|
struct ovsdb_monitor_table *mt =
|
|
|
|
shash_find_data(&dbmon->tables, mtc->table->schema->name);
|
|
|
|
|
|
|
|
mtc->mt = mt;
|
|
|
|
ovsdb_monitor_condition_add_columns(dbmon, mtc->table,
|
|
|
|
&mtc->new_condition);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-18 11:45:53 +03:00
|
|
|
bool
|
|
|
|
ovsdb_monitor_table_exists(struct ovsdb_monitor *m,
|
|
|
|
const struct ovsdb_table *table)
|
|
|
|
{
|
|
|
|
return shash_find_data(&m->tables, table->schema->name);
|
|
|
|
}
|
|
|
|
|
2015-03-16 03:03:20 -07:00
|
|
|
static struct ovsdb_monitor_changes *
|
2015-03-13 16:35:49 -07:00
|
|
|
ovsdb_monitor_table_add_changes(struct ovsdb_monitor_table *mt,
|
|
|
|
uint64_t next_txn)
|
|
|
|
{
|
|
|
|
struct ovsdb_monitor_changes *changes;
|
|
|
|
|
|
|
|
changes = xzalloc(sizeof *changes);
|
|
|
|
|
|
|
|
changes->transaction = next_txn;
|
|
|
|
changes->mt = mt;
|
|
|
|
changes->n_refs = 1;
|
|
|
|
hmap_init(&changes->rows);
|
2015-03-14 00:40:18 -07:00
|
|
|
hmap_insert(&mt->changes, &changes->hmap_node, hash_uint64(next_txn));
|
2015-03-16 03:03:20 -07:00
|
|
|
|
|
|
|
return changes;
|
2015-03-14 00:40:18 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
static struct ovsdb_monitor_changes *
|
|
|
|
ovsdb_monitor_table_find_changes(struct ovsdb_monitor_table *mt,
|
|
|
|
uint64_t transaction)
|
|
|
|
{
|
|
|
|
struct ovsdb_monitor_changes *changes;
|
|
|
|
size_t hash = hash_uint64(transaction);
|
|
|
|
|
|
|
|
HMAP_FOR_EACH_WITH_HASH(changes, hmap_node, hash, &mt->changes) {
|
|
|
|
if (changes->transaction == transaction) {
|
|
|
|
return changes;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
2015-03-13 16:35:49 -07:00
|
|
|
}
|
|
|
|
|
2015-10-22 00:10:53 -07:00
|
|
|
/* Stop currently tracking changes to table 'mt' since 'transaction'. */
|
2015-03-13 16:35:49 -07:00
|
|
|
static void
|
|
|
|
ovsdb_monitor_table_untrack_changes(struct ovsdb_monitor_table *mt,
|
|
|
|
uint64_t transaction)
|
|
|
|
{
|
2015-03-14 00:40:18 -07:00
|
|
|
struct ovsdb_monitor_changes *changes =
|
|
|
|
ovsdb_monitor_table_find_changes(mt, transaction);
|
2015-03-13 16:35:49 -07:00
|
|
|
if (changes) {
|
|
|
|
if (--changes->n_refs == 0) {
|
2015-03-14 00:40:18 -07:00
|
|
|
hmap_remove(&mt->changes, &changes->hmap_node);
|
2015-03-13 16:35:49 -07:00
|
|
|
ovsdb_monitor_changes_destroy(changes);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Start tracking changes to table 'mt' begins from 'transaction' inclusive.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
ovsdb_monitor_table_track_changes(struct ovsdb_monitor_table *mt,
|
|
|
|
uint64_t transaction)
|
|
|
|
{
|
2015-03-14 00:40:18 -07:00
|
|
|
struct ovsdb_monitor_changes *changes;
|
|
|
|
|
|
|
|
changes = ovsdb_monitor_table_find_changes(mt, transaction);
|
|
|
|
if (changes) {
|
|
|
|
changes->n_refs++;
|
|
|
|
} else {
|
|
|
|
ovsdb_monitor_table_add_changes(mt, transaction);
|
|
|
|
}
|
2015-03-13 16:35:49 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
ovsdb_monitor_changes_destroy(struct ovsdb_monitor_changes *changes)
|
|
|
|
{
|
|
|
|
struct ovsdb_monitor_row *row, *next;
|
|
|
|
|
|
|
|
HMAP_FOR_EACH_SAFE (row, next, hmap_node, &changes->rows) {
|
|
|
|
hmap_remove(&changes->rows, &row->hmap_node);
|
|
|
|
ovsdb_monitor_row_destroy(changes->mt, row);
|
|
|
|
}
|
|
|
|
hmap_destroy(&changes->rows);
|
|
|
|
free(changes);
|
|
|
|
}
|
|
|
|
|
2015-06-10 13:19:43 -07:00
|
|
|
static enum ovsdb_monitor_selection
|
|
|
|
ovsdb_monitor_row_update_type(bool initial, const bool old, const bool new)
|
|
|
|
{
|
|
|
|
return initial ? OJMS_INITIAL
|
|
|
|
: !old ? OJMS_INSERT
|
|
|
|
: !new ? OJMS_DELETE
|
|
|
|
: OJMS_MODIFY;
|
|
|
|
}
|
2016-07-18 11:45:52 +03:00
|
|
|
|
|
|
|
/* Set conditional monitoring mode only if we have non-empty condition in one
|
|
|
|
* of the tables at least */
|
|
|
|
static inline void
|
|
|
|
ovsdb_monitor_session_condition_set_mode(
|
|
|
|
struct ovsdb_monitor_session_condition *cond)
|
|
|
|
{
|
|
|
|
cond->conditional = shash_count(&cond->tables) !=
|
|
|
|
cond->n_true_cnd;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Returnes an empty allocated session's condition state holder */
|
|
|
|
struct ovsdb_monitor_session_condition *
|
|
|
|
ovsdb_monitor_session_condition_create(void)
|
|
|
|
{
|
|
|
|
struct ovsdb_monitor_session_condition *condition =
|
|
|
|
xzalloc(sizeof *condition);
|
|
|
|
|
|
|
|
condition->conditional = false;
|
|
|
|
shash_init(&condition->tables);
|
|
|
|
return condition;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ovsdb_monitor_session_condition_destroy(
|
|
|
|
struct ovsdb_monitor_session_condition *condition)
|
|
|
|
{
|
|
|
|
struct shash_node *node, *next;
|
|
|
|
|
|
|
|
if (!condition) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
SHASH_FOR_EACH_SAFE (node, next, &condition->tables) {
|
|
|
|
struct ovsdb_monitor_table_condition *mtc = node->data;
|
|
|
|
|
|
|
|
ovsdb_condition_destroy(&mtc->new_condition);
|
|
|
|
ovsdb_condition_destroy(&mtc->old_condition);
|
|
|
|
shash_delete(&condition->tables, node);
|
|
|
|
free(mtc);
|
|
|
|
}
|
2016-07-25 11:00:29 +03:00
|
|
|
shash_destroy(&condition->tables);
|
2016-07-18 11:45:52 +03:00
|
|
|
free(condition);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct ovsdb_error *
|
|
|
|
ovsdb_monitor_table_condition_create(
|
|
|
|
struct ovsdb_monitor_session_condition *condition,
|
|
|
|
const struct ovsdb_table *table,
|
|
|
|
const struct json *json_cnd)
|
|
|
|
{
|
|
|
|
struct ovsdb_monitor_table_condition *mtc;
|
|
|
|
struct ovsdb_error *error;
|
|
|
|
|
|
|
|
mtc = xzalloc(sizeof *mtc);
|
|
|
|
mtc->table = table;
|
|
|
|
ovsdb_condition_init(&mtc->old_condition);
|
|
|
|
ovsdb_condition_init(&mtc->new_condition);
|
|
|
|
|
|
|
|
if (json_cnd) {
|
|
|
|
error = ovsdb_condition_from_json(table->schema,
|
|
|
|
json_cnd,
|
|
|
|
NULL,
|
|
|
|
&mtc->old_condition);
|
|
|
|
if (error) {
|
|
|
|
free(mtc);
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
shash_add(&condition->tables, table->schema->name, mtc);
|
|
|
|
/* On session startup old == new condition */
|
|
|
|
ovsdb_condition_clone(&mtc->new_condition, &mtc->old_condition);
|
|
|
|
if (ovsdb_condition_is_true(&mtc->old_condition)) {
|
|
|
|
condition->n_true_cnd++;
|
|
|
|
ovsdb_monitor_session_condition_set_mode(condition);
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
|
|
|
ovsdb_monitor_get_table_conditions(
|
|
|
|
const struct ovsdb_monitor_table *mt,
|
|
|
|
const struct ovsdb_monitor_session_condition *condition,
|
|
|
|
struct ovsdb_condition **old_condition,
|
|
|
|
struct ovsdb_condition **new_condition)
|
|
|
|
{
|
|
|
|
if (!condition) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct ovsdb_monitor_table_condition *mtc =
|
|
|
|
shash_find_data(&condition->tables, mt->table->schema->name);
|
|
|
|
|
|
|
|
if (!mtc) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
*old_condition = &mtc->old_condition;
|
|
|
|
*new_condition = &mtc->new_condition;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-07-18 11:45:53 +03:00
|
|
|
struct ovsdb_error *
|
|
|
|
ovsdb_monitor_table_condition_update(
|
|
|
|
struct ovsdb_monitor *dbmon,
|
|
|
|
struct ovsdb_monitor_session_condition *condition,
|
|
|
|
const struct ovsdb_table *table,
|
|
|
|
const struct json *cond_json)
|
|
|
|
{
|
2017-05-26 20:48:45 -07:00
|
|
|
if (!condition) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2016-07-18 11:45:53 +03:00
|
|
|
struct ovsdb_monitor_table_condition *mtc =
|
|
|
|
shash_find_data(&condition->tables, table->schema->name);
|
|
|
|
struct ovsdb_error *error;
|
2016-07-18 11:45:54 +03:00
|
|
|
struct ovsdb_condition cond = OVSDB_CONDITION_INITIALIZER(&cond);
|
2016-07-18 11:45:53 +03:00
|
|
|
|
|
|
|
error = ovsdb_condition_from_json(table->schema, cond_json,
|
|
|
|
NULL, &cond);
|
|
|
|
if (error) {
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
ovsdb_condition_destroy(&mtc->new_condition);
|
|
|
|
ovsdb_condition_clone(&mtc->new_condition, &cond);
|
|
|
|
ovsdb_condition_destroy(&cond);
|
|
|
|
ovsdb_monitor_condition_add_columns(dbmon,
|
|
|
|
table,
|
|
|
|
&mtc->new_condition);
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
ovsdb_monitor_table_condition_updated(struct ovsdb_monitor_table *mt,
|
|
|
|
struct ovsdb_monitor_session_condition *condition)
|
|
|
|
{
|
|
|
|
struct ovsdb_monitor_table_condition *mtc =
|
|
|
|
shash_find_data(&condition->tables, mt->table->schema->name);
|
|
|
|
|
|
|
|
if (mtc) {
|
|
|
|
/* If conditional monitoring - set old condition to new condition */
|
|
|
|
if (ovsdb_condition_cmp_3way(&mtc->old_condition,
|
|
|
|
&mtc->new_condition)) {
|
|
|
|
if (ovsdb_condition_is_true(&mtc->new_condition)) {
|
2016-09-16 00:51:49 +00:00
|
|
|
if (!ovsdb_condition_is_true(&mtc->old_condition)) {
|
2016-07-18 11:45:53 +03:00
|
|
|
condition->n_true_cnd++;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (ovsdb_condition_is_true(&mtc->old_condition)) {
|
|
|
|
condition->n_true_cnd--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ovsdb_condition_destroy(&mtc->old_condition);
|
|
|
|
ovsdb_condition_clone(&mtc->old_condition, &mtc->new_condition);
|
|
|
|
ovsdb_monitor_session_condition_set_mode(condition);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-18 11:45:52 +03:00
|
|
|
static enum ovsdb_monitor_selection
|
|
|
|
ovsdb_monitor_row_update_type_condition(
|
|
|
|
const struct ovsdb_monitor_table *mt,
|
|
|
|
const struct ovsdb_monitor_session_condition *condition,
|
|
|
|
bool initial,
|
2016-07-18 11:45:53 +03:00
|
|
|
enum ovsdb_monitor_row_type row_type,
|
2016-07-18 11:45:52 +03:00
|
|
|
const struct ovsdb_datum *old,
|
|
|
|
const struct ovsdb_datum *new)
|
|
|
|
{
|
|
|
|
struct ovsdb_condition *old_condition, *new_condition;
|
|
|
|
enum ovsdb_monitor_selection type =
|
|
|
|
ovsdb_monitor_row_update_type(initial, old, new);
|
|
|
|
|
|
|
|
if (ovsdb_monitor_get_table_conditions(mt,
|
|
|
|
condition,
|
|
|
|
&old_condition,
|
|
|
|
&new_condition)) {
|
|
|
|
bool old_cond = !old ? false
|
|
|
|
: ovsdb_condition_empty_or_match_any(old,
|
2016-07-18 11:45:53 +03:00
|
|
|
old_condition,
|
|
|
|
row_type == OVSDB_MONITOR_ROW ?
|
|
|
|
mt->columns_index_map :
|
|
|
|
NULL);
|
2016-07-18 11:45:52 +03:00
|
|
|
bool new_cond = !new ? false
|
|
|
|
: ovsdb_condition_empty_or_match_any(new,
|
2016-07-18 11:45:53 +03:00
|
|
|
new_condition,
|
|
|
|
row_type == OVSDB_MONITOR_ROW ?
|
|
|
|
mt->columns_index_map :
|
|
|
|
NULL);
|
2016-07-18 11:45:52 +03:00
|
|
|
|
|
|
|
if (!old_cond && !new_cond) {
|
|
|
|
type = OJMS_NONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
case OJMS_INITIAL:
|
|
|
|
case OJMS_INSERT:
|
|
|
|
if (!new_cond) {
|
|
|
|
type = OJMS_NONE;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case OJMS_MODIFY:
|
|
|
|
type = !old_cond ? OJMS_INSERT : !new_cond
|
|
|
|
? OJMS_DELETE : OJMS_MODIFY;
|
|
|
|
break;
|
|
|
|
case OJMS_DELETE:
|
|
|
|
if (!old_cond) {
|
|
|
|
type = OJMS_NONE;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case OJMS_NONE:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return type;
|
|
|
|
}
|
|
|
|
|
2015-10-15 14:07:43 -07:00
|
|
|
static bool
|
|
|
|
ovsdb_monitor_row_skip_update(const struct ovsdb_monitor_table *mt,
|
2016-07-18 11:45:53 +03:00
|
|
|
enum ovsdb_monitor_row_type row_type,
|
|
|
|
const struct ovsdb_datum *old,
|
|
|
|
const struct ovsdb_datum *new,
|
2015-10-15 14:07:43 -07:00
|
|
|
enum ovsdb_monitor_selection type,
|
|
|
|
unsigned long int *changed)
|
|
|
|
{
|
|
|
|
if (!(mt->select & type)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (type == OJMS_MODIFY) {
|
|
|
|
size_t i, n_changes;
|
|
|
|
|
|
|
|
n_changes = 0;
|
|
|
|
memset(changed, 0, bitmap_n_bytes(mt->n_columns));
|
|
|
|
for (i = 0; i < mt->n_columns; i++) {
|
|
|
|
const struct ovsdb_column *c = mt->columns[i].column;
|
2016-07-18 11:45:53 +03:00
|
|
|
size_t index = row_type == OVSDB_ROW ? c->index : i;
|
|
|
|
if (!ovsdb_datum_equals(&old[index], &new[index], &c->type)) {
|
2015-10-15 14:07:43 -07:00
|
|
|
bitmap_set1(changed, i);
|
|
|
|
n_changes++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!n_changes) {
|
|
|
|
/* No actual changes: presumably a row changed and then
|
|
|
|
* changed back later. */
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
2015-06-10 13:19:43 -07:00
|
|
|
|
2015-03-11 21:20:44 -07:00
|
|
|
/* Returns JSON for a <row-update> (as described in RFC 7047) for 'row' within
|
|
|
|
* 'mt', or NULL if no row update should be sent.
|
|
|
|
*
|
|
|
|
* The caller should specify 'initial' as true if the returned JSON is going to
|
|
|
|
* be used as part of the initial reply to a "monitor" request, false if it is
|
|
|
|
* going to be used as part of an "update" notification.
|
|
|
|
*
|
|
|
|
* 'changed' must be a scratch buffer for internal use that is at least
|
|
|
|
* bitmap_n_bytes(mt->n_columns) bytes long. */
|
|
|
|
static struct json *
|
|
|
|
ovsdb_monitor_compose_row_update(
|
|
|
|
const struct ovsdb_monitor_table *mt,
|
2016-07-18 11:45:52 +03:00
|
|
|
const struct ovsdb_monitor_session_condition *condition OVS_UNUSED,
|
2016-07-18 11:45:53 +03:00
|
|
|
enum ovsdb_monitor_row_type row_type OVS_UNUSED,
|
|
|
|
const void *_row,
|
2015-03-11 21:20:44 -07:00
|
|
|
bool initial, unsigned long int *changed)
|
|
|
|
{
|
2016-07-18 11:45:53 +03:00
|
|
|
const struct ovsdb_monitor_row *row = _row;
|
2015-03-11 21:20:44 -07:00
|
|
|
enum ovsdb_monitor_selection type;
|
|
|
|
struct json *old_json, *new_json;
|
|
|
|
struct json *row_json;
|
|
|
|
size_t i;
|
|
|
|
|
2016-07-18 11:45:53 +03:00
|
|
|
ovs_assert(row_type == OVSDB_MONITOR_ROW);
|
2015-06-10 13:19:43 -07:00
|
|
|
type = ovsdb_monitor_row_update_type(initial, row->old, row->new);
|
2016-07-18 11:45:53 +03:00
|
|
|
if (ovsdb_monitor_row_skip_update(mt, row_type, row->old,
|
|
|
|
row->new, type, changed)) {
|
2015-03-11 21:20:44 -07:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
row_json = json_object_create();
|
|
|
|
old_json = new_json = NULL;
|
|
|
|
if (type & (OJMS_DELETE | OJMS_MODIFY)) {
|
|
|
|
old_json = json_object_create();
|
|
|
|
json_object_put(row_json, "old", old_json);
|
|
|
|
}
|
|
|
|
if (type & (OJMS_INITIAL | OJMS_INSERT | OJMS_MODIFY)) {
|
|
|
|
new_json = json_object_create();
|
|
|
|
json_object_put(row_json, "new", new_json);
|
|
|
|
}
|
2016-07-18 11:45:51 +03:00
|
|
|
for (i = 0; i < mt->n_monitored_columns; i++) {
|
2015-03-11 21:20:44 -07:00
|
|
|
const struct ovsdb_monitor_column *c = &mt->columns[i];
|
|
|
|
|
2016-07-18 11:45:51 +03:00
|
|
|
if (!c->monitored || !(type & c->select)) {
|
2015-03-11 21:20:44 -07:00
|
|
|
/* We don't care about this type of change for this
|
|
|
|
* particular column (but we will care about it for some
|
|
|
|
* other column). */
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((type == OJMS_MODIFY && bitmap_is_set(changed, i))
|
|
|
|
|| type == OJMS_DELETE) {
|
|
|
|
json_object_put(old_json, c->column->name,
|
|
|
|
ovsdb_datum_to_json(&row->old[i],
|
|
|
|
&c->column->type));
|
|
|
|
}
|
|
|
|
if (type & (OJMS_INITIAL | OJMS_INSERT | OJMS_MODIFY)) {
|
|
|
|
json_object_put(new_json, c->column->name,
|
|
|
|
ovsdb_datum_to_json(&row->new[i],
|
|
|
|
&c->column->type));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return row_json;
|
|
|
|
}
|
|
|
|
|
2015-10-15 14:07:43 -07:00
|
|
|
/* Returns JSON for a <row-update2> (as described in ovsdb-server(1) mapage)
|
|
|
|
* for 'row' within * 'mt', or NULL if no row update should be sent.
|
|
|
|
*
|
|
|
|
* The caller should specify 'initial' as true if the returned JSON is
|
2016-07-18 11:45:53 +03:00
|
|
|
* going to be used as part of the initial reply to a "monitor_cond" request,
|
2015-10-15 14:07:43 -07:00
|
|
|
* false if it is going to be used as part of an "update2" notification.
|
|
|
|
*
|
|
|
|
* 'changed' must be a scratch buffer for internal use that is at least
|
|
|
|
* bitmap_n_bytes(mt->n_columns) bytes long. */
|
|
|
|
static struct json *
|
|
|
|
ovsdb_monitor_compose_row_update2(
|
|
|
|
const struct ovsdb_monitor_table *mt,
|
2016-07-18 11:45:52 +03:00
|
|
|
const struct ovsdb_monitor_session_condition *condition,
|
2016-07-18 11:45:53 +03:00
|
|
|
enum ovsdb_monitor_row_type row_type,
|
|
|
|
const void *_row,
|
2015-10-15 14:07:43 -07:00
|
|
|
bool initial, unsigned long int *changed)
|
|
|
|
{
|
|
|
|
enum ovsdb_monitor_selection type;
|
|
|
|
struct json *row_update2, *diff_json;
|
2016-07-18 11:45:53 +03:00
|
|
|
const struct ovsdb_datum *old, *new;
|
2015-10-15 14:07:43 -07:00
|
|
|
size_t i;
|
|
|
|
|
2016-07-18 11:45:53 +03:00
|
|
|
if (row_type == OVSDB_MONITOR_ROW) {
|
|
|
|
old = ((const struct ovsdb_monitor_row *)_row)->old;;
|
|
|
|
new = ((const struct ovsdb_monitor_row *)_row)->new;
|
|
|
|
} else {
|
|
|
|
old = new = ((const struct ovsdb_row *)_row)->fields;
|
|
|
|
}
|
|
|
|
|
2016-07-18 11:45:52 +03:00
|
|
|
type = ovsdb_monitor_row_update_type_condition(mt, condition, initial,
|
2016-07-18 11:45:53 +03:00
|
|
|
row_type, old, new);
|
|
|
|
if (ovsdb_monitor_row_skip_update(mt, row_type, old, new, type, changed)) {
|
2015-10-15 14:07:43 -07:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
row_update2 = json_object_create();
|
|
|
|
if (type == OJMS_DELETE) {
|
|
|
|
json_object_put(row_update2, "delete", json_null_create());
|
|
|
|
} else {
|
|
|
|
diff_json = json_object_create();
|
|
|
|
const char *op;
|
|
|
|
|
2016-07-18 11:45:51 +03:00
|
|
|
for (i = 0; i < mt->n_monitored_columns; i++) {
|
2015-10-15 14:07:43 -07:00
|
|
|
const struct ovsdb_monitor_column *c = &mt->columns[i];
|
2016-07-18 11:45:53 +03:00
|
|
|
size_t index = row_type == OVSDB_ROW ? c->column->index : i;
|
2016-07-18 11:45:51 +03:00
|
|
|
if (!c->monitored || !(type & c->select)) {
|
2015-10-15 14:07:43 -07:00
|
|
|
/* We don't care about this type of change for this
|
|
|
|
* particular column (but we will care about it for some
|
|
|
|
* other column). */
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (type == OJMS_MODIFY) {
|
|
|
|
struct ovsdb_datum diff;
|
|
|
|
|
|
|
|
if (!bitmap_is_set(changed, i)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2016-07-18 11:45:53 +03:00
|
|
|
ovsdb_datum_diff(&diff ,&old[index], &new[index],
|
2015-10-15 14:07:43 -07:00
|
|
|
&c->column->type);
|
|
|
|
json_object_put(diff_json, c->column->name,
|
|
|
|
ovsdb_datum_to_json(&diff, &c->column->type));
|
|
|
|
ovsdb_datum_destroy(&diff, &c->column->type);
|
|
|
|
} else {
|
2016-07-18 11:45:53 +03:00
|
|
|
if (!ovsdb_datum_is_default(&new[index], &c->column->type)) {
|
2015-10-15 14:07:43 -07:00
|
|
|
json_object_put(diff_json, c->column->name,
|
2016-07-18 11:45:53 +03:00
|
|
|
ovsdb_datum_to_json(&new[index],
|
2015-10-15 14:07:43 -07:00
|
|
|
&c->column->type));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
op = type == OJMS_INITIAL ? "initial"
|
|
|
|
: type == OJMS_MODIFY ? "modify" : "insert";
|
|
|
|
json_object_put(row_update2, op, diff_json);
|
|
|
|
}
|
|
|
|
|
|
|
|
return row_update2;
|
|
|
|
}
|
|
|
|
|
2015-09-24 14:13:45 -07:00
|
|
|
static size_t
|
|
|
|
ovsdb_monitor_max_columns(struct ovsdb_monitor *dbmon)
|
|
|
|
{
|
|
|
|
struct shash_node *node;
|
|
|
|
size_t max_columns = 0;
|
|
|
|
|
|
|
|
SHASH_FOR_EACH (node, &dbmon->tables) {
|
|
|
|
struct ovsdb_monitor_table *mt = node->data;
|
|
|
|
|
|
|
|
max_columns = MAX(max_columns, mt->n_columns);
|
|
|
|
}
|
|
|
|
|
|
|
|
return max_columns;
|
|
|
|
}
|
|
|
|
|
2016-07-18 11:45:53 +03:00
|
|
|
static void
|
|
|
|
ovsdb_monitor_add_json_row(struct json **json, const char *table_name,
|
|
|
|
struct json **table_json, struct json *row_json,
|
|
|
|
const struct uuid *row_uuid)
|
|
|
|
{
|
|
|
|
char uuid[UUID_LEN + 1];
|
|
|
|
|
|
|
|
/* Create JSON object for transaction overall. */
|
|
|
|
if (!*json) {
|
|
|
|
*json = json_object_create();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Create JSON object for transaction on this table. */
|
|
|
|
if (!*table_json) {
|
|
|
|
*table_json = json_object_create();
|
|
|
|
json_object_put(*json, table_name, *table_json);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Add JSON row to JSON table. */
|
|
|
|
snprintf(uuid, sizeof uuid, UUID_FMT, UUID_ARGS(row_uuid));
|
|
|
|
json_object_put(*table_json, uuid, row_json);
|
|
|
|
}
|
|
|
|
|
2015-03-11 21:20:44 -07:00
|
|
|
/* Constructs and returns JSON for a <table-updates> object (as described in
|
2015-03-16 15:45:27 -07:00
|
|
|
* RFC 7047) for all the outstanding changes within 'monitor', starting from
|
|
|
|
* 'transaction'. */
|
|
|
|
static struct json*
|
2016-07-18 11:45:52 +03:00
|
|
|
ovsdb_monitor_compose_update(
|
|
|
|
struct ovsdb_monitor *dbmon,
|
|
|
|
bool initial, uint64_t transaction,
|
|
|
|
const struct ovsdb_monitor_session_condition *condition,
|
|
|
|
compose_row_update_cb_func row_update)
|
2015-03-11 21:20:44 -07:00
|
|
|
{
|
|
|
|
struct shash_node *node;
|
|
|
|
struct json *json;
|
2015-09-24 14:13:45 -07:00
|
|
|
size_t max_columns = ovsdb_monitor_max_columns(dbmon);
|
|
|
|
unsigned long int *changed = xmalloc(bitmap_n_bytes(max_columns));
|
2015-03-11 21:20:44 -07:00
|
|
|
|
|
|
|
json = NULL;
|
|
|
|
SHASH_FOR_EACH (node, &dbmon->tables) {
|
|
|
|
struct ovsdb_monitor_table *mt = node->data;
|
|
|
|
struct ovsdb_monitor_row *row, *next;
|
2015-03-14 00:40:18 -07:00
|
|
|
struct ovsdb_monitor_changes *changes;
|
2015-03-11 21:20:44 -07:00
|
|
|
struct json *table_json = NULL;
|
|
|
|
|
2015-03-16 15:45:27 -07:00
|
|
|
changes = ovsdb_monitor_table_find_changes(mt, transaction);
|
2015-03-14 00:40:18 -07:00
|
|
|
if (!changes) {
|
2015-03-13 16:35:49 -07:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2016-09-16 00:51:49 +00:00
|
|
|
HMAP_FOR_EACH_SAFE (row, next, hmap_node, &changes->rows) {
|
|
|
|
struct json *row_json;
|
|
|
|
row_json = (*row_update)(mt, condition, OVSDB_MONITOR_ROW, row,
|
|
|
|
initial, changed);
|
|
|
|
if (row_json) {
|
|
|
|
ovsdb_monitor_add_json_row(&json, mt->table->schema->name,
|
|
|
|
&table_json, row_json,
|
|
|
|
&row->uuid);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-07-18 11:45:53 +03:00
|
|
|
free(changed);
|
2015-03-11 21:20:44 -07:00
|
|
|
|
2016-07-18 11:45:53 +03:00
|
|
|
return json;
|
|
|
|
}
|
2015-03-11 21:20:44 -07:00
|
|
|
|
2016-07-18 11:45:53 +03:00
|
|
|
static struct json*
|
|
|
|
ovsdb_monitor_compose_cond_change_update(
|
|
|
|
struct ovsdb_monitor *dbmon,
|
|
|
|
struct ovsdb_monitor_session_condition *condition)
|
|
|
|
{
|
|
|
|
struct shash_node *node;
|
|
|
|
struct json *json = NULL;
|
|
|
|
size_t max_columns = ovsdb_monitor_max_columns(dbmon);
|
|
|
|
unsigned long int *changed = xmalloc(bitmap_n_bytes(max_columns));
|
2015-03-11 21:20:44 -07:00
|
|
|
|
2016-07-18 11:45:53 +03:00
|
|
|
SHASH_FOR_EACH (node, &dbmon->tables) {
|
|
|
|
struct ovsdb_monitor_table *mt = node->data;
|
|
|
|
struct ovsdb_row *row;
|
|
|
|
struct json *table_json = NULL;
|
|
|
|
struct ovsdb_condition *old_condition, *new_condition;
|
|
|
|
|
|
|
|
if (!ovsdb_monitor_get_table_conditions(mt,
|
|
|
|
condition,
|
|
|
|
&old_condition,
|
|
|
|
&new_condition) ||
|
|
|
|
!ovsdb_condition_cmp_3way(old_condition, new_condition)) {
|
|
|
|
/* Nothing to update on this table */
|
|
|
|
continue;
|
|
|
|
}
|
2015-03-11 21:20:44 -07:00
|
|
|
|
2016-07-18 11:45:53 +03:00
|
|
|
/* Iterate over all rows in table */
|
|
|
|
HMAP_FOR_EACH (row, hmap_node, &mt->table->rows) {
|
|
|
|
struct json *row_json;
|
|
|
|
|
|
|
|
row_json = ovsdb_monitor_compose_row_update2(mt, condition,
|
|
|
|
OVSDB_ROW, row,
|
|
|
|
false, changed);
|
|
|
|
if (row_json) {
|
|
|
|
ovsdb_monitor_add_json_row(&json, mt->table->schema->name,
|
|
|
|
&table_json, row_json,
|
|
|
|
ovsdb_row_get_uuid(row));
|
2015-03-11 21:20:44 -07:00
|
|
|
}
|
|
|
|
}
|
2016-07-18 11:45:53 +03:00
|
|
|
ovsdb_monitor_table_condition_updated(mt, condition);
|
2015-03-16 15:45:27 -07:00
|
|
|
}
|
|
|
|
free(changed);
|
|
|
|
|
|
|
|
return json;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Returns JSON for a <table-updates> object (as described in RFC 7047)
|
|
|
|
* for all the outstanding changes within 'monitor' that starts from
|
2016-07-18 11:45:53 +03:00
|
|
|
* '*unflushed'.
|
|
|
|
* If cond_updated is true all rows in the db that match conditions will be
|
|
|
|
* sent.
|
2015-03-16 15:45:27 -07:00
|
|
|
*
|
|
|
|
* The caller should specify 'initial' as true if the returned JSON is going to
|
|
|
|
* be used as part of the initial reply to a "monitor" request, false if it is
|
|
|
|
* going to be used as part of an "update" notification. */
|
|
|
|
struct json *
|
2016-07-18 11:45:52 +03:00
|
|
|
ovsdb_monitor_get_update(
|
|
|
|
struct ovsdb_monitor *dbmon,
|
2016-07-18 11:45:53 +03:00
|
|
|
bool initial, bool cond_updated,
|
|
|
|
uint64_t *unflushed_,
|
|
|
|
struct ovsdb_monitor_session_condition *condition,
|
2016-07-18 11:45:52 +03:00
|
|
|
enum ovsdb_monitor_version version)
|
2015-03-16 15:45:27 -07:00
|
|
|
{
|
2016-07-18 11:45:52 +03:00
|
|
|
struct ovsdb_monitor_json_cache_node *cache_node = NULL;
|
2015-03-16 15:45:27 -07:00
|
|
|
struct shash_node *node;
|
|
|
|
struct json *json;
|
2016-02-22 00:31:03 -08:00
|
|
|
const uint64_t unflushed = *unflushed_;
|
|
|
|
const uint64_t next_unflushed = dbmon->n_transactions + 1;
|
2015-03-16 15:45:27 -07:00
|
|
|
|
2016-07-18 11:45:53 +03:00
|
|
|
ovs_assert(cond_updated ? unflushed == next_unflushed : true);
|
|
|
|
|
2015-03-16 15:45:27 -07:00
|
|
|
/* Return a clone of cached json if one exists. Otherwise,
|
|
|
|
* generate a new one and add it to the cache. */
|
2016-07-18 11:45:53 +03:00
|
|
|
if (!condition || (!condition->conditional && !cond_updated)) {
|
2016-07-18 11:45:52 +03:00
|
|
|
cache_node = ovsdb_monitor_json_cache_search(dbmon, version,
|
|
|
|
unflushed);
|
|
|
|
}
|
2015-03-16 15:45:27 -07:00
|
|
|
if (cache_node) {
|
|
|
|
json = cache_node->json ? json_clone(cache_node->json) : NULL;
|
|
|
|
} else {
|
2015-10-15 14:07:43 -07:00
|
|
|
if (version == OVSDB_MONITOR_V1) {
|
2016-07-18 11:45:52 +03:00
|
|
|
json =
|
|
|
|
ovsdb_monitor_compose_update(dbmon, initial, unflushed,
|
|
|
|
condition,
|
|
|
|
ovsdb_monitor_compose_row_update);
|
2015-10-15 14:07:43 -07:00
|
|
|
} else {
|
|
|
|
ovs_assert(version == OVSDB_MONITOR_V2);
|
2016-07-18 11:45:53 +03:00
|
|
|
if (!cond_updated) {
|
2016-09-16 00:51:49 +00:00
|
|
|
json = ovsdb_monitor_compose_update(dbmon, initial, unflushed,
|
|
|
|
condition,
|
|
|
|
ovsdb_monitor_compose_row_update2);
|
|
|
|
|
|
|
|
if (!condition || !condition->conditional) {
|
|
|
|
ovsdb_monitor_json_cache_insert(dbmon, version, unflushed,
|
|
|
|
json);
|
|
|
|
}
|
|
|
|
} else {
|
2016-07-18 11:45:53 +03:00
|
|
|
/* Compose update on whole db due to condition update.
|
|
|
|
Session must be flushed (change list is empty)*/
|
2016-09-16 00:51:49 +00:00
|
|
|
json =
|
|
|
|
ovsdb_monitor_compose_cond_change_update(dbmon, condition);
|
|
|
|
}
|
|
|
|
}
|
2015-03-16 15:45:27 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Maintain transaction id of 'changes'. */
|
|
|
|
SHASH_FOR_EACH (node, &dbmon->tables) {
|
|
|
|
struct ovsdb_monitor_table *mt = node->data;
|
2015-03-13 16:35:49 -07:00
|
|
|
|
2016-02-22 00:31:03 -08:00
|
|
|
ovsdb_monitor_table_untrack_changes(mt, unflushed);
|
|
|
|
ovsdb_monitor_table_track_changes(mt, next_unflushed);
|
2015-03-11 21:20:44 -07:00
|
|
|
}
|
2016-02-22 00:31:03 -08:00
|
|
|
*unflushed_ = next_unflushed;
|
2015-03-16 15:45:27 -07:00
|
|
|
|
2015-03-11 21:20:44 -07:00
|
|
|
return json;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
ovsdb-monitor: add transaction ids
With N:1 mappings, multiple jsonrpc server may be servicing the rpc
connection at a different pace. ovsdb-monitor thus needs to maintain
different change sets, depends on connection speed of each rpc
connections. Connections servicing at the same speed can share the
same change set.
Transaction ID is an concept added to describe the change set. One
possible view of the database state is a sequence of changes, more
precisely, commits be applied to it in order, starting from an
initial state, with commit 0. The logic can also be applied to the
jsonrpc monitor; each change it pushes corresponds to commits between
two transaction IDs.
This patch introduces transaction IDs. For ovsdb-monitor, it maintains
n_transactions, starting from 0. Each commit add 1 to the number.
Jsonrpc maintains and 'unflushed' transaction number, corresponding to
the next commit the remote has not seen. jsonrpc's job is simply to
notice there are changes in the ovsdb-monitor that it is interested in,
i.e. 'n_transactions' >= 'unflushed', get the changes in json format,
and push them to the remote site.
Signed-off-by: Andy Zhou <azhou@nicira.com>
Acked-by: Ben Pfaff <blp@nicira.com>
2015-03-12 23:15:56 -07:00
|
|
|
ovsdb_monitor_needs_flush(struct ovsdb_monitor *dbmon,
|
|
|
|
uint64_t next_transaction)
|
2015-03-11 21:20:44 -07:00
|
|
|
{
|
ovsdb-monitor: add transaction ids
With N:1 mappings, multiple jsonrpc server may be servicing the rpc
connection at a different pace. ovsdb-monitor thus needs to maintain
different change sets, depends on connection speed of each rpc
connections. Connections servicing at the same speed can share the
same change set.
Transaction ID is an concept added to describe the change set. One
possible view of the database state is a sequence of changes, more
precisely, commits be applied to it in order, starting from an
initial state, with commit 0. The logic can also be applied to the
jsonrpc monitor; each change it pushes corresponds to commits between
two transaction IDs.
This patch introduces transaction IDs. For ovsdb-monitor, it maintains
n_transactions, starting from 0. Each commit add 1 to the number.
Jsonrpc maintains and 'unflushed' transaction number, corresponding to
the next commit the remote has not seen. jsonrpc's job is simply to
notice there are changes in the ovsdb-monitor that it is interested in,
i.e. 'n_transactions' >= 'unflushed', get the changes in json format,
and push them to the remote site.
Signed-off-by: Andy Zhou <azhou@nicira.com>
Acked-by: Ben Pfaff <blp@nicira.com>
2015-03-12 23:15:56 -07:00
|
|
|
ovs_assert(next_transaction <= dbmon->n_transactions + 1);
|
|
|
|
return (next_transaction <= dbmon->n_transactions);
|
2015-03-11 21:20:44 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ovsdb_monitor_table_add_select(struct ovsdb_monitor *dbmon,
|
|
|
|
const struct ovsdb_table *table,
|
|
|
|
enum ovsdb_monitor_selection select)
|
|
|
|
{
|
|
|
|
struct ovsdb_monitor_table * mt;
|
|
|
|
|
|
|
|
mt = shash_find_data(&dbmon->tables, table->schema->name);
|
|
|
|
mt->select |= select;
|
|
|
|
}
|
|
|
|
|
2015-06-10 17:11:09 -07:00
|
|
|
/*
|
|
|
|
* If a row's change type (insert, delete or modify) matches that of
|
|
|
|
* the monitor, they should be sent to the monitor's clients as updates.
|
|
|
|
* Of cause, the monitor should also internally update with this change.
|
|
|
|
*
|
|
|
|
* When a change type does not require client side update, the monitor
|
|
|
|
* may still need to keep track of certain changes in order to generate
|
|
|
|
* correct future updates. For example, the monitor internal state should
|
|
|
|
* be updated whenever a new row is inserted, in order to generate the
|
|
|
|
* correct initial state, regardless if a insert change type is being
|
|
|
|
* monitored.
|
|
|
|
*
|
|
|
|
* On the other hand, if a transaction only contains changes to columns
|
|
|
|
* that are not monitored, this transaction can be safely ignored by the
|
|
|
|
* monitor.
|
|
|
|
*
|
|
|
|
* Thus, the order of the declaration is important:
|
|
|
|
* 'OVSDB_CHANGES_REQUIRE_EXTERNAL_UPDATE' always implies
|
|
|
|
* 'OVSDB_CHANGES_REQUIRE_INTERNAL_UPDATE', but not vice versa. */
|
|
|
|
enum ovsdb_monitor_changes_efficacy {
|
|
|
|
OVSDB_CHANGES_NO_EFFECT, /* Monitor does not care about this
|
|
|
|
change. */
|
|
|
|
OVSDB_CHANGES_REQUIRE_INTERNAL_UPDATE, /* Monitor internal updates. */
|
|
|
|
OVSDB_CHANGES_REQUIRE_EXTERNAL_UPDATE, /* Client needs to be updated. */
|
|
|
|
};
|
|
|
|
|
2015-03-11 21:20:44 -07:00
|
|
|
struct ovsdb_monitor_aux {
|
|
|
|
const struct ovsdb_monitor *monitor;
|
|
|
|
struct ovsdb_monitor_table *mt;
|
2015-06-10 17:24:08 -07:00
|
|
|
enum ovsdb_monitor_changes_efficacy efficacy;
|
2015-03-11 21:20:44 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
static void
|
|
|
|
ovsdb_monitor_init_aux(struct ovsdb_monitor_aux *aux,
|
|
|
|
const struct ovsdb_monitor *m)
|
|
|
|
{
|
|
|
|
aux->monitor = m;
|
|
|
|
aux->mt = NULL;
|
2015-06-10 17:24:08 -07:00
|
|
|
aux->efficacy = OVSDB_CHANGES_NO_EFFECT;
|
2015-03-11 21:20:44 -07:00
|
|
|
}
|
|
|
|
|
2015-03-14 00:40:18 -07:00
|
|
|
static void
|
|
|
|
ovsdb_monitor_changes_update(const struct ovsdb_row *old,
|
|
|
|
const struct ovsdb_row *new,
|
|
|
|
const struct ovsdb_monitor_table *mt,
|
|
|
|
struct ovsdb_monitor_changes *changes)
|
2015-03-11 21:20:44 -07:00
|
|
|
{
|
|
|
|
const struct uuid *uuid = ovsdb_row_get_uuid(new ? new : old);
|
|
|
|
struct ovsdb_monitor_row *change;
|
|
|
|
|
2015-03-14 00:40:18 -07:00
|
|
|
change = ovsdb_monitor_changes_row_find(changes, uuid);
|
2015-03-11 21:20:44 -07:00
|
|
|
if (!change) {
|
2015-03-13 16:35:49 -07:00
|
|
|
change = xzalloc(sizeof *change);
|
2015-03-14 00:40:18 -07:00
|
|
|
hmap_insert(&changes->rows, &change->hmap_node, uuid_hash(uuid));
|
2015-03-11 21:20:44 -07:00
|
|
|
change->uuid = *uuid;
|
|
|
|
change->old = clone_monitor_row_data(mt, old);
|
|
|
|
change->new = clone_monitor_row_data(mt, new);
|
|
|
|
} else {
|
|
|
|
if (new) {
|
ovsdb: Fix segfalut during replication.
The newly added replication logic makes it possible for a monitor to
receive delete and insertion of the same row back to back, which
was not possible before. Add logic (and comment) to handle this
case to avoid follow crash reported by Valgrind:
#0 0x0000000000453edd in ovsdb_datum_compare_3way
(a=0x5efbe60, b=0x0, type=0x5e6a848) at lib/ovsdb-data.c:1626
#1 0x0000000000453ea4 in ovsdb_datum_equals
(a=0x5efbe60, b=0x0, type=0x5e6a848) at lib/ovsdb-data.c:1616
#2 0x000000000041b651 in update_monitor_row_data
(mt=0x5eda4a0, row=0x5efbe00, data=0x0) at ovsdb/monitor.c:310
#3 0x000000000041ed14 in ovsdb_monitor_changes_update
(old=0x0, new=0x5efbe00, mt=0x5eda4a0, changes=0x5ef7180)
at ovsdb/monitor.c:1255
#4 0x000000000041f12e in ovsdb_monitor_change_cb
(old=0x0, new=0x5efbe00, changed=0x5efc218, aux_=0xffefff040)
at ovsdb/monitor.c:1339
#5 0x000000000042ded9 in ovsdb_txn_for_each_change
(txn=0x5efbd90, cb=0x41ef50 <ovsdb_monitor_change_cb>,
aux=0xffefff040) at ovsdb/transaction.c:906
#6 0x0000000000420155 in ovsdb_monitor_commit
(replica=0x5eda2c0, txn=0x5efbd90, durable=false)
at ovsdb/monitor.c:1553
#7 0x000000000042dc04 in ovsdb_txn_commit_
(txn=0x5efbd90, durable=false) at ovsdb/transaction.c:868
#8 0x000000000042ddd4 in ovsdb_txn_commit (txn=0x5efbd90, durable=false)
at ovsdb/transaction.c:893
#9 0x0000000000422e0c in process_notification
(table_updates=0x5efad10, db=0x5e6bd40) at ovsdb/replication.c:575
#10 0x0000000000420ff3 in replication_run () at ovsdb/replication.c:184
#11 0x0000000000405cc8 in main_loop
(jsonrpc=0x5e67770, all_dbs=0xffefff3a0, unixctl=0x5ebd980,
remotes=0xffefff360, run_process=0x0, exiting=0xffefff3c0,
is_backup=0xffefff2de) at ovsdb/ovsdb-server.c:198
#12 0x0000000000406edb in main (argc=1, argv=0xffefff550)
at ovsdb/ovsdb-server.c:429
Reported-by: Joe Stringer <joe@ovn.org>
Reported-at: http://openvswitch.org/pipermail/dev/2016-September/079315.html
Reported-by: Alin Serdean <aserdean@cloudbasesolutions.com>
Reported-at: http://openvswitch.org/pipermail/dev/2016-September/079586.html
Co-authored-by: Joe Stringer <joe@ovn.org>
Signed-off-by: Andy Zhou <azhou@ovn.org>
Acked-by: Ben Pfaff <blp@ovn.org>
2016-09-20 12:44:32 -07:00
|
|
|
if (!change->new) {
|
|
|
|
/* Reinsert the row that was just deleted.
|
|
|
|
*
|
|
|
|
* This path won't be hit without replication. Whenever OVSDB
|
|
|
|
* server inserts a new row, It always generates a new UUID
|
|
|
|
* that is different from the row just deleted.
|
|
|
|
*
|
|
|
|
* With replication, this path can be hit in a corner
|
|
|
|
* case when two OVSDB servers are set up to replicate
|
|
|
|
* each other. Not that is a useful set up, but can
|
|
|
|
* happen in practice.
|
|
|
|
*
|
|
|
|
* An example of how this path can be hit is documented below.
|
|
|
|
* The details is not as important to the correctness of the
|
|
|
|
* logic, but added here to convince ourselves that this path
|
|
|
|
* can be hit.
|
|
|
|
*
|
|
|
|
* Imagine two OVSDB servers that replicates from each
|
|
|
|
* other. For each replication session, there is a
|
|
|
|
* corresponding monitor at the other end of the replication
|
|
|
|
* JSONRPC connection.
|
|
|
|
*
|
|
|
|
* The events can lead to a back to back deletion and
|
|
|
|
* insertion operation of the same row for the monitor of
|
|
|
|
* the first server are:
|
|
|
|
*
|
|
|
|
* 1. A row is inserted in the first OVSDB server.
|
|
|
|
* 2. The row is then replicated to the remote OVSDB server.
|
|
|
|
* 3. The row is now deleted by the local OVSDB server. This
|
|
|
|
* deletion operation is replicated to the local monitor
|
|
|
|
* of the OVSDB server.
|
|
|
|
* 4. The monitor now receives the same row, as an insertion,
|
|
|
|
* from the replication server. Because of
|
|
|
|
* replication, the row carries the same UUID as the row
|
|
|
|
* just deleted.
|
|
|
|
*/
|
|
|
|
change->new = clone_monitor_row_data(mt, new);
|
|
|
|
} else {
|
|
|
|
update_monitor_row_data(mt, new, change->new);
|
|
|
|
}
|
2015-03-11 21:20:44 -07:00
|
|
|
} else {
|
|
|
|
free_monitor_row_data(mt, change->new);
|
|
|
|
change->new = NULL;
|
|
|
|
|
|
|
|
if (!change->old) {
|
|
|
|
/* This row was added then deleted. Forget about it. */
|
2015-03-14 00:40:18 -07:00
|
|
|
hmap_remove(&changes->rows, &change->hmap_node);
|
2015-03-11 21:20:44 -07:00
|
|
|
free(change);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-03-14 00:40:18 -07:00
|
|
|
}
|
|
|
|
|
2015-06-10 17:11:09 -07:00
|
|
|
static bool
|
|
|
|
ovsdb_monitor_columns_changed(const struct ovsdb_monitor_table *mt,
|
|
|
|
const unsigned long int *changed)
|
|
|
|
{
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
for (i = 0; i < mt->n_columns; i++) {
|
|
|
|
size_t column_index = mt->columns[i].column->index;
|
|
|
|
|
|
|
|
if (bitmap_is_set(changed, column_index)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Return the efficacy of a row's change to a monitor table.
|
|
|
|
*
|
|
|
|
* Please see the block comment above 'ovsdb_monitor_changes_efficacy'
|
|
|
|
* definition form more information. */
|
|
|
|
static enum ovsdb_monitor_changes_efficacy
|
|
|
|
ovsdb_monitor_changes_classify(enum ovsdb_monitor_selection type,
|
|
|
|
const struct ovsdb_monitor_table *mt,
|
|
|
|
const unsigned long int *changed)
|
|
|
|
{
|
|
|
|
if (type == OJMS_MODIFY &&
|
|
|
|
!ovsdb_monitor_columns_changed(mt, changed)) {
|
|
|
|
return OVSDB_CHANGES_NO_EFFECT;
|
|
|
|
}
|
|
|
|
|
2016-07-18 11:45:52 +03:00
|
|
|
if (type == OJMS_MODIFY) {
|
|
|
|
/* Condition might turn a modify operation to insert or delete */
|
|
|
|
type |= OJMS_INSERT | OJMS_DELETE;
|
|
|
|
}
|
|
|
|
|
2015-06-10 17:11:09 -07:00
|
|
|
return (mt->select & type)
|
|
|
|
? OVSDB_CHANGES_REQUIRE_EXTERNAL_UPDATE
|
|
|
|
: OVSDB_CHANGES_REQUIRE_INTERNAL_UPDATE;
|
|
|
|
}
|
|
|
|
|
2015-03-14 00:40:18 -07:00
|
|
|
static bool
|
|
|
|
ovsdb_monitor_change_cb(const struct ovsdb_row *old,
|
|
|
|
const struct ovsdb_row *new,
|
2015-08-31 09:44:04 -07:00
|
|
|
const unsigned long int *changed,
|
2015-03-14 00:40:18 -07:00
|
|
|
void *aux_)
|
|
|
|
{
|
|
|
|
struct ovsdb_monitor_aux *aux = aux_;
|
|
|
|
const struct ovsdb_monitor *m = aux->monitor;
|
|
|
|
struct ovsdb_table *table = new ? new->table : old->table;
|
|
|
|
struct ovsdb_monitor_table *mt;
|
|
|
|
struct ovsdb_monitor_changes *changes;
|
|
|
|
|
|
|
|
if (!aux->mt || table != aux->mt->table) {
|
|
|
|
aux->mt = shash_find_data(&m->tables, table->schema->name);
|
|
|
|
if (!aux->mt) {
|
|
|
|
/* We don't care about rows in this table at all. Tell the caller
|
|
|
|
* to skip it. */
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
mt = aux->mt;
|
|
|
|
|
2016-07-18 11:45:52 +03:00
|
|
|
enum ovsdb_monitor_selection type =
|
|
|
|
ovsdb_monitor_row_update_type(false, old, new);
|
|
|
|
enum ovsdb_monitor_changes_efficacy efficacy =
|
|
|
|
ovsdb_monitor_changes_classify(type, mt, changed);
|
2015-06-10 17:11:09 -07:00
|
|
|
|
2016-07-18 11:45:52 +03:00
|
|
|
HMAP_FOR_EACH(changes, hmap_node, &mt->changes) {
|
2015-06-10 17:11:09 -07:00
|
|
|
if (efficacy > OVSDB_CHANGES_NO_EFFECT) {
|
|
|
|
ovsdb_monitor_changes_update(old, new, mt, changes);
|
|
|
|
}
|
2016-07-18 11:45:52 +03:00
|
|
|
}
|
|
|
|
if (aux->efficacy < efficacy) {
|
|
|
|
aux->efficacy = efficacy;
|
2015-03-14 00:40:18 -07:00
|
|
|
}
|
2015-06-10 17:11:09 -07:00
|
|
|
|
2015-03-11 21:20:44 -07:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2015-03-17 21:25:20 -07:00
|
|
|
void
|
2015-03-11 21:20:44 -07:00
|
|
|
ovsdb_monitor_get_initial(const struct ovsdb_monitor *dbmon)
|
|
|
|
{
|
|
|
|
struct shash_node *node;
|
|
|
|
|
|
|
|
SHASH_FOR_EACH (node, &dbmon->tables) {
|
|
|
|
struct ovsdb_monitor_table *mt = node->data;
|
|
|
|
|
|
|
|
if (mt->select & OJMS_INITIAL) {
|
|
|
|
struct ovsdb_row *row;
|
2015-03-16 03:03:20 -07:00
|
|
|
struct ovsdb_monitor_changes *changes;
|
2015-03-11 21:20:44 -07:00
|
|
|
|
2015-03-16 03:03:20 -07:00
|
|
|
changes = ovsdb_monitor_table_find_changes(mt, 0);
|
|
|
|
if (!changes) {
|
|
|
|
changes = ovsdb_monitor_table_add_changes(mt, 0);
|
|
|
|
HMAP_FOR_EACH (row, hmap_node, &mt->table->rows) {
|
|
|
|
ovsdb_monitor_changes_update(NULL, row, mt, changes);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
changes->n_refs++;
|
2015-03-11 21:20:44 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2015-04-09 16:39:58 -07:00
|
|
|
ovsdb_monitor_remove_jsonrpc_monitor(struct ovsdb_monitor *dbmon,
|
2016-03-07 15:44:34 -08:00
|
|
|
struct ovsdb_jsonrpc_monitor *jsonrpc_monitor,
|
|
|
|
uint64_t unflushed)
|
2015-04-09 16:39:58 -07:00
|
|
|
{
|
|
|
|
struct jsonrpc_monitor_node *jm;
|
|
|
|
|
2016-03-25 14:10:22 -07:00
|
|
|
if (ovs_list_is_empty(&dbmon->jsonrpc_monitors)) {
|
2015-03-16 03:03:20 -07:00
|
|
|
ovsdb_monitor_destroy(dbmon);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-04-09 16:39:58 -07:00
|
|
|
/* Find and remove the jsonrpc monitor from the list. */
|
|
|
|
LIST_FOR_EACH(jm, node, &dbmon->jsonrpc_monitors) {
|
|
|
|
if (jm->jsonrpc_monitor == jsonrpc_monitor) {
|
2016-03-07 15:44:34 -08:00
|
|
|
/* Release the tracked changes. */
|
|
|
|
struct shash_node *node;
|
|
|
|
SHASH_FOR_EACH (node, &dbmon->tables) {
|
|
|
|
struct ovsdb_monitor_table *mt = node->data;
|
|
|
|
ovsdb_monitor_table_untrack_changes(mt, unflushed);
|
|
|
|
}
|
2016-03-25 14:10:22 -07:00
|
|
|
ovs_list_remove(&jm->node);
|
2015-04-09 16:39:58 -07:00
|
|
|
free(jm);
|
|
|
|
|
|
|
|
/* Destroy ovsdb monitor if this is the last user. */
|
2016-03-25 14:10:22 -07:00
|
|
|
if (ovs_list_is_empty(&dbmon->jsonrpc_monitors)) {
|
2015-04-09 16:39:58 -07:00
|
|
|
ovsdb_monitor_destroy(dbmon);
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Should never reach here. jsonrpc_monitor should be on the list. */
|
|
|
|
OVS_NOT_REACHED();
|
|
|
|
}
|
|
|
|
|
2015-03-16 03:03:20 -07:00
|
|
|
static bool
|
|
|
|
ovsdb_monitor_table_equal(const struct ovsdb_monitor_table *a,
|
|
|
|
const struct ovsdb_monitor_table *b)
|
|
|
|
{
|
|
|
|
size_t i;
|
|
|
|
|
2016-07-18 11:45:51 +03:00
|
|
|
ovs_assert(b->n_columns == b->n_monitored_columns);
|
|
|
|
|
2015-03-16 03:03:20 -07:00
|
|
|
if ((a->table != b->table) ||
|
|
|
|
(a->select != b->select) ||
|
2016-07-18 11:45:51 +03:00
|
|
|
(a->n_monitored_columns != b->n_monitored_columns)) {
|
2015-03-16 03:03:20 -07:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-07-18 11:45:51 +03:00
|
|
|
/* Compare only monitored columns that must be sorted already */
|
|
|
|
for (i = 0; i < a->n_monitored_columns; i++) {
|
2015-03-16 03:03:20 -07:00
|
|
|
if ((a->columns[i].column != b->columns[i].column) ||
|
|
|
|
(a->columns[i].select != b->columns[i].select)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
|
|
|
ovsdb_monitor_equal(const struct ovsdb_monitor *a,
|
|
|
|
const struct ovsdb_monitor *b)
|
|
|
|
{
|
|
|
|
struct shash_node *node;
|
|
|
|
|
|
|
|
if (shash_count(&a->tables) != shash_count(&b->tables)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
SHASH_FOR_EACH(node, &a->tables) {
|
|
|
|
const struct ovsdb_monitor_table *mta = node->data;
|
|
|
|
const struct ovsdb_monitor_table *mtb;
|
|
|
|
|
|
|
|
mtb = shash_find_data(&b->tables, node->name);
|
|
|
|
if (!mtb) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!ovsdb_monitor_table_equal(mta, mtb)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static size_t
|
|
|
|
ovsdb_monitor_hash(const struct ovsdb_monitor *dbmon, size_t basis)
|
|
|
|
{
|
|
|
|
const struct shash_node **nodes;
|
|
|
|
size_t i, j, n;
|
|
|
|
|
|
|
|
nodes = shash_sort(&dbmon->tables);
|
|
|
|
n = shash_count(&dbmon->tables);
|
|
|
|
|
|
|
|
for (i = 0; i < n; i++) {
|
|
|
|
struct ovsdb_monitor_table *mt = nodes[i]->data;
|
|
|
|
|
|
|
|
basis = hash_pointer(mt->table, basis);
|
|
|
|
basis = hash_3words(mt->select, mt->n_columns, basis);
|
|
|
|
|
|
|
|
for (j = 0; j < mt->n_columns; j++) {
|
|
|
|
basis = hash_pointer(mt->columns[j].column, basis);
|
|
|
|
basis = hash_2words(mt->columns[j].select, basis);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
free(nodes);
|
|
|
|
|
|
|
|
return basis;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct ovsdb_monitor *
|
|
|
|
ovsdb_monitor_add(struct ovsdb_monitor *new_dbmon)
|
|
|
|
{
|
|
|
|
struct ovsdb_monitor *dbmon;
|
|
|
|
size_t hash;
|
|
|
|
|
|
|
|
/* New_dbmon should be associated with only one jsonrpc
|
|
|
|
* connections. */
|
2016-03-25 14:10:22 -07:00
|
|
|
ovs_assert(ovs_list_is_singleton(&new_dbmon->jsonrpc_monitors));
|
2015-03-16 03:03:20 -07:00
|
|
|
|
2016-07-18 11:45:49 +03:00
|
|
|
ovsdb_monitor_columns_sort(new_dbmon);
|
|
|
|
|
2015-03-16 03:03:20 -07:00
|
|
|
hash = ovsdb_monitor_hash(new_dbmon, 0);
|
|
|
|
HMAP_FOR_EACH_WITH_HASH(dbmon, hmap_node, hash, &ovsdb_monitors) {
|
|
|
|
if (ovsdb_monitor_equal(dbmon, new_dbmon)) {
|
|
|
|
return dbmon;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
hmap_insert(&ovsdb_monitors, &new_dbmon->hmap_node, hash);
|
|
|
|
return new_dbmon;
|
|
|
|
}
|
|
|
|
|
2015-04-09 16:39:58 -07:00
|
|
|
static void
|
2015-03-11 21:20:44 -07:00
|
|
|
ovsdb_monitor_destroy(struct ovsdb_monitor *dbmon)
|
|
|
|
{
|
|
|
|
struct shash_node *node;
|
|
|
|
|
2016-03-25 14:10:22 -07:00
|
|
|
ovs_list_remove(&dbmon->replica.node);
|
2015-03-11 21:20:44 -07:00
|
|
|
|
2015-03-16 03:03:20 -07:00
|
|
|
if (!hmap_node_is_null(&dbmon->hmap_node)) {
|
|
|
|
hmap_remove(&ovsdb_monitors, &dbmon->hmap_node);
|
|
|
|
}
|
|
|
|
|
2015-03-16 15:45:27 -07:00
|
|
|
ovsdb_monitor_json_cache_flush(dbmon);
|
|
|
|
hmap_destroy(&dbmon->json_cache);
|
|
|
|
|
2015-03-11 21:20:44 -07:00
|
|
|
SHASH_FOR_EACH (node, &dbmon->tables) {
|
|
|
|
struct ovsdb_monitor_table *mt = node->data;
|
2015-03-14 00:40:18 -07:00
|
|
|
struct ovsdb_monitor_changes *changes, *next;
|
2015-03-11 21:20:44 -07:00
|
|
|
|
2015-03-14 00:40:18 -07:00
|
|
|
HMAP_FOR_EACH_SAFE (changes, next, hmap_node, &mt->changes) {
|
|
|
|
hmap_remove(&mt->changes, &changes->hmap_node);
|
|
|
|
ovsdb_monitor_changes_destroy(changes);
|
|
|
|
}
|
2015-10-22 00:08:15 -07:00
|
|
|
hmap_destroy(&mt->changes);
|
2015-03-11 21:20:44 -07:00
|
|
|
free(mt->columns);
|
2016-07-18 11:45:49 +03:00
|
|
|
free(mt->columns_index_map);
|
2015-03-11 21:20:44 -07:00
|
|
|
free(mt);
|
|
|
|
}
|
|
|
|
shash_destroy(&dbmon->tables);
|
|
|
|
free(dbmon);
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct ovsdb_error *
|
|
|
|
ovsdb_monitor_commit(struct ovsdb_replica *replica,
|
|
|
|
const struct ovsdb_txn *txn,
|
|
|
|
bool durable OVS_UNUSED)
|
|
|
|
{
|
|
|
|
struct ovsdb_monitor *m = ovsdb_monitor_cast(replica);
|
|
|
|
struct ovsdb_monitor_aux aux;
|
|
|
|
|
|
|
|
ovsdb_monitor_init_aux(&aux, m);
|
2016-02-22 00:24:06 -08:00
|
|
|
/* Update ovsdb_monitor's transaction number for
|
|
|
|
* each transaction, before calling ovsdb_monitor_change_cb(). */
|
|
|
|
m->n_transactions++;
|
2015-03-11 21:20:44 -07:00
|
|
|
ovsdb_txn_for_each_change(txn, ovsdb_monitor_change_cb, &aux);
|
2015-06-10 17:24:08 -07:00
|
|
|
|
2016-02-22 00:24:06 -08:00
|
|
|
switch(aux.efficacy) {
|
|
|
|
case OVSDB_CHANGES_NO_EFFECT:
|
|
|
|
/* The transaction is ignored by the monitor.
|
|
|
|
* Roll back the 'n_transactions' as if the transaction
|
|
|
|
* has never happened. */
|
|
|
|
m->n_transactions--;
|
|
|
|
break;
|
|
|
|
case OVSDB_CHANGES_REQUIRE_INTERNAL_UPDATE:
|
|
|
|
/* Nothing. */
|
|
|
|
break;
|
|
|
|
case OVSDB_CHANGES_REQUIRE_EXTERNAL_UPDATE:
|
2015-06-10 17:24:08 -07:00
|
|
|
ovsdb_monitor_json_cache_flush(m);
|
2016-02-22 00:24:06 -08:00
|
|
|
break;
|
2015-06-10 17:24:08 -07:00
|
|
|
}
|
2015-03-11 21:20:44 -07:00
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
ovsdb_monitor_destroy_callback(struct ovsdb_replica *replica)
|
|
|
|
{
|
|
|
|
struct ovsdb_monitor *dbmon = ovsdb_monitor_cast(replica);
|
2015-04-09 16:39:58 -07:00
|
|
|
struct jsonrpc_monitor_node *jm, *next;
|
2015-03-11 21:20:44 -07:00
|
|
|
|
2015-04-09 16:39:58 -07:00
|
|
|
/* Delete all front end monitors. Removing the last front
|
|
|
|
* end monitor will also destroy the corresponding 'ovsdb_monitor'.
|
|
|
|
* ovsdb monitor will also be destroied. */
|
|
|
|
LIST_FOR_EACH_SAFE(jm, next, node, &dbmon->jsonrpc_monitors) {
|
|
|
|
ovsdb_jsonrpc_monitor_destroy(jm->jsonrpc_monitor);
|
|
|
|
}
|
2015-03-11 21:20:44 -07:00
|
|
|
}
|
|
|
|
|
2016-02-03 20:57:32 -08:00
|
|
|
/* Add some memory usage statics for monitors into 'usage', for use with
|
|
|
|
* memory_report(). */
|
|
|
|
void
|
|
|
|
ovsdb_monitor_get_memory_usage(struct simap *usage)
|
|
|
|
{
|
2016-03-08 11:54:45 -08:00
|
|
|
struct ovsdb_monitor *dbmon;
|
2016-02-03 20:57:32 -08:00
|
|
|
simap_put(usage, "monitors", hmap_count(&ovsdb_monitors));
|
2016-03-08 11:54:45 -08:00
|
|
|
|
|
|
|
HMAP_FOR_EACH(dbmon, hmap_node, &ovsdb_monitors) {
|
|
|
|
simap_increase(usage, "json-caches", hmap_count(&dbmon->json_cache));
|
|
|
|
}
|
2016-02-03 20:57:32 -08:00
|
|
|
}
|
|
|
|
|
2015-03-11 21:20:44 -07:00
|
|
|
static const struct ovsdb_replica_class ovsdb_jsonrpc_replica_class = {
|
|
|
|
ovsdb_monitor_commit,
|
|
|
|
ovsdb_monitor_destroy_callback,
|
|
|
|
};
|