[ovs-dev] [PATCH monitor_cond V3 08/10] lib: add monitor_cond_update API to C IDL lib
Liran Schour
LIRANS at il.ibm.com
Sun Feb 7 11:06:40 UTC 2016
Andy Zhou <azhou at ovn.org> wrote on 05/02/2016 01:03:17 PM:
> On Wed, Feb 3, 2016 at 5:53 AM, Liran Schour <lirans at il.ibm.com> wrote:
> Add API that allows the user to create condition iteratively
> and send condition_update to the server.
>
> Signed-off-by: Liran Schour <lirans at il.ibm.com>
>
> ---
> v2->v3:
> * Simplify API to allow iteratively adding clauses to condition
> before send monitor_cond_update
> * monitor_cond_update receives only a single json condition
> * Automaticly generate <dbName>_<tableName)_add_clause_<columnName()
> ---
> lib/ovsdb-idl-provider.h | 13 ++++
> lib/ovsdb-idl.c | 178 ++++++++++++++++++++++++++++++++++++
> ++++++++++-
> lib/ovsdb-idl.h | 34 +++++++++
> ovsdb/ovsdb-idlc.in | 168
++++++++++++++++++++++++++++++++++++++++++++
> 4 files changed, 392 insertions(+), 1 deletion(-)
>
> diff --git a/lib/ovsdb-idl-provider.h b/lib/ovsdb-idl-provider.h
> index 190acca..1288ad3 100644
> --- a/lib/ovsdb-idl-provider.h
> +++ b/lib/ovsdb-idl-provider.h
> @@ -51,6 +51,18 @@ struct ovsdb_idl_column {
> void (*unparse)(struct ovsdb_idl_row *);
> };
>
> +struct ovsdb_idl_condition {
> + const struct ovsdb_idl_table_class *tc;
> + struct ovs_list clauses;
> +};
> +
> +struct ovsdb_idl_clause {
> + struct ovs_list node;
> + enum ovsdb_idl_function function;
> + const struct ovsdb_idl_column *column;
> + struct ovsdb_datum arg;
> +};
> +
> struct ovsdb_idl_table_class {
> char *name;
> bool is_root;
> @@ -70,6 +82,7 @@ struct ovsdb_idl_table {
> struct ovsdb_idl *idl; /* Containing idl. */
> unsigned int change_seqno[OVSDB_IDL_CHANGE_MAX];
> struct ovs_list track_list; /* Tracked rows
> (ovsdb_idl_row.track_node). */
> + struct ovsdb_idl_condition condition;
> };
>
> struct ovsdb_idl_class {
> diff --git a/lib/ovsdb-idl.c b/lib/ovsdb-idl.c
> index a05b420..513b23f 100644
> --- a/lib/ovsdb-idl.c
> +++ b/lib/ovsdb-idl.c
> @@ -261,6 +261,7 @@ ovsdb_idl_create(const char *remote, const
> struct ovsdb_idl_class *class,
> = table->change_seqno[OVSDB_IDL_CHANGE_MODIFY]
> = table->change_seqno[OVSDB_IDL_CHANGE_DELETE] = 0;
> table->idl = idl;
> + ovsdb_idl_condition_init(&table->condition, tc);
> }
>
> idl->state_seqno = UINT_MAX;
> @@ -646,6 +647,176 @@ ovsdb_idl_add_table(struct ovsdb_idl *idl,
> OVS_NOT_REACHED();
> }
>
> +struct ovsdb_error *
> +ovsdb_idl_function_from_string(const char *name,
> + enum ovsdb_idl_function *function)
> +{
> +#define OVSDB_IDL_FUNCTION(ENUM, NAME) \
> + if (!strcmp(name, NAME)) { \
> + *function = ENUM; \
> + return NULL; \
> + }
> + OVSDB_IDL_FUNCTIONS;
> +#undef OVSDB_IDL_FUNCTION
> +
> + return ovsdb_syntax_error(NULL, "unknown function",
> + "No function named %s.", name);
> +}
> +
> +static const char *
> +ovsdb_idl_function_to_string(enum ovsdb_idl_function function)
> +{
> + switch (function) {
> +#define OVSDB_IDL_FUNCTION(ENUM, NAME) case ENUM: return NAME;
> + OVSDB_IDL_FUNCTIONS;
> +#undef OVSDB_IDL_FUNCTION
> + }
> +
> + return NULL;
> +}
> +
> +static void
> +ovsdb_idl_condition_merge(struct ovsdb_idl_condition *a,
> + struct ovsdb_idl_condition *b)
> +{
> + while(!list_is_empty(&b->clauses)) {
> + list_push_back(&a->clauses, list_pop_front(&b->clauses));
> + }
> +}
> +
> +static struct json *
> +ovsdb_idl_clause_to_json(const struct ovsdb_idl_clause *clause)
> +{
> + if (clause->function != OVSDB_IDL_F_TRUE &&
> + clause->function != OVSDB_IDL_F_FALSE) {
> + const char *function = ovsdb_idl_function_to_string
> (clause->function);
> +
> + return
json_array_create_3(json_string_create(clause->column->name),
> + json_string_create(function),
> + ovsdb_datum_to_json(&clause->arg,
> +
> &clause->column->type));
> + }
> +
> + return json_boolean_create(clause->function == OVSDB_IDL_F_TRUE ?
> + true : false);
> +}
> +
> +static void
> +ovsdb_idl_clause_free(struct ovsdb_idl_clause *clause)
> +{
> + if (clause->function != OVSDB_IDL_F_TRUE &&
> + clause->function != OVSDB_IDL_F_FALSE) {
> + ovsdb_datum_destroy(&clause->arg, &clause->column->type);
> + }
> +
> + list_remove(&clause->node);
> + free(clause);
> +}
> +
> +void
> +ovsdb_idl_condition_destroy(struct ovsdb_idl_condition *cnd)
> +{
> + struct ovsdb_idl_clause *c, *next;
> +
> + LIST_FOR_EACH_SAFE (c, next, node, &cnd->clauses) {
> + ovsdb_idl_clause_free(c);
> + }
> +}
> +
> +void
> +ovsdb_idl_condition_init(struct ovsdb_idl_condition *cnd,
> + const struct ovsdb_idl_table_class *tc)
> +{
> + cnd->tc = tc;
> + list_init(&cnd->clauses);
> +}
> +
> +void ovsdb_idl_condition_add_clause(struct ovsdb_idl_condition *cnd,
> + enum ovsdb_idl_function function,
> + const struct ovsdb_idl_column
*column,
> + struct ovsdb_datum *arg)
> +{
> + struct ovsdb_idl_clause *clause = xzalloc(sizeof *clause);
> + const struct ovsdb_type *type = NULL;
> +
> + list_init(&clause->node);
> + clause->function = function;
> + clause->column = column;
> + if (column) {
> + type = &column->type;
> + } else {
> + type = &ovsdb_type_boolean;
> + }
> + ovsdb_datum_clone(&clause->arg, arg, type);
> + list_push_back(&cnd->clauses, &clause->node);
> +}
> +
> +static struct json *
> +ovsdb_idl_condition_to_json(const struct ovsdb_idl_condition *cnd)
> +{
> + struct json **clauses;
> + size_t i = 0, n_clauses = list_size(&cnd->clauses);
> + struct ovsdb_idl_clause *c;
> +
> + clauses = xmalloc(n_clauses * sizeof *clauses);
> + LIST_FOR_EACH (c, node, &cnd->clauses) {
> + clauses[i++] = ovsdb_idl_clause_to_json(c);
> + }
> +
> + return json_array_create(clauses, n_clauses);
> +}
> +
> +static void
> +ovsdb_idl_send_cond_update__(struct ovsdb_idl *idl,
> + struct ovsdb_idl_table *table,
> + const struct ovsdb_idl_condition *cond)
> +{
> + char uuid[UUID_LEN + 1];
> + struct json *monitor_cond_update_requests = json_object_create();
> + struct json *monitor_cond_update_request = json_object_create();
> + struct json *cond_json = ovsdb_idl_condition_to_json(cond);
> + struct json *params, *json_uuid;
> + struct jsonrpc_msg *request;
> +
> + json_object_put(monitor_cond_update_request, "where", cond_json);
> + json_object_put(monitor_cond_update_requests,
> + table->class->name,
> + json_array_create_1(monitor_cond_update_request));
> +
> + snprintf(uuid, sizeof uuid, UUID_FMT,
> + UUID_ARGS(&idl->uuid));
> + json_uuid = json_string_create(uuid);
> +
> + /* Create a new uuid */
> + uuid_generate(&idl->uuid);
> + snprintf(uuid, sizeof uuid, UUID_FMT,
> + UUID_ARGS(&idl->uuid));
> + params = json_array_create_3(json_uuid, json_string_create(uuid),
> + monitor_cond_update_requests);
> +
> + request = jsonrpc_create_request("monitor_cond_update", params,
NULL);
> + jsonrpc_session_send(idl->session, request);
> +}
> +
> +/* Add conditions to the replicated tables. Ensure that tables are
> added to the
> + * replication.
> + */
> +bool
> +ovsdb_idl_cond_update(struct ovsdb_idl *idl,
> + struct ovsdb_idl_condition *cond)
> +{
> + struct ovsdb_idl_table *table;
> +
> + table = ovsdb_idl_table_from_class(idl, cond->tc);
> +
> + if (jsonrpc_session_is_connected(idl->session)) {
> + ovsdb_idl_send_cond_update__(idl, table, cond);
> + } else {
> + ovsdb_idl_condition_merge(&table->condition, cond);
> + }
> + return true;
> +}
> This interface seems to allow only condition updates to one table at
> a time. Did I mss something
> here? Also in patch 10. I did not find a test that covers updates
> with multiple tables.
The user can update one table on each ovsdb_idl_cond_update() call and can
do it iteratively on many tables. I think this API is good enough. (I
tested it to change the SB monitoring in ovn-controller to be
conditional).
Will add test that covers cond_update with multiple tables.
> +
> /* Turns off OVSDB_IDL_ALERT for 'column' in 'idl'.
> *
> * This function should be called between ovsdb_idl_create() and
> the first call
> @@ -945,7 +1116,7 @@ ovsdb_idl_send_monitor_request__(struct ovsdb_idl
*idl,
> for (i = 0; i < idl->class->n_tables; i++) {
> const struct ovsdb_idl_table *table = &idl->tables[i];
> const struct ovsdb_idl_table_class *tc = table->class;
> - struct json *monitor_request, *columns;
> + struct json *monitor_request, *columns, *where;
> const struct sset *table_schema;
> size_t j;
>
> @@ -983,6 +1154,11 @@ ovsdb_idl_send_monitor_request__(struct ovsdb_idl
*idl,
>
> monitor_request = json_object_create();
> json_object_put(monitor_request, "columns", columns);
> + if (!strcmp(method, "monitor_cond") &&
> + list_size(&table->condition.clauses) > 0) {
> + where = ovsdb_idl_condition_to_json(&table->condition);
> + json_object_put(monitor_request, "where", where);
> + }
> json_object_put(monitor_requests, tc->name,
monitor_request);
> }
> }
> diff --git a/lib/ovsdb-idl.h b/lib/ovsdb-idl.h
> index 1cbaf35..c93fdf3 100644
> --- a/lib/ovsdb-idl.h
> +++ b/lib/ovsdb-idl.h
> @@ -45,6 +45,7 @@ struct ovsdb_idl_class;
> struct ovsdb_idl_row;
> struct ovsdb_idl_column;
> struct ovsdb_idl_table_class;
> +struct ovsdb_idl_condition;
> struct uuid;
>
> struct ovsdb_idl *ovsdb_idl_create(const char *remote,
> @@ -277,4 +278,37 @@ void ovsdb_idl_loop_destroy(struct ovsdb_idl_loop
*);
> struct ovsdb_idl_txn *ovsdb_idl_loop_run(struct ovsdb_idl_loop *);
> void ovsdb_idl_loop_commit_and_wait(struct ovsdb_idl_loop *);
>
> +/* These list is ordered in ascending order of the fraction of
> tables row that
> + * they are (heuristically) expected to leave in query results. */
> +#define OVSDB_IDL_FUNCTIONS \
> + OVSDB_IDL_FUNCTION(OVSDB_IDL_F_FALSE, "false") \
> + OVSDB_IDL_FUNCTION(OVSDB_IDL_F_TRUE, "true") \
> + OVSDB_IDL_FUNCTION(OVSDB_IDL_F_EQ, "==") \
> + OVSDB_IDL_FUNCTION(OVSDB_IDL_F_INCLUDES, "includes") \
> + OVSDB_IDL_FUNCTION(OVSDB_IDL_F_LE, "<=") \
> + OVSDB_IDL_FUNCTION(OVSDB_IDL_F_LT, "<") \
> + OVSDB_IDL_FUNCTION(OVSDB_IDL_F_GE, ">=") \
> + OVSDB_IDL_FUNCTION(OVSDB_IDL_F_GT, ">") \
> + OVSDB_IDL_FUNCTION(OVSDB_IDL_F_EXCLUDES, "excludes") \
> + OVSDB_IDL_FUNCTION(OVSDB_IDL_F_NE, "!=")
> +
> +enum ovsdb_idl_function {
> +#define OVSDB_IDL_FUNCTION(ENUM, NAME) ENUM,
> + OVSDB_IDL_FUNCTIONS
> +#undef OVSDB_IDL_FUNCTION
> +};
> +
> +void ovsdb_idl_condition_init(struct ovsdb_idl_condition *cnd,
> + const struct ovsdb_idl_table_class *tc);
> +void ovsdb_idl_condition_destroy(struct ovsdb_idl_condition *cnd);
> +void ovsdb_idl_condition_add_clause(struct ovsdb_idl_condition *cnd,
> + enum ovsdb_idl_function function,
> + const struct ovsdb_idl_column
*column,
> + struct ovsdb_datum *arg);
> +bool ovsdb_idl_cond_update(struct ovsdb_idl *idl,
> + struct ovsdb_idl_condition *cond);
> +
> +struct ovsdb_error *
> +ovsdb_idl_function_from_string(const char *name,
> + enum ovsdb_idl_function *function);
> #endif /* ovsdb-idl.h */
> diff --git a/ovsdb/ovsdb-idlc.in b/ovsdb/ovsdb-idlc.in
> index 26b0de4..596c2a7 100755
> --- a/ovsdb/ovsdb-idlc.in
> +++ b/ovsdb/ovsdb-idlc.in
> @@ -216,6 +216,20 @@ bool %(s)s_is_updated(const struct %(s)s *,
> enum %(s)s_column_id);
> print '%s);' % ', '.join(args)
>
> print
> + for columnName, column in sorted(table.columns.iteritems()):
> + print 'void %(s)s_add_clause_%(c)s(struct
> ovsdb_idl_condition *, enum ovsdb_idl_function function,' % {'s':
> structName, 'c': columnName},
> + if column.type.is_smap():
> + args = ['const struct smap *']
> + else:
> + comment, members = cMembers(prefix, tableName,
columnName,
> + column, True)
> + args = ['%(type)s%(name)s' % member for member in
members]
> + print '%s);' % ', '.join(args)
> +
> + print 'void %s_add_clause_true(struct ovsdb_idl_condition
> *);' % structName
> + print 'void %s_add_clause_false(struct ovsdb_idl_condition
> *);' % structName
> +
> + print
>
> # Table indexes.
> printEnum("%stable_id" % prefix.lower(), ["%sTABLE_%s" %
> (prefix.upper(), tableName.upper()) for tableName in sorted
> (schema.tables)] + ["%sN_TABLES" % prefix.upper()])
> @@ -747,6 +761,160 @@ const struct ovsdb_datum *
> 'C': columnName.upper()}
> print "}"
>
> + # Add clause functions.
> + for columnName, column in sorted(table.columns.iteritems()):
> + type = column.type
> +
> + comment, members = cMembers(prefix, tableName, columnName,
> + column, True)
> +
> + if type.is_smap():
> + print comment
> + print """void
> +%(s)s_add_clause_%(c)s(struct ovsdb_idl_condition *cnd, enum
> ovsdb_idl_function function, const struct smap *%(c)s)
> +{
> + struct ovsdb_datum datum;
> +
> + ovs_assert(inited);
> + if (%(c)s) {
> + struct smap_node *node;
> + size_t i;
> +
> + datum.n = smap_count(%(c)s);
> + datum.keys = xmalloc(datum.n * sizeof *datum.keys);
> + datum.values = xmalloc(datum.n * sizeof *datum.values);
> +
> + i = 0;
> + SMAP_FOR_EACH (node, %(c)s) {
> + datum.keys[i].string = xstrdup(node->key);
> + datum.values[i].string = xstrdup(node->value);
> + i++;
> + }
> + ovsdb_datum_sort_unique(&datum, OVSDB_TYPE_STRING,
> OVSDB_TYPE_STRING);
> + } else {
> + ovsdb_datum_init_empty(&datum);
> + }
> +
> + ovsdb_idl_condition_add_clause(cnd,
> + function,
> + &%(s)s_columns[%(S)s_COL_%(C)s],
> + &datum);
> +}
> +""" % {'t': tableName,
> + 's': structName,
> + 'S': structName.upper(),
> + 'c': columnName,
> + 'C': columnName.upper()}
> + continue
> +
> + keyVar = members[0]['name']
> + nVar = None
> + valueVar = None
> + if type.value:
> + valueVar = members[1]['name']
> + if len(members) > 2:
> + nVar = members[2]['name']
> + else:
> + if len(members) > 1:
> + nVar = members[1]['name']
> +
> + print comment
> + print 'void'
> + print '%(s)s_add_clause_%(c)s(struct
> ovsdb_idl_condition *cnd, enum ovsdb_idl_function function, %(args)s)' %
\
> + {'s': structName, 'c': columnName,
> + 'args': ', '.join(['%(type)s%(name)s' % m for m
inmembers])}
> + print "{"
> + print " struct ovsdb_datum datum;"
> + if type.n_min == 1 and type.n_max == 1:
> + print " union ovsdb_atom key;"
> + if type.value:
> + print " union ovsdb_atom value;"
> + print
> + print " ovs_assert(inited);"
> + print " datum.n = 1;"
> + print " datum.keys = &key;"
> + print " " +
> type.key.assign_c_value_casting_away_const("key.%s" %
> type.key.type.to_string(), keyVar)
> + if type.value:
> + print " datum.values = &value;"
> + print " "+
> type.value.assign_c_value_casting_away_const("value.%s" %
> type.value.type.to_string(), valueVar)
> + else:
> + print " datum.values = NULL;"
> + elif type.is_optional_pointer():
> + print " union ovsdb_atom key;"
> + print
> + print " ovs_assert(inited);"
> + print " if (%s) {" % keyVar
> + print " datum.n = 1;"
> + print " datum.keys = &key;"
> + print " " +
> type.key.assign_c_value_casting_away_const("key.%s" %
> type.key.type.to_string(), keyVar)
> + print " } else {"
> + print " datum.n = 0;"
> + print " datum.keys = NULL;"
> + print " }"
> + print " datum.values = NULL;"
> + elif type.n_max == 1:
> + print " union ovsdb_atom key;"
> + print
> + print " ovs_assert(inited);"
> + print " if (%s) {" % nVar
> + print " datum.n = 1;"
> + print " datum.keys = &key;"
> + print " " +
> type.key.assign_c_value_casting_away_const("key.%s" %
> type.key.type.to_string(), "*" + keyVar)
> + print " } else {"
> + print " datum.n = 0;"
> + print " datum.keys = NULL;"
> + print " }"
> + print " datum.values = NULL;"
> + else:
> + print " size_t i;"
> + print
> + print " ovs_assert(inited);"
> + print " datum.n = %s;" % nVar
> + print " datum.keys = %s ? xmalloc(%s * sizeof
> *datum.keys) : NULL;" % (nVar, nVar)
> + if type.value:
> + print " datum.values = xmalloc(%s * sizeof
> *datum.values);" % nVar
> + else:
> + print " datum.values = NULL;"
> + print " for (i = 0; i < %s; i++) {" % nVar
> + print " " + type.key.copyCValue("datum.keys
> [i].%s" % type.key.type.to_string(), "%s[i]" % keyVar)
> + if type.value:
> + print " " + type.value.copyCValue
> ("datum.values[i].%s" % type.value.type.to_string(), "%s[i]" % valueVar)
> + print " }"
> + if type.value:
> + valueType = type.value.toAtomicType()
> + else:
> + valueType = "OVSDB_TYPE_VOID"
> + print " ovsdb_datum_sort_unique(&datum, %s, %s);" %
(
> + type.key.toAtomicType(), valueType)
> +
> + print""" ovsdb_idl_condition_add_clause(cnd,
> + function,
> + &%(s)s_columns[%(S)s_COL_%(C)s],
> + &datum);
> +}""" % {'t': tableName,
> + 's': structName,
> + 'S': structName.upper(),
> + 'c': columnName,
> + 'C': columnName.upper()}
> +
> + print """void
> +%s_add_clause_false(struct ovsdb_idl_condition *cnd)
> +{
> + struct ovsdb_datum datum;
> +
> + ovsdb_datum_init_empty(&datum);
> + ovsdb_idl_condition_add_clause(cnd, OVSDB_IDL_F_FALSE, NULL,
&datum);
> +}""" % structName
> +
> + print """void
> +%s_add_clause_true(struct ovsdb_idl_condition *cnd)
> +{
> + struct ovsdb_datum datum;
> +
> + ovsdb_datum_init_empty(&datum);
> + ovsdb_idl_condition_add_clause(cnd, OVSDB_IDL_F_TRUE, NULL,
&datum);
> +}""" % structName
> +
> # Table columns.
> print "\nstruct ovsdb_idl_column %s_columns[%s_N_COLUMNS];" % (
> structName, structName.upper())
> --
> 2.1.4
>
>
> _______________________________________________
> dev mailing list
> dev at openvswitch.org
> http://openvswitch.org/mailman/listinfo/dev
More information about the dev
mailing list