On Sat, Jan 16, 2016 at 12:16 AM, Liran Schour <lir...@il.ibm.com> wrote:
> Implement function for changing condition in an idl session. > > Signed-off-by: Liran Schour <lir...@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@openvswitch.org > http://openvswitch.org/mailman/listinfo/dev > _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev