Andy Zhou <az...@ovn.org> wrote on 21/01/2016 11:27:42 AM: > On Sat, Jan 16, 2016 at 12:16 AM, Liran Schour <lir...@il.ibm.com> wrote: > <condition> now is a 3-element json array or a boolean value, see > ovsdb-server(1) man page. This functions will be used for > conditional monitoring sessions. > > Signed-off-by: Liran Schour <lir...@il.ibm.com> > --- > ovsdb/condition.c | 270 ++++++++++++++++++++++++++++++++++++ > +++++++++-- > ovsdb/condition.h | 28 ++++- > ovsdb/query.c | 4 +- > tests/ovsdb-condition.at | 35 +++++- > tests/test-ovsdb.c | 29 ++++- > 5 files changed, 348 insertions(+), 18 deletions(-)
> From the last review: > > Should any columns within schema be allowed in condition? or only > > the ones being monitored? > > From protocol viewpoint, it would make sense to allow any column. > > > > Yes, any columns should be allowed in condition. > > I did not find the implementation to match this. The values used to > conditional comparison is coming > from the monitored table rows, this is required to be part of the > monitored columns? Also tested and verified > that monitor_cond does not work if where clause contains columns not > being monitored. > > It would be nice to clearly define which columns are allowed in the > where clause. > > I suppose if the implementation actually allows any column, than > there may not be a need for > 'columns_index_map' introduced from the last patch. > You are right. We have 2 options to fix it: 1. Save in ovsdb_monitor_row all the columns in the db and mark the columns needs to be monitored. Then we will not need the 'columns_index_map' also. 2. If a none monitored column is included in a condition then add this columns to mt->columns and mark it as only for condition evaluation. In this case we do need the 'columns_index_map'. I prefer option 1 as being simpler and save indexing mapping issue. What do you think? > The commit message is slightly misleading since ovsdb-server(1) > changes are not contained within this patch, > but in a later patch. > Right will remove this from message. > diff --git a/ovsdb/condition.c b/ovsdb/condition.c > index 4baf1bb..3e1cc19 100644 > --- a/ovsdb/condition.c > +++ b/ovsdb/condition.c > @@ -19,6 +19,7 @@ > > #include <limits.h> > > +#include "bitmap.h" > #include "column.h" > #include "json.h" > #include "ovsdb-error.h" > @@ -64,6 +65,17 @@ ovsdb_clause_from_json(const struct ovsdb_table_schema *ts, > const char *column_name; > struct ovsdb_type type; > > + if (json->type == JSON_TRUE || json->type == JSON_FALSE) { > + function_name = (json->type == JSON_TRUE) ? "true" : "false"; > + error = ovsdb_function_from_string(function_name, &clause->function); > + > + /* column and arg fields are not being used with boolean function > + * use dummy values */ > + clause->column = ovsdb_table_schema_get_column(ts, "_uuid"); > + ovsdb_datum_init_default(&clause->arg, &clause->column->type); > + return error; > + } > + > > It seems we can simply drop any FALSE if there are more than one > clauses, because > of the or conditions. On the other hand, the presence to True can > be reduced to an empty > condition.. > But you still need to remember that you have FALSE clause. For example client does the following: condition_add([false,[x],y[]) then does condition_remove([x],[y]) the outcome of these 2 operations should be FALSE. With the TRUE clause you still need to remember all other clauses in cas that client will remove the TRUE clause. > To handle condition changes, you may still want to finish the JSON > conversions, or define the protocol > in such way that the modification of a TRUE condition the same as > modifying an empty condition. > As I see it, TRUE is not equal to empty condition. For example: condition[TRUE + [x]] != condition[EMPTY + [x]] > If JSON_TRUE and JSON_FALSE has been removed, this function can just > expect a JSON_ARRAY. > After the examples above do you still think it is relevant? > if (json->type != JSON_ARRAY > || json->u.array.n != 3 > || json->u.array.elems[0]->type != JSON_STRING > @@ -109,7 +121,8 @@ ovsdb_clause_from_json(const struct > ovsdb_table_schema *ts, > return error; > } > break; > - > + case OVSDB_F_TRUE: > + case OVSDB_F_FALSE: > case OVSDB_F_EQ: > case OVSDB_F_NE: > break; > @@ -164,6 +177,19 @@ compare_clauses_3way(const void *a_, const void *b_) > } > } > > +static int > +compare_clauses_3way_with_data(const void *a_, const void *b_) > +{ > + const struct ovsdb_clause *a = a_; > + const struct ovsdb_clause *b = b_; > + int res; > + > + res = compare_clauses_3way(a, b); > + return res ? res : ovsdb_datum_compare_3way(&a->arg, > + &b->arg, > + &a->column->type); > + } > + > struct ovsdb_error * > ovsdb_condition_from_json(const struct ovsdb_table_schema *ts, > const struct json *json, > > Should we make sure there is not duplicated clauses here? > > > @@ -173,7 +199,7 @@ ovsdb_condition_from_json(const struct > ovsdb_table_schema *ts, > const struct json_array *array = json_array(json); > size_t i; > > - cnd->clauses = xmalloc(array->n * sizeof *cnd->clauses); > + cnd->clauses = xzalloc(array->n * sizeof *cnd->clauses); > cnd->n_clauses = 0; > for (i = 0; i < array->n; i++) { > struct ovsdb_error *error; > @@ -198,10 +224,16 @@ ovsdb_condition_from_json(const struct > ovsdb_table_schema *ts, > static struct json * > ovsdb_clause_to_json(const struct ovsdb_clause *clause) > { > - return json_array_create_3( > - json_string_create(clause->column->name), > - json_string_create(ovsdb_function_to_string(clause->function)), > - ovsdb_datum_to_json(&clause->arg, &clause->column->type)); > + if (clause->function != OVSDB_F_TRUE && > + clause->function != OVSDB_F_FALSE) { > + return json_array_create_3( > + json_string_create(clause->column->name), > + json_string_create(ovsdb_function_to_string > (clause->function)), > + ovsdb_datum_to_json(&clause->arg, &clause->column->type)); > + } > + > + return json_boolean_create(clause->function == OVSDB_F_TRUE ? > + true : false); > } > > struct json * > @@ -218,13 +250,22 @@ ovsdb_condition_to_json(const struct > ovsdb_condition *cnd) > } > > static bool > -ovsdb_clause_evaluate(const struct ovsdb_row *row, > - const struct ovsdb_clause *c) > +ovsdb_clause_evaluate(const struct ovsdb_datum *fields, > + const struct ovsdb_clause *c, > + const unsigned int columns_index_map[]) > { > - const struct ovsdb_datum *field = &row->fields[c->column->index]; > + if (c->function == OVSDB_F_TRUE || c->function == OVSDB_F_FALSE) { > + return c->function == OVSDB_F_TRUE ? true : false; > + } > + > + const struct ovsdb_datum *field; > const struct ovsdb_datum *arg = &c->arg; > const struct ovsdb_type *type = &c->column->type; > > + field = !columns_index_map ? > + &fields[c->column->index] : > + &fields[columns_index_map[c->column->index]]; > + > if (ovsdb_type_is_optional_scalar(type) && field->n == 0) { > switch (c->function) { > case OVSDB_F_LT: > @@ -237,6 +278,9 @@ ovsdb_clause_evaluate(const struct ovsdb_row *row, > case OVSDB_F_NE: > case OVSDB_F_EXCLUDES: > return true; > + case OVSDB_F_TRUE: > + case OVSDB_F_FALSE: > + OVS_NOT_REACHED(); > } > } else if (ovsdb_type_is_scalar(type) > || ovsdb_type_is_optional_scalar(type)) { > @@ -257,6 +301,9 @@ ovsdb_clause_evaluate(const struct ovsdb_row *row, > return cmp >= 0; > case OVSDB_F_GT: > return cmp > 0; > + case OVSDB_F_TRUE: > + case OVSDB_F_FALSE: > + OVS_NOT_REACHED(); > } > } else { > switch (c->function) { > @@ -272,6 +319,8 @@ ovsdb_clause_evaluate(const struct ovsdb_row *row, > case OVSDB_F_LE: > case OVSDB_F_GE: > case OVSDB_F_GT: > + case OVSDB_F_TRUE: > + case OVSDB_F_FALSE: > OVS_NOT_REACHED(); > } > } > @@ -279,14 +328,42 @@ ovsdb_clause_evaluate(const struct ovsdb_row *row, > OVS_NOT_REACHED(); > } > > +static int > +ovsdb_clause_exists(const struct ovsdb_condition *cnd, > + const struct ovsdb_clause *clause) > +{ > + size_t i; > + > + for (i=0; i < cnd->n_clauses; i++) { > + if(!compare_clauses_3way_with_data(&cnd->clauses[i], clause)) { > + return i; > + } > + } > + > + return -1; > +} > + > +static void > +ovsdb_clone_clause(struct ovsdb_clause *new, struct ovsdb_clause *old) > +{ > + new->function = old->function; > + new->column = old->column; > + ovsdb_datum_clone(&new->arg, > + &old->arg, > + &old->column->type); > +} > + > bool > ovsdb_condition_evaluate(const struct ovsdb_row *row, > - const struct ovsdb_condition *cnd) > + const struct ovsdb_condition *cnd, > + const unsigned int columns_index_map[]) > { > size_t i; > > for (i = 0; i < cnd->n_clauses; i++) { > - if (!ovsdb_clause_evaluate(row, &cnd->clauses[i])) { > + if (!ovsdb_clause_evaluate(row->fields, > + &cnd->clauses[i], > + columns_index_map)) { > return false; > } > } > @@ -294,6 +371,28 @@ ovsdb_condition_evaluate(const struct ovsdb_row *row, > return true; > } > > +bool > +ovsdb_condition_evaluate_or_datum(const struct ovsdb_datum *row_datum, > + const struct ovsdb_condition *cnd, > + const unsigned int columns_index_map[]) > The name of this function is not clear about its intention. The > implementation also > duplicate in many parts with ovsdb_condition_evaluate() above. > +{ > + size_t i; > + > + if (cnd->n_clauses == 0) { > + return true; > + } > + > + for (i = 0; i < cnd->n_clauses; i++) { > + if (ovsdb_clause_evaluate(row_datum, > + &cnd->clauses[i], > + columns_index_map)) { > + return true; > + } > + } > + > + return false; > +} > + > void > ovsdb_condition_destroy(struct ovsdb_condition *cnd) > { > @@ -303,4 +402,153 @@ ovsdb_condition_destroy(struct ovsdb_condition *cnd) > ovsdb_clause_free(&cnd->clauses[i]); > } > free(cnd->clauses); > Should cnd->clauses be set to NULL? > + cnd->n_clauses = 0; > +} > + > +void ovsdb_condition_init(struct ovsdb_condition *cnd) > +{ > + cnd->clauses = NULL; > + cnd->n_clauses = 0; > +} > + > +bool ovsdb_condition_empty(const struct ovsdb_condition *cnd) > +{ > + return cnd->n_clauses == 0; > +} > + > +int ovsdb_condition_cmp(const struct ovsdb_condition *a, > + const struct ovsdb_condition *b) > +{ > + size_t i; > + int res; > + > + if (a->n_clauses != b->n_clauses) { > + return a->n_clauses - b->n_clauses; > + } > + > + /* We assume clauses are sorted */ > + for (i = 0; i < a->n_clauses; i++) { > + res = (compare_clauses_3way_with_data(&a->clauses[i], > &b->clauses[i])); > + if (res != 0) { > + return res; > + } > + } > + > + return 0; > +} > + > +void > +ovsdb_condition_clone(struct ovsdb_condition *to, > + const struct ovsdb_condition *from) > +{ > + size_t i; > + > + to->clauses = xzalloc(from->n_clauses * sizeof *to->clauses); > + > + for (i = 0; i < from->n_clauses; i++) { > + ovsdb_clone_clause(&to->clauses[i], &from->clauses[i]); > + } > + to->n_clauses = from->n_clauses; > +} > + > > With the way it is implemented, the order of when "add" and > "remove' are applied > is important. May be it should be documented. > Agree. Add is being applied before of remove. > Another possibility is to check and make sure clauses in "add" and > "remove" are orthogonal. > Reject the change if they are not. > To simplify client usage I think we should allow client to add a clause and then remove it in the same change operation. What do you think? > +void > +ovsdb_condition_add(struct ovsdb_condition *to, > + const struct ovsdb_condition *add) > +{ > + size_t i, count = 0; > + struct ovsdb_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_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_clone_clause(&clauses[i], &to->clauses[i]); > + ovsdb_clause_free(&to->clauses[i]); > + } > + > + for (i = 0; i < add->n_clauses; i++) { > + if (bitmap_is_set(clause_map, i)) { > + ovsdb_clone_clause(&clauses[index++], &add->clauses[i]); > + } > + } > > Should we keep the clauses sorted? > > If yes, It may be more efficient to blindly add the new clauses, > using xreallc() > sort them, then only check for duplicates with adjacent clauses. > Will fix this. > + > + free(to->clauses); > + free(clause_map); > + to->clauses = clauses; > + to->n_clauses += count; > +} > + > +void > +ovsdb_condition_remove(struct ovsdb_condition *from, > + const struct ovsdb_condition *remove) > +{ > + size_t i, count = 0; > + int j; > + struct ovsdb_clause *clauses; > + unsigned long int *clause_map = xmalloc(bitmap_n_bytes(from->n_clauses)); > + int index = 0; > + > + if (remove->n_clauses == 0) { > + free(clause_map); > + return; > + } > + > + for (i = 0; i < from->n_clauses; i++) { > + bitmap_set1(clause_map, i); > + } > + > + for (i = 0; i < remove->n_clauses; i++) { > + j = ovsdb_clause_exists(from, &remove->clauses[i]); > + if (j >= 0) { > + bitmap_set0(clause_map, j); > + count++; > + } > + } > + > + if (count == 0) { > + free(clause_map); > + return; > + } > + > + clauses = xzalloc((from->n_clauses - count) * sizeof *clauses); > + for (i = 0; i < from->n_clauses; i++) { > + if (bitmap_is_set(clause_map, i)) { > + ovsdb_clone_clause(&clauses[index++], &from->clauses[i]); > + } > + } > + > Should clauses still be sorted after removal? Since we make sure all removed > clauses exist in current condition at message parsing time > (ovsdb_monitor_table_condition_change()), > sort then remove should also work. > Will fix this. > + free(from->clauses); > + free(clause_map); > + from->clauses = clauses; > + from->n_clauses -= count; > +} > + > +/* Returns if a + b includes c */ > +bool > +ovsdb_conditions_includes(const struct ovsdb_condition *a, > + const struct ovsdb_condition *b, > + const struct ovsdb_condition *c) > +{ > + size_t i; > + > + for (i = 0; i < c->n_clauses; i++) { > + if(ovsdb_clause_exists(a, &c->clauses[i]) == -1 && > + ovsdb_clause_exists(b, &c->clauses[i]) == -1) { > + return false; > + } > + } > + > + return true; > } > diff --git a/ovsdb/condition.h b/ovsdb/condition.h > index 620757f..4d223d4 100644 > --- a/ovsdb/condition.h > +++ b/ovsdb/condition.h > @@ -27,6 +27,8 @@ struct ovsdb_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_FUNCTIONS \ > + OVSDB_FUNCTION(OVSDB_F_FALSE, "false") \ > + OVSDB_FUNCTION(OVSDB_F_TRUE, "true") \ > OVSDB_FUNCTION(OVSDB_F_EQ, "==") \ > OVSDB_FUNCTION(OVSDB_F_INCLUDES, "includes") \ > OVSDB_FUNCTION(OVSDB_F_LE, "<=") \ > @@ -60,6 +62,8 @@ struct ovsdb_condition { > > #define OVSDB_CONDITION_INITIALIZER { NULL, 0 } > > +void ovsdb_condition_init(struct ovsdb_condition *); > +bool ovsdb_condition_empty(const struct ovsdb_condition *); > struct ovsdb_error *ovsdb_condition_from_json( > const struct ovsdb_table_schema *, > const struct json *, struct ovsdb_symbol_table *, > @@ -67,6 +71,28 @@ struct ovsdb_error *ovsdb_condition_from_json( > struct json *ovsdb_condition_to_json(const struct ovsdb_condition *); > void ovsdb_condition_destroy(struct ovsdb_condition *); > bool ovsdb_condition_evaluate(const struct ovsdb_row *, > - const struct ovsdb_condition *); > + const struct ovsdb_condition *, > + const unsigned int columns_index_map[]); > +bool ovsdb_condition_evaluate_or_datum(const struct ovsdb_datum *, > + const struct ovsdb_condition *, > + const unsigned int > columns_index_map[]); > +int ovsdb_condition_cmp(const struct ovsdb_condition *a, > + const struct ovsdb_condition *b); > + > +void ovsdb_condition_clone(struct ovsdb_condition *to, > + const struct ovsdb_condition *from); > + > +void > +ovsdb_condition_add(struct ovsdb_condition *to, > + const struct ovsdb_condition *add); > + > +void > +ovsdb_condition_remove(struct ovsdb_condition *from, > + const struct ovsdb_condition *remove); > + > +bool > +ovsdb_conditions_includes(const struct ovsdb_condition *a, > + const struct ovsdb_condition *b, > + const struct ovsdb_condition *c); > > #endif /* ovsdb/condition.h */ > diff --git a/ovsdb/query.c b/ovsdb/query.c > index e288020..5d3f9b1 100644 > --- a/ovsdb/query.c > +++ b/ovsdb/query.c > @@ -34,7 +34,7 @@ ovsdb_query(struct ovsdb_table *table, const > struct ovsdb_condition *cnd, > const struct ovsdb_row *row; > > row = ovsdb_table_get_row(table, &cnd->clauses[0].arg.keys[0].uuid); > - if (row && row->table == table && ovsdb_condition_evaluate > (row, cnd)) { > + if (row && row->table == table && ovsdb_condition_evaluate > (row, cnd, NULL)) { > output_row(row, aux); > } > } else { > @@ -42,7 +42,7 @@ ovsdb_query(struct ovsdb_table *table, const > struct ovsdb_condition *cnd, > const struct ovsdb_row *row, *next; > > HMAP_FOR_EACH_SAFE (row, next, hmap_node, &table->rows) { > - if (ovsdb_condition_evaluate(row, cnd) && !output_row > (row, aux)) { > + if (ovsdb_condition_evaluate(row, cnd, NULL) && ! > output_row(row, aux)) { > break; > } > } > diff --git a/tests/ovsdb-condition.at b/tests/ovsdb-condition.at > index ab54b1c..285c3d6 100644 > --- a/tests/ovsdb-condition.at > +++ b/tests/ovsdb-condition.at > @@ -181,8 +181,21 @@ OVSDB_CHECK_POSITIVE([condition sorting], > ["i", "<", 4], > ["i", ">", 6], > ["i", ">=", 5], > - ["_uuid", "==", ["uuid", "d50e85c6-8ae7-4b16-b69e-4395928bd9be"]]]']], > - [[[["_uuid","==",["uuid","d50e85c6-8ae7-4b16- > b69e-4395928bd9be"]],["i","==",1],["i","includes",2],["i","<=",3], > ["i","<",4],["i",">=",5],["i",">",6],["i","excludes",7],["i","!=",8]]]]) > + ["_uuid", "==", ["uuid", "d50e85c6-8ae7-4b16-b69e-4395928bd9be"]], > + true]']], > + [[[true,["_uuid","==",["uuid","d50e85c6-8ae7-4b16- > b69e-4395928bd9be"]],["i","==",1],["i","includes",2],["i","<=",3], > ["i","<",4],["i",">=",5],["i",">",6],["i","excludes",7],["i","!=",8]]]]) > + > +OVSDB_CHECK_POSITIVE([boolean condition], > + [[parse-conditions \ > + '{"columns": {"name": {"type": "string"}}}' \ > + '[true]']], > + [[[true]]]) > + > +OVSDB_CHECK_POSITIVE([boolean condition], > + [[parse-conditions \ > + '{"columns": {"name": {"type": "string"}}}' \ > + '[false]']], > + [[[false]]]) > > OVSDB_CHECK_POSITIVE([evaluating null condition], > [[evaluate-conditions \ > @@ -657,3 +670,21 @@ condition 5: --T- > condition 6: -T-- > condition 7: T-TT > condition 8: -T-T], [condition]) > + > +OVSDB_CHECK_POSITIVE([evaluating false boolean condition], > + [[evaluate-conditions \ > + '{"columns": {"i": {"type": "integer"}}}' \ > + '[[false,["i","==",0]]]' \ > + '[{"i": 0}, > + {"i": 1}, > + {"i": 2}']]], > + [condition 0: ---]) > + > +OVSDB_CHECK_POSITIVE([evaluating true boolean condition], > + [[evaluate-conditions-or \ > + '{"columns": {"i": {"type": "integer"}}}' \ > + '[[true,["i","==",0]]]' \ > + '[{"i": 0}, > + {"i": 1}, > + {"i": 2}']]], > + [condition 0: TTT]) > diff --git a/tests/test-ovsdb.c b/tests/test-ovsdb.c > index 15f41b0..e924532 100644 > --- a/tests/test-ovsdb.c > +++ b/tests/test-ovsdb.c > @@ -851,8 +851,11 @@ do_parse_conditions(struct ovs_cmdl_context *ctx) > exit(exit_code); > } > > +#define OVSDB_CONDITION_AND 0 > +#define OVSDB_CONDITION_OR 1 > + > static void > -do_evaluate_conditions(struct ovs_cmdl_context *ctx) > +do_evaluate_condition__(struct ovs_cmdl_context *ctx, int mode) > { > struct ovsdb_table_schema *ts; > struct ovsdb_table *table; > @@ -900,7 +903,16 @@ do_evaluate_conditions(struct ovs_cmdl_context *ctx) > for (i = 0; i < n_conditions; i++) { > printf("condition %2"PRIuSIZE":", i); > for (j = 0; j < n_rows; j++) { > - bool result = ovsdb_condition_evaluate(rows[j], &conditions[i]); > + bool result; > + if (mode == OVSDB_CONDITION_AND) { > + result = ovsdb_condition_evaluate(rows[j], > + &conditions[i], > + NULL); > + } else { > + result = ovsdb_condition_evaluate_or_datum(rows[j]->fields, > + &conditions[i], > + NULL); > + } > if (j % 5 == 0) { > putchar(' '); > } > @@ -921,6 +933,18 @@ do_evaluate_conditions(struct ovs_cmdl_context *ctx) > } > > static void > +do_evaluate_conditions(struct ovs_cmdl_context *ctx) > +{ > + do_evaluate_condition__(ctx, OVSDB_CONDITION_AND); > +} > + > +static void > +do_evaluate_conditions_or(struct ovs_cmdl_context *ctx) > +{ > + do_evaluate_condition__(ctx, OVSDB_CONDITION_OR); > +} > + > +static void > do_parse_mutations(struct ovs_cmdl_context *ctx) > { > struct ovsdb_table_schema *ts; > @@ -2191,6 +2215,7 @@ static struct ovs_cmdl_command all_commands[] = { > { "compare-rows", NULL, 2, INT_MAX, do_compare_rows }, > { "parse-conditions", NULL, 2, INT_MAX, do_parse_conditions }, > { "evaluate-conditions", NULL, 3, 3, do_evaluate_conditions }, > + { "evaluate-conditions-or", NULL, 3, 3, do_evaluate_conditions_or }, > { "parse-mutations", NULL, 2, INT_MAX, do_parse_mutations }, > { "execute-mutations", NULL, 3, 3, do_execute_mutations }, > { "query", NULL, 3, 3, do_query }, > -- > 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