From: Josef 'Jeff' Sipek Date: Fri, 30 Apr 2021 20:59:50 +0000 (-0400) Subject: lib: event filter - Avoid using event field wildcard matching when not needed X-Git-Tag: 2.3.16~163 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=aefe4941c14c6001a9d09fbc3122aca1417d00a8;p=thirdparty%2Fdovecot%2Fcore.git lib: event filter - Avoid using event field wildcard matching when not needed If the right hand side of an event field comparison is not using any wildcards, we can compare using strcasecmp() instead of the more expensive wildcard_match_icase(). This wildcard matching avoidance change speeds up matching quite a bit. When the desired comparison is *not* a wildcard match (i.e., the filter is 'fieldname=abc'), microbenchmarks show at least a 11% speedup in filter matching speed. When the comparison includes a wildcard (i.e., the filter is 'fieldname=abc*'), microbenchmarks show approximately 0.9% filer matching slowdown. Since there are so many non-wildcard matches in a typical filter, this is a very good trade-off. --- diff --git a/src/lib/event-filter-parser.y b/src/lib/event-filter-parser.y index 8f53dfd0d2..3d5460043f 100644 --- a/src/lib/event-filter-parser.y +++ b/src/lib/event-filter-parser.y @@ -102,8 +102,12 @@ static struct event_filter_node *key_value(struct event_filter_parser_state *sta Either we have a string, or a number with wildcards */ node->field.value.intmax = INT_MIN; } + + if (wildcard_is_literal(node->field.value.str)) + node->type = EVENT_FILTER_NODE_TYPE_EVENT_FIELD_EXACT; break; case EVENT_FILTER_NODE_TYPE_EVENT_NAME_EXACT: + case EVENT_FILTER_NODE_TYPE_EVENT_FIELD_EXACT: i_unreached(); } diff --git a/src/lib/event-filter-private.h b/src/lib/event-filter-private.h index 09ce1a0a8a..47ff8df3cf 100644 --- a/src/lib/event-filter-private.h +++ b/src/lib/event-filter-private.h @@ -24,6 +24,7 @@ enum event_filter_node_type { EVENT_FILTER_NODE_TYPE_EVENT_NAME_WILDCARD, /* str */ EVENT_FILTER_NODE_TYPE_EVENT_SOURCE_LOCATION, /* str + int */ EVENT_FILTER_NODE_TYPE_EVENT_CATEGORY, /* cat */ + EVENT_FILTER_NODE_TYPE_EVENT_FIELD_EXACT, /* field */ EVENT_FILTER_NODE_TYPE_EVENT_FIELD_WILDCARD, /* field */ }; diff --git a/src/lib/event-filter.c b/src/lib/event-filter.c index cd7fb7ca8d..ff49e1b956 100644 --- a/src/lib/event-filter.c +++ b/src/lib/event-filter.c @@ -464,6 +464,7 @@ event_filter_export_query_expr(const struct event_filter_query_internal *query, } else str_append(dest, event_filter_category_from_log_type(node->category.log_type)); break; + case EVENT_FILTER_NODE_TYPE_EVENT_FIELD_EXACT: case EVENT_FILTER_NODE_TYPE_EVENT_FIELD_WILDCARD: str_append_c(dest, '"'); event_filter_append_escaped(dest, node->field.key); @@ -560,7 +561,7 @@ event_has_category(struct event *event, struct event_filter_node *node, static bool event_match_field(struct event *event, const struct event_field *wanted_field, - enum event_filter_node_op op) + enum event_filter_node_op op, bool use_strcmp) { const struct event_field *field; @@ -581,7 +582,10 @@ event_match_field(struct event *event, const struct event_field *wanted_field, /* field was removed, but it matches field="" filter */ return wanted_field->value.str[0] == '\0'; } - return wildcard_match_icase(field->value.str, wanted_field->value.str); + if (use_strcmp) + return strcasecmp(field->value.str, wanted_field->value.str) == 0; + else + return wildcard_match_icase(field->value.str, wanted_field->value.str); case EVENT_FIELD_VALUE_TYPE_INTMAX: if (wanted_field->value.intmax > INT_MIN) { /* compare against an integer */ @@ -610,7 +614,10 @@ event_match_field(struct event *event, const struct event_field *wanted_field, } char tmp[MAX_INT_STRLEN]; i_snprintf(tmp, sizeof(tmp), "%jd", field->value.intmax); - return wildcard_match_icase(tmp, wanted_field->value.str); + if (use_strcmp) + return strcasecmp(field->value.str, wanted_field->value.str) == 0; + else + return wildcard_match_icase(tmp, wanted_field->value.str); } case EVENT_FIELD_VALUE_TYPE_TIMEVAL: /* there's no point to support matching exact timestamps */ @@ -647,8 +654,12 @@ event_filter_query_match_cmp(struct event_filter_node *node, strcmp(event->source_filename, node->str) != 0); case EVENT_FILTER_NODE_TYPE_EVENT_CATEGORY: return event_has_category(event, node, log_type); + case EVENT_FILTER_NODE_TYPE_EVENT_FIELD_EXACT: + return event_match_field(event, &node->field, node->op, + TRUE); case EVENT_FILTER_NODE_TYPE_EVENT_FIELD_WILDCARD: - return event_match_field(event, &node->field, node->op); + return event_match_field(event, &node->field, node->op, + FALSE); } i_unreached(); @@ -815,6 +826,7 @@ event_filter_query_update_category(struct event_filter_query_internal *query, case EVENT_FILTER_NODE_TYPE_EVENT_NAME_EXACT: case EVENT_FILTER_NODE_TYPE_EVENT_NAME_WILDCARD: case EVENT_FILTER_NODE_TYPE_EVENT_SOURCE_LOCATION: + case EVENT_FILTER_NODE_TYPE_EVENT_FIELD_EXACT: case EVENT_FILTER_NODE_TYPE_EVENT_FIELD_WILDCARD: break; case EVENT_FILTER_NODE_TYPE_EVENT_CATEGORY: