diff --git a/Documentation/Books/Manual/Programs/Arangod/Query.md b/Documentation/Books/Manual/Programs/Arangod/Query.md index 57de8da249..08928e0a6f 100644 --- a/Documentation/Books/Manual/Programs/Arangod/Query.md +++ b/Documentation/Books/Manual/Programs/Arangod/Query.md @@ -59,6 +59,17 @@ setting the option `--query.tracking` to *false*. The default value is *10.0*. +`--query.slow-streaming-threshold value` + +By setting *value* it can be controlled after what execution time streaming AQL +queries are considered "slow". This option exists to give streaming queries a +separate, potentially higher timeout value than regular queries. Streaming queries +are often executed in lockstep with application data processing logic, which then +also accounts for the queries' runtime. It is thus not unexpected if streaming +queries' lifetime is longer than the one of regular queries. + +The default value is *10.0*. + ## Limiting the number of query execution plans created by the AQL optimizer `--query.optimizer-max-plans value` diff --git a/arangod/Aql/QueryList.cpp b/arangod/Aql/QueryList.cpp index de3658a837..ae48a074c4 100644 --- a/arangod/Aql/QueryList.cpp +++ b/arangod/Aql/QueryList.cpp @@ -59,6 +59,7 @@ QueryList::QueryList(TRI_vocbase_t*) _trackSlowQueries(application_features::ApplicationServer::getFeature("QueryRegistry")->trackSlowQueries()), _trackBindVars(application_features::ApplicationServer::getFeature("QueryRegistry")->trackBindVars()), _slowQueryThreshold(application_features::ApplicationServer::getFeature("QueryRegistry")->slowQueryThreshold()), + _slowStreamingQueryThreshold(application_features::ApplicationServer::getFeature("QueryRegistry")->slowStreamingQueryThreshold()), _maxSlowQueries(defaultMaxSlowQueries), _maxQueryStringLength(defaultMaxQueryStringLength) { _current.reserve(64); @@ -110,8 +111,11 @@ void QueryList::remove(Query* query) { } _current.erase(it); - - if (!_trackSlowQueries || _slowQueryThreshold < 0.0) { + + bool const isStreaming = query->queryOptions().stream; + double threshold = (isStreaming ? _slowStreamingQueryThreshold : _slowQueryThreshold); + + if (!_trackSlowQueries || threshold < 0.0) { return; } @@ -120,7 +124,7 @@ void QueryList::remove(Query* query) { try { // check if we need to push the query into the list of slow queries - if (now - started >= _slowQueryThreshold && !query->killed()) { + if (now - started >= threshold && !query->killed()) { // yes. TRI_IF_FAILURE("QueryList::remove") { @@ -149,10 +153,11 @@ void QueryList::remove(Query* query) { } } } + if (loadTime >= 0.1) { - LOG_TOPIC(WARN, Logger::QUERIES) << "slow query: '" << q << "'" << bindParameters << ", took: " << Logger::FIXED(now - started) << " s, loading took: " << Logger::FIXED(loadTime) << " s"; + LOG_TOPIC(WARN, Logger::QUERIES) << "slow " << (isStreaming ? "streaming " : "") << "query: '" << q << "'" << bindParameters << ", took: " << Logger::FIXED(now - started) << " s, loading took: " << Logger::FIXED(loadTime) << " s"; } else { - LOG_TOPIC(WARN, Logger::QUERIES) << "slow query: '" << q << "'" << bindParameters << ", took: " << Logger::FIXED(now - started) << " s"; + LOG_TOPIC(WARN, Logger::QUERIES) << "slow " << (isStreaming ? "streaming " : "") << "query: '" << q << "'" << bindParameters << ", took: " << Logger::FIXED(now - started) << " s"; } _slow.emplace_back( @@ -161,7 +166,7 @@ void QueryList::remove(Query* query) { _trackBindVars ? query->bindParameters() : nullptr, started, now - started, QueryExecutionState::ValueType::FINISHED, - query->queryOptions().stream + isStreaming ); if (++_slowCount > _maxSlowQueries) { diff --git a/arangod/Aql/QueryList.h b/arangod/Aql/QueryList.h index 58bfad0df5..df3a770f05 100644 --- a/arangod/Aql/QueryList.h +++ b/arangod/Aql/QueryList.h @@ -77,7 +77,7 @@ class QueryList { /// @brief toggle query tracking /// we're not using a lock here for performance reasons - thus concurrent /// modifications of this variable are possible but are considered unharmful - inline void enabled(bool value) { _enabled.store(value, std::memory_order_relaxed); } + inline void enabled(bool value) { _enabled.store(value); } /// @brief whether or not slow queries are tracked /// we're not using a lock here for performance reasons - thus concurrent @@ -87,7 +87,7 @@ class QueryList { /// @brief toggle slow query tracking /// we're not using a lock here for performance reasons - thus concurrent /// modifications of this variable are possible but are considered unharmful - inline void trackSlowQueries(bool value) { _trackSlowQueries.store(value, std::memory_order_relaxed); } + inline void trackSlowQueries(bool value) { _trackSlowQueries.store(value); } /// @brief whether or not bind vars are tracked with queries /// we're not using a lock here for performance reasons - thus concurrent @@ -97,13 +97,13 @@ class QueryList { /// @brief toggle query bind vars tracking /// we're not using a lock here for performance reasons - thus concurrent /// modifications of this variable are possible but are considered unharmful - inline void trackBindVars(bool value) { _trackBindVars.store(value, std::memory_order_relaxed); } + inline void trackBindVars(bool value) { _trackBindVars.store(value); } /// @brief threshold for slow queries (in seconds) /// we're not using a lock here for performance reasons - thus concurrent /// modifications of this variable are possible but are considered unharmful inline double slowQueryThreshold() const { return _slowQueryThreshold.load(std::memory_order_relaxed); } - + /// @brief set the slow query threshold /// we're not using a lock here for performance reasons - thus concurrent /// modifications of this variable are possible but are considered unharmful @@ -112,7 +112,23 @@ class QueryList { // sanity checks value = 0.0; } - _slowQueryThreshold.store(value, std::memory_order_relaxed); + _slowQueryThreshold.store(value); + } + + /// @brief threshold for slow streaming queries (in seconds) + /// we're not using a lock here for performance reasons - thus concurrent + /// modifications of this variable are possible but are considered unharmful + inline double slowStreamingQueryThreshold() const { return _slowStreamingQueryThreshold.load(std::memory_order_relaxed); } + + /// @brief set the slow streaming query threshold + /// we're not using a lock here for performance reasons - thus concurrent + /// modifications of this variable are possible but are considered unharmful + inline void slowStreamingQueryThreshold(double value) { + if (value < 0.0 || value == HUGE_VAL || value != value) { + // sanity checks + value = 0.0; + } + _slowStreamingQueryThreshold.store(value); } /// @brief return the max number of slow queries to keep @@ -128,7 +144,7 @@ class QueryList { // sanity checks value = 16384; } - _maxSlowQueries.store(value, std::memory_order_relaxed); + _maxSlowQueries.store(value); } /// @brief return the max length of query strings that are stored / returned @@ -147,7 +163,7 @@ class QueryList { value = 8 * 1024 * 1024; } - _maxQueryStringLength.store(value, std::memory_order_relaxed); + _maxQueryStringLength.store(value); } /// @brief enter a query @@ -204,6 +220,9 @@ class QueryList { /// @brief threshold for slow queries (in seconds) std::atomic _slowQueryThreshold; + + /// @brief threshold for slow streaming queries (in seconds) + std::atomic _slowStreamingQueryThreshold; /// @brief maximum number of slow queries to keep std::atomic _maxSlowQueries; diff --git a/arangod/RestServer/QueryRegistryFeature.cpp b/arangod/RestServer/QueryRegistryFeature.cpp index d7ae496a61..8b70671eb5 100644 --- a/arangod/RestServer/QueryRegistryFeature.cpp +++ b/arangod/RestServer/QueryRegistryFeature.cpp @@ -47,6 +47,7 @@ QueryRegistryFeature::QueryRegistryFeature( _queryMemoryLimit(0), _maxQueryPlans(128), _slowQueryThreshold(10.0), + _slowStreamingQueryThreshold(10.0), _queryCacheMode("off"), _queryCacheMaxResultsCount(0), _queryCacheMaxResultsSize(0), @@ -85,6 +86,9 @@ void QueryRegistryFeature::collectOptions( options->addOption("--query.slow-threshold", "threshold for slow AQL queries (in seconds)", new DoubleParameter(&_slowQueryThreshold)); + + options->addOption("--query.slow-streaming-threshold", "threshold for slow streaming AQL queries (in seconds)", + new DoubleParameter(&_slowStreamingQueryThreshold)); options->addOption("--query.cache-mode", "mode for the AQL query result cache (on, off, demand)", diff --git a/arangod/RestServer/QueryRegistryFeature.h b/arangod/RestServer/QueryRegistryFeature.h index 796529b49d..0bcaba583a 100644 --- a/arangod/RestServer/QueryRegistryFeature.h +++ b/arangod/RestServer/QueryRegistryFeature.h @@ -55,6 +55,7 @@ class QueryRegistryFeature final : public application_features::ApplicationFeatu bool trackSlowQueries() const { return _trackSlowQueries; } bool trackBindVars() const { return _trackBindVars; } double slowQueryThreshold() const { return _slowQueryThreshold; } + double slowStreamingQueryThreshold() const { return _slowStreamingQueryThreshold; } bool failOnWarning() const { return _failOnWarning; } uint64_t queryMemoryLimit() const { return _queryMemoryLimit; } uint64_t maxQueryPlans() const { return _maxQueryPlans; } @@ -66,6 +67,7 @@ class QueryRegistryFeature final : public application_features::ApplicationFeatu uint64_t _queryMemoryLimit; uint64_t _maxQueryPlans; double _slowQueryThreshold; + double _slowStreamingQueryThreshold; std::string _queryCacheMode; uint64_t _queryCacheMaxResultsCount; uint64_t _queryCacheMaxResultsSize;