From d0a9571da0cc7169a1ffb8bf9de68954b717d4e3 Mon Sep 17 00:00:00 2001 From: Johan Wikman Date: Wed, 15 Mar 2017 14:11:08 +0200 Subject: [PATCH] Introduce new qc_parse() prototype It is now possible to specify what information the caller is interested in. With this the cost for collecting information during the query parsing that nobody is interested in can be avoided. --- include/maxscale/query_classifier.h | 31 ++++++++++++++++--- query_classifier/qc_dummy/qc_dummy.cc | 2 +- .../qc_mysqlembedded/qc_mysqlembedded.cc | 2 +- query_classifier/qc_sqlite/qc_sqlite.c | 4 +-- query_classifier/test/compare.cc | 4 +-- query_classifier/test/crash_qc_sqlite.c | 2 +- server/core/query_classifier.cc | 4 +-- server/modules/filter/dbfwfilter/dbfwfilter.c | 2 +- 8 files changed, 36 insertions(+), 15 deletions(-) diff --git a/include/maxscale/query_classifier.h b/include/maxscale/query_classifier.h index 38556a4a8..8727dbb6c 100644 --- a/include/maxscale/query_classifier.h +++ b/include/maxscale/query_classifier.h @@ -29,6 +29,18 @@ typedef enum qc_init_kind QC_INIT_BOTH = 0x03 } qc_init_kind_t; +/** + * @c qc_collect_info_t specifies what information should be collected during parsing. + */ +typedef enum qc_collect_info +{ + QC_COLLECT_TABLES = 0x01, /*< Collect table names. */ + QC_COLLECT_DATABASES = 0x02, /*< Collect database names. */ + QC_COLLECT_FIELDS = 0x04, /*< Collect field information. */ + QC_COLLECT_FUNCTIONS = 0x08, /*< Collect function information. */ + + QC_COLLECT_ALL = (QC_COLLECT_TABLES|QC_COLLECT_DATABASES|QC_COLLECT_FIELDS|QC_COLLECT_FUNCTIONS) +} qc_collect_info_t; /** * qc_query_type_t defines bits that provide information about a * particular statement. @@ -196,13 +208,16 @@ typedef struct query_classifier /** * Called to explicitly parse a statement. * - * @param stmt The statement to be parsed. - * @param result On return, the parse result, if @c QC_RESULT_OK is returned. + * @param stmt The statement to be parsed. + * @param collect A bitmask of @c qc_collect_info_t values. Specifies what information + * should be collected. Only a hint and must not restrict what information + * later can be queried. + * @param result On return, the parse result, if @c QC_RESULT_OK is returned. * * @return QC_RESULT_OK, if the parsing was not aborted due to resource * exhaustion or equivalent. */ - int32_t (*qc_parse)(GWBUF* stmt, int32_t* result); + int32_t (*qc_parse)(GWBUF* stmt, uint32_t collect, int32_t* result); /** * Reports the type of the statement. @@ -476,11 +491,17 @@ void qc_thread_end(uint32_t kind); * already then this function will only return the result of that parsing; * the statement will not be parsed again. * - * @param stmt A buffer containing an COM_QUERY or COM_STMT_PREPARE packet. + * @param stmt A buffer containing an COM_QUERY or COM_STMT_PREPARE packet. + * @param collect A bitmask of @c qc_collect_info_t values. Specifies what information + * should be collected. + * + * Note that this is merely a hint and does not restrict what + * information can be queried for. If necessary, the statement + * will transparently be reparsed. * * @return To what extent the statement could be parsed. */ -qc_parse_result_t qc_parse(GWBUF* stmt); +qc_parse_result_t qc_parse(GWBUF* stmt, uint32_t collect); /** * Convert a qc_field_usage_t enum to corresponding string. diff --git a/query_classifier/qc_dummy/qc_dummy.cc b/query_classifier/qc_dummy/qc_dummy.cc index 4e8c5ca63..6b91fceba 100644 --- a/query_classifier/qc_dummy/qc_dummy.cc +++ b/query_classifier/qc_dummy/qc_dummy.cc @@ -16,7 +16,7 @@ #include "../../server/core/maxscale/config.h" -int32_t qc_dummy_parse(GWBUF* querybuf, int32_t* pResult) +int32_t qc_dummy_parse(GWBUF* querybuf, uint32_t collect, int32_t* pResult) { *pResult = QC_QUERY_INVALID; return QC_RESULT_OK; diff --git a/query_classifier/qc_mysqlembedded/qc_mysqlembedded.cc b/query_classifier/qc_mysqlembedded/qc_mysqlembedded.cc index 788b71e27..ee7dd83bb 100644 --- a/query_classifier/qc_mysqlembedded/qc_mysqlembedded.cc +++ b/query_classifier/qc_mysqlembedded/qc_mysqlembedded.cc @@ -136,7 +136,7 @@ bool ensure_query_is_parsed(GWBUF* query) return parsed; } -int32_t qc_mysql_parse(GWBUF* querybuf, int32_t* result) +int32_t qc_mysql_parse(GWBUF* querybuf, uint32_t collect, int32_t* result) { bool parsed = ensure_query_is_parsed(querybuf); diff --git a/query_classifier/qc_sqlite/qc_sqlite.c b/query_classifier/qc_sqlite/qc_sqlite.c index 054496f5f..8482d7acb 100644 --- a/query_classifier/qc_sqlite/qc_sqlite.c +++ b/query_classifier/qc_sqlite/qc_sqlite.c @@ -2792,7 +2792,7 @@ static int32_t qc_sqlite_process_init(void); static void qc_sqlite_process_end(void); static int32_t qc_sqlite_thread_init(void); static void qc_sqlite_thread_end(void); -static int32_t qc_sqlite_parse(GWBUF* query, int32_t* result); +static int32_t qc_sqlite_parse(GWBUF* query, uint32_t collect, int32_t* result); static int32_t qc_sqlite_get_type_mask(GWBUF* query, uint32_t* typemask); static int32_t qc_sqlite_get_operation(GWBUF* query, int32_t* op); static int32_t qc_sqlite_get_created_table_name(GWBUF* query, char** name); @@ -3010,7 +3010,7 @@ static void qc_sqlite_thread_end(void) this_thread.initialized = false; } -static int32_t qc_sqlite_parse(GWBUF* query, int32_t* result) +static int32_t qc_sqlite_parse(GWBUF* query, uint32_t collect, int32_t* result) { QC_TRACE(); ss_dassert(this_unit.initialized); diff --git a/query_classifier/test/compare.cc b/query_classifier/test/compare.cc index 809bcf673..b101aca9b 100644 --- a/query_classifier/test/compare.cc +++ b/query_classifier/test/compare.cc @@ -312,13 +312,13 @@ bool compare_parse(QUERY_CLASSIFIER* pClassifier1, GWBUF* pCopy1, clock_gettime(CLOCK_MONOTONIC_RAW, &start); int32_t rv1; - pClassifier1->qc_parse(pCopy1, &rv1); + pClassifier1->qc_parse(pCopy1, QC_COLLECT_ALL, &rv1); clock_gettime(CLOCK_MONOTONIC_RAW, &finish); update_time(&global.time1, start, finish); clock_gettime(CLOCK_MONOTONIC_RAW, &start); int32_t rv2; - pClassifier2->qc_parse(pCopy2, &rv2); + pClassifier2->qc_parse(pCopy2, QC_COLLECT_ALL, &rv2); clock_gettime(CLOCK_MONOTONIC_RAW, &finish); update_time(&global.time2, start, finish); diff --git a/query_classifier/test/crash_qc_sqlite.c b/query_classifier/test/crash_qc_sqlite.c index 991b56dbb..d4ac4e321 100644 --- a/query_classifier/test/crash_qc_sqlite.c +++ b/query_classifier/test/crash_qc_sqlite.c @@ -51,7 +51,7 @@ int main() // being of the opinion that the statement was not the one to be // classified and hence an alien parse-tree being passed to sqlite3's // code generator. - qc_parse(stmt); + qc_parse(stmt, QC_COLLECT_ALL); qc_process_end(QC_INIT_BOTH); diff --git a/server/core/query_classifier.cc b/server/core/query_classifier.cc index 99f8d5e02..17b8c41fa 100644 --- a/server/core/query_classifier.cc +++ b/server/core/query_classifier.cc @@ -178,14 +178,14 @@ void qc_thread_end(uint32_t kind) } } -qc_parse_result_t qc_parse(GWBUF* query) +qc_parse_result_t qc_parse(GWBUF* query, uint32_t collect) { QC_TRACE(); ss_dassert(classifier); int32_t result = QC_QUERY_INVALID; - classifier->qc_parse(query, &result); + classifier->qc_parse(query, collect, &result); return (qc_parse_result_t)result; } diff --git a/server/modules/filter/dbfwfilter/dbfwfilter.c b/server/modules/filter/dbfwfilter/dbfwfilter.c index c16bf4ed1..343b590bc 100644 --- a/server/modules/filter/dbfwfilter/dbfwfilter.c +++ b/server/modules/filter/dbfwfilter/dbfwfilter.c @@ -2007,7 +2007,7 @@ bool rule_matches(FW_INSTANCE* my_instance, if (is_sql) { - qc_parse_result_t parse_result = qc_parse(queue); + qc_parse_result_t parse_result = qc_parse(queue, QC_COLLECT_ALL); if (parse_result == QC_QUERY_INVALID) {