[ovs-dev] [PATCH monitor_cond V2 10/12] lib: add monitor_cond_update to idl session
Andy Zhou
azhou at ovn.org
Fri Jan 22 03:55:45 UTC 2016
On Sat, Jan 16, 2016 at 12:16 AM, Liran Schour <lirans at il.ibm.com> wrote:
> Implement function for changing condition in an idl session.
>
> Signed-off-by: Liran Schour <lirans at il.ibm.com>
>
Tabs are used in this file.
> ---
> lib/ovsdb-idl-provider.h | 33 ++++
> lib/ovsdb-idl.c | 399
> ++++++++++++++++++++++++++++++++++++++++++++++-
> lib/ovsdb-idl.h | 13 ++
> 3 files changed, 444 insertions(+), 1 deletion(-)
>
> diff --git a/lib/ovsdb-idl-provider.h b/lib/ovsdb-idl-provider.h
> index 190acca..2722922 100644
> --- a/lib/ovsdb-idl-provider.h
> +++ b/lib/ovsdb-idl-provider.h
> @@ -51,6 +51,38 @@ struct ovsdb_idl_column {
> void (*unparse)(struct ovsdb_idl_row *);
> };
>
> +
> +/* 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
> +};
> +
> +struct ovsdb_idl_clause {
> + enum ovsdb_idl_function function;
> + const struct ovsdb_idl_column *column;
> + struct ovsdb_datum arg;
> +};
> +
> +struct ovsdb_idl_condition {
> + struct ovsdb_idl_clause *clauses;
> + size_t n_clauses;
> +};
> +
> struct ovsdb_idl_table_class {
> char *name;
> bool is_root;
> @@ -70,6 +102,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 1b8731e..c3550b9 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);
> }
>
> idl->state_seqno = UINT_MAX;
> @@ -650,6 +651,397 @@ ovsdb_idl_add_table(struct ovsdb_idl *idl,
> OVS_NOT_REACHED();
> }
>
> +static const struct ovsdb_idl_table_class *
> +ovsdb_idl_table_name_to_class(struct ovsdb_idl *idl, const char *name)
> +{
> + int i;
> + struct ovsdb_idl_table *table;
> +
> + /* Ensure table are being replicated */
> + for (i = 0; i < idl->class->n_tables; i++) {
> + table = &idl->tables[i];
> +
> + if (strcmp(table->class->name, name) == 0) {
> + return table->class;
> + }
> + }
> + return NULL;
> +}
> +
> +static const struct ovsdb_idl_column *
> +ovsdb_table_get_column(const struct ovsdb_idl_table_class *tc, const char
> *name)
> +{
> + int i;
> +
> + for (i = 0; i < tc->n_columns; i++) {
> + if(!strcmp(tc->columns[i].name, name)) {
> + return &tc->columns[i];
> + }
> + }
> + return NULL;
> +}
> +
> +static 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 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);
> + }
> +}
> +
> +void
> +ovsdb_idl_condition_destroy(struct ovsdb_idl_condition *cnd)
> +{
> + size_t i;
> +
> + for (i = 0; i < cnd->n_clauses; i++) {
> + ovsdb_idl_clause_free(&cnd->clauses[i]);
> + }
> + free(cnd->clauses);
> + cnd->n_clauses = 0;
> +}
> +
> +void
> +ovsdb_idl_condition_init(struct ovsdb_idl_condition *cnd)
> +{
> + cnd->clauses = NULL;
> + cnd->n_clauses = 0;
> +}
> +
> +static int
> +compare_clauses(const void *a_, const void *b_)
> +{
> + const struct ovsdb_idl_clause *a = a_;
> + const struct ovsdb_idl_clause *b = b_;
> +
> + if (a->function != b->function) {
> + return a->function < b->function ? -1 : 1;
> + } else if (a->function == OVSDB_IDL_F_TRUE ||
> + a->function == OVSDB_IDL_F_FALSE) {
> + return 0;
> + } else if (strcmp(a->column->name, b->column->name)) {
> + return strcmp(a->column->name, b->column->name);
> + } else {
> + return ovsdb_datum_compare_3way(&a->arg, &b->arg,
> &a->column->type);
> + }
> + OVS_NOT_REACHED();
> +}
> +
> +static int
> +ovsdb_idl_clause_exists(const struct ovsdb_idl_condition *cnd,
> + const struct ovsdb_idl_clause *clause)
> +{
> + size_t i;
> +
> + for (i=0; i < cnd->n_clauses; i++) {
> + if(!compare_clauses(&cnd->clauses[i], clause)) {
> + return i;
> + }
> + }
> +
> + return -1;
> +}
> +
> +static void
> +ovsdb_idl_clone_clause(struct ovsdb_idl_clause *new,
> + struct ovsdb_idl_clause *old)
> +{
> + new->function = old->function;
> + if (new->function == OVSDB_IDL_F_TRUE ||
> + new->function ==OVSDB_IDL_F_FALSE) {
> + return;
> + }
> + new->column = old->column;
> + ovsdb_datum_clone(&new->arg,
> + &old->arg,
> + &old->column->type);
> +}
> +
> +static void
> +ovsdb_idl_condition_add(struct ovsdb_idl_condition *to,
> + const struct ovsdb_idl_condition *add)
> +{
> + size_t i, count = 0;
> + struct ovsdb_idl_clause *clauses;
> + unsigned long int *clause_map =
> xzalloc(bitmap_n_bytes(add->n_clauses));
> + int index = to->n_clauses;;
> +
> + for (i = 0; i < add->n_clauses; i++) {
> + if (ovsdb_idl_clause_exists(to, &add->clauses[i]) == -1) {
> + bitmap_set1(clause_map, i);
> + count++;
> + }
> + }
> +
> + if (!count) {
> + free(clause_map);
> + return;
> + }
> + clauses = xzalloc((to->n_clauses + count) * sizeof *clauses);
> +
> + for (i = 0; i < to->n_clauses; i++) {
> + ovsdb_idl_clone_clause(&clauses[i], &to->clauses[i]);
> + ovsdb_idl_clause_free(&to->clauses[i]);
> + }
> +
> + for (i = 0; i < add->n_clauses; i++) {
> + if (bitmap_is_set(clause_map, i)) {
> + ovsdb_idl_clone_clause(&clauses[index++], &add->clauses[i]);
> + }
> + }
> +
> + free(to->clauses);
> + free(clause_map);
> + to->clauses = clauses;
> + to->n_clauses += count;
> +}
> +
> +static struct json *
> +ovsdb_idl_condition_to_json(const struct ovsdb_idl_condition *cnd)
> +{
> + struct json **clauses;
> + size_t i;
> +
> + clauses = xmalloc(cnd->n_clauses * sizeof *clauses);
> + for (i = 0; i < cnd->n_clauses; i++) {
> + clauses[i] = ovsdb_idl_clause_to_json(&cnd->clauses[i]);
> + }
> + return json_array_create(clauses, cnd->n_clauses);
> +}
> +
> +static struct ovsdb_error *
> +ovsdb_idl_clause_from_json(const struct ovsdb_idl_table_class *tc,
> + const struct json *json,
> + struct ovsdb_idl_clause *clause)
> +{
> + const struct json_array *array;
> + struct ovsdb_error *error;
> + const char *function_name;
> + const char *column_name;
> + struct ovsdb_type type;
> +
> + if (json->type == JSON_TRUE || json->type == JSON_FALSE) {
> + /* column and arg fields are not being used with boolean function
> */
> + function_name = (json->type == JSON_TRUE) ? "true" : "false";
> + error = ovsdb_idl_function_from_string(function_name,
> &clause->function);
> +
> + return error;
> + }
> +
> + if (json->type != JSON_ARRAY
> + || json->u.array.n != 3
> + || json->u.array.elems[0]->type != JSON_STRING
> + || json->u.array.elems[1]->type != JSON_STRING) {
> + return ovsdb_syntax_error(json, NULL, "Parse error in
> condition.");
> + }
> + array = json_array(json);
> +
> + column_name = json_string(array->elems[0]);
> + clause->column = ovsdb_table_get_column(tc, column_name);
> + if (!clause->column) {
> + return ovsdb_syntax_error(json, "unknown column",
> + "No column %s in table %s.",
> + column_name, tc->name);
> + }
> + type = clause->column->type;
> +
> + function_name = json_string(array->elems[1]);
> + error = ovsdb_idl_function_from_string(function_name,
> &clause->function);
> + if (error) {
> + return error;
> + }
> +
> + /* Type-check and relax restrictions on 'type' if appropriate. */
> + switch (clause->function) {
> + case OVSDB_IDL_F_LT:
> + case OVSDB_IDL_F_LE:
> + case OVSDB_IDL_F_GT:
> + case OVSDB_IDL_F_GE:
> + /* Allow these operators for types with n_min == 0, n_max == 1.
> + * (They will always be "false" if the value is missing.) */
> + if (!(ovsdb_type_is_scalar(&type)
> + || ovsdb_type_is_optional_scalar(&type))
> + || (type.key.type != OVSDB_TYPE_INTEGER
> + && type.key.type != OVSDB_TYPE_REAL)) {
> + char *s = ovsdb_type_to_english(&type);
> + error = ovsdb_syntax_error(
> + json, NULL, "Type mismatch: \"%s\" operator may not be "
> + "applied to column %s of type %s.",
> + ovsdb_idl_function_to_string(clause->function),
> + clause->column->name, s);
> + free(s);
> + return error;
> + }
> + break;
> + case OVSDB_IDL_F_TRUE:
> + case OVSDB_IDL_F_FALSE:
> + case OVSDB_IDL_F_EQ:
> + case OVSDB_IDL_F_NE:
> + break;
> +
> + case OVSDB_IDL_F_EXCLUDES:
> + if (!ovsdb_type_is_scalar(&type)) {
> + type.n_min = 0;
> + type.n_max = UINT_MAX;
> + }
> + break;
> +
> + case OVSDB_IDL_F_INCLUDES:
> + if (!ovsdb_type_is_scalar(&type)) {
> + type.n_min = 0;
> + }
> + break;
> + }
> + return ovsdb_datum_from_json(&clause->arg, &type, array->elems[2],
> NULL);
> +}
> +
> +struct ovsdb_error *
> +ovsdb_idl_condition_from_json(struct ovsdb_idl *idl,
> + const char *table_name,
> + const struct json *json,
> + struct ovsdb_idl_condition *cnd)
> +{
> + const struct ovsdb_idl_table_class *table_class =
> + ovsdb_idl_table_name_to_class(idl, table_name);
> + const struct json_array *array = json_array(json);
> + struct ovsdb_error *error;
> + size_t i;
> +
> + if (!table_class) {
> + error = ovsdb_syntax_error(NULL, NULL, "Error finding table %s ",
> + table_name);
> + return error;
> + }
> +
> + cnd->clauses = xzalloc(array->n * sizeof *cnd->clauses);
> + cnd->n_clauses = 0;
> + for (i = 0; i < array->n; i++) {
> + struct ovsdb_error *error;
> + error = ovsdb_idl_clause_from_json(table_class, array->elems[i],
> + &cnd->clauses[i]);
> + if (error) {
> + ovsdb_idl_condition_destroy(cnd);
> + cnd->clauses = NULL;
> + cnd->n_clauses = 0;
> + return error;
> + }
> + cnd->n_clauses++;
> + }
> +
> + return NULL;
> +}
> +
> +static void
> +ovsdb_idl_send_cond_update__(struct ovsdb_idl *idl,
> + struct ovsdb_idl_table *table,
> + const struct ovsdb_idl_condition *add,
> + const struct ovsdb_idl_condition *remove)
> +{
> + 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 *added = ovsdb_idl_condition_to_json(add);
> + struct json *removed = ovsdb_idl_condition_to_json(remove);
> + struct json *params, *json_uuid;
> + struct jsonrpc_msg *request;
> +
> + json_object_put(monitor_cond_update_request, "added", added);
> + json_object_put(monitor_cond_update_request, "removed", removed);
> + 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);
>
How should we handle any on going update2 message of the old condition?
+ 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,
> + const char *table_name,
> + const struct ovsdb_idl_condition *add,
> + const struct ovsdb_idl_condition *remove)
> +{
> + const struct ovsdb_idl_table_class *table_class =
> + ovsdb_idl_table_name_to_class(idl, table_name);
> + struct ovsdb_idl_table *table;
> +
> + if (table_class == NULL) {
> + return false;
> + }
> + table = ovsdb_idl_table_from_class(idl, table_class);
> +
> + if (jsonrpc_session_is_connected(idl->session)) {
> + ovsdb_idl_send_cond_update__(idl, table, add, remove);
> + } else {
> + if (remove && remove->n_clauses > 0) {
> + /* No remove conditions on an unconnected session */
> + return false;
> + }
> + ovsdb_idl_condition_add(&table->condition, add);
> + }
> + return true;
> +}
> +
> /* Turns off OVSDB_IDL_ALERT for 'column' in 'idl'.
> *
> * This function should be called between ovsdb_idl_create() and the
> first call
> @@ -949,7 +1341,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;
>
> @@ -987,6 +1379,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") &&
> + table->condition.n_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..413da7d 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,
> @@ -276,5 +277,17 @@ struct ovsdb_idl_loop {
> 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 *);
> +#define OVSDB_IDL_CONDITION_INITIALIZER { NULL, 0 }
> +void ovsdb_idl_condition_init(struct ovsdb_idl_condition *cnd);
> +void ovsdb_idl_condition_destroy(struct ovsdb_idl_condition *cnd);
> +struct ovsdb_error *
> +ovsdb_idl_condition_from_json(struct ovsdb_idl *idl,
> + const char *table_name,
> + const struct json *json,
> + struct ovsdb_idl_condition *cnd);
> +bool ovsdb_idl_cond_update(struct ovsdb_idl *idl,
> + const char *table_name,
> + const struct ovsdb_idl_condition *add,
> + const struct ovsdb_idl_condition *remove);
>
> #endif /* ovsdb-idl.h */
> --
> 2.1.4
>
>
> _______________________________________________
> dev mailing list
> dev at openvswitch.org
> http://openvswitch.org/mailman/listinfo/dev
>
More information about the dev
mailing list