On Wed, 9 May 2018 13:02:55 -0700 Ben Pfaff <b...@ovn.org> wrote: > On Thu, Apr 26, 2018 at 09:54:06PM +0200, Jakub Sitnicki wrote: > > Appending prerequisites to sub-expressions of OR that are all over one > > symbol prevents the expression-to-matches converter from applying > > conjunctive matching. This happens during the annotation phase. > > > > input: s1 == { c1, c2 } && s2 == { c3, c4 } > > expanded: (s1 == c1 || s1 == c2) && (s2 == c3 || s2 == c4) > > annotated: ((p1 && s1 == c1) || (p1 && s1 == c2)) && > > ((p2 && s2 == c3) || (p2 && s2 == c4)) > > normalized: (p1 && p2 && s1 == c1 && s2 == c3) || > > (p1 && p2 && s1 == c1 && s2 == c4) || > > (p1 && p2 && s1 == c2 && s2 == c3) || > > (p1 && p2 && s1 == c2 && s2 == c4) > > > > Where s1,s2 - symbols, c1..c4 - constants, p1,p2 - prerequisites. > > > > Since sub-expressions of OR trees that are over one symbol all have the > > same prerequisites, we can factor them out leaving the OR tree in tact, > > and enabling the converter to apply conjunctive matching to > > AND(OR(clause)) trees. > > > > Going back to our example this change gives us: > > > > input: s1 == { c1, c2 } && s2 == { c3, c4 } > > expanded: (s1 == c1 || s1 == c2) && (s2 == c3 || s2 == c4) > > annotated: (s1 == c1 || s1 == c2) && p1 && (s2 == c3 || s2 == c4) && p2 > > normalized: p1 && p2 && (s1 == c1 || s1 == c2) && (s2 == c3 || s2 == c4) > > > > We also factor out the prerequisites out of pure AND or mixed AND/OR > > trees to keep the common code path, but in this case we don't gain > > anything. > > > > Signed-off-by: Jakub Sitnicki <j...@redhat.com> > > This is nice. Thank you. > > I suggest folding in the following to better document and to better > match usual OVS style: > > diff --git a/ovn/lib/expr.c b/ovn/lib/expr.c > index 9dd8d6f17abe..bac8e1efd53f 100644 > --- a/ovn/lib/expr.c > +++ b/ovn/lib/expr.c > @@ -32,13 +32,10 @@ > > VLOG_DEFINE_THIS_MODULE(expr); > > -static const struct expr_symbol * > -expr_get_unique_symbol(const struct expr *expr); > - > -struct expr * > -expr_annotate__(struct expr *expr, const struct shash *symtab, > - bool append_prereqs, struct ovs_list *nesting, char > **errorp); > - > +static const struct expr_symbol *expr_get_unique_symbol(const struct expr *); > +struct expr *expr_annotate__(struct expr *, const struct shash *symtab, > + bool append_prereqs, struct ovs_list *nesting, > + char **errorp); > static struct expr *parse_and_annotate(const char *s, > const struct shash *symtab, > struct ovs_list *nesting, > @@ -1771,6 +1768,15 @@ error: > return NULL; > } > > +/* Same interface and purpose as expr_annotate(), with a couple of additional > + * parameters for internal bookkeeping. > + * > + * Uses 'nesting' to ensure that a given symbol is not recursively expanded. > + * > + * Ordinarily, annotation adds prerequisites to the expression, and that's > what > + * this function does if 'append_prereqs' is true. If 'append_prereqs' is > + * false, this function ignores prerequisites (in which case the caller must > + * have arranged to deal with them). */ > struct expr * > expr_annotate__(struct expr *expr, const struct shash *symtab, > bool append_prereqs, struct ovs_list *nesting, char **errorp) > > I also wonder about the following, because it seems like currently the > append_prereqs parameter is only being honored for a single level of > AND/OR, not when expr_annotate__() recurses: > > diff --git a/ovn/lib/expr.c b/ovn/lib/expr.c > index 9dd8d6f17abe..a33b4eb46933 100644 > --- a/ovn/lib/expr.c > +++ b/ovn/lib/expr.c > @@ -1782,12 +1788,25 @@ expr_annotate__(struct expr *expr, const struct shash > *symtab, > > case EXPR_T_AND: > case EXPR_T_OR: { > - const struct expr_symbol *unique_symbol = > expr_get_unique_symbol(expr); > + /* Detect whether every term in 'expr' mentions the same symbol. If > + * so, then suppress prerequisites for that symbol for those terms > and > + * instead apply them once at our higher level. > + * > + * If 'append_prereqs' is true, though, we're not supposed to handle > + * prereqs at all (because our caller is already doing it). */ > + const struct expr_symbol *unique_symbol = NULL; > + if (!append_prereqs) { > + unique_symbol = expr_get_unique_symbol(expr); > + if (unique_symbol) { > + append_prereqs = false; > + } > + } > + > struct expr *sub, *next; > > LIST_FOR_EACH_SAFE (sub, next, node, &expr->andor) { > ovs_list_remove(&sub->node); > - struct expr *new_sub = expr_annotate__(sub, symtab, > !unique_symbol, > + struct expr *new_sub = expr_annotate__(sub, symtab, > append_prereqs, > nesting, errorp); > if (!new_sub) { > expr_destroy(expr); > > However this patch, while it seems reasonable, causes some test failures > due to the difference that it produces and I'm not sure whether the new > results are actually superior to the old ones.
Thank you for the review and the style fixes. I'll have to mull over the recursive case, this is something I have not considered, before I roll out a v2. -Jakub _______________________________________________ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev