diff --git a/include/maxscale/service.h b/include/maxscale/service.h index 2806ab7bc..1afc60026 100644 --- a/include/maxscale/service.h +++ b/include/maxscale/service.h @@ -20,6 +20,7 @@ #include +#include #include #include #include diff --git a/maxutils/maxbase/src/average.cc b/maxutils/maxbase/src/average.cc index cc6bd3e5f..8da5a9bfa 100644 --- a/maxutils/maxbase/src/average.cc +++ b/maxutils/maxbase/src/average.cc @@ -70,8 +70,11 @@ EMAverage::EMAverage(double min_alpha, double max_alpha, int sample_max) : void EMAverage::add(double ave, int num_samples) { + // Give more weight to initial samples. + int sample_max = std::min(m_num_samples ? m_num_samples : 1, m_sample_max); + double alpha = m_min_alpha + m_max_alpha * - std::min(double(num_samples) / m_sample_max, 1.0); + std::min(double(num_samples) / sample_max, 1.0); m_num_samples += num_samples; if (m_num_samples == num_samples) diff --git a/server/modules/routing/readwritesplit/response_stat.cc b/server/modules/routing/readwritesplit/response_stat.cc index e1f7751a0..e2ab667f8 100644 --- a/server/modules/routing/readwritesplit/response_stat.cc +++ b/server/modules/routing/readwritesplit/response_stat.cc @@ -16,10 +16,11 @@ namespace maxscale { -ResponseStat::ResponseStat(int ignore_first_n, int num_filter_samples, - maxbase::Duration sync_duration) : - m_ignore_first_n{ignore_first_n}, - m_num_filter_samples {num_filter_samples}, +ResponseStat::ResponseStat(int num_filter_samples, + int num_synch_medians, + maxbase::Duration sync_duration) + : m_num_filter_samples {num_filter_samples}, + m_num_synch_medians{num_synch_medians}, m_sync_duration{sync_duration}, m_sample_count{0}, m_samples(num_filter_samples), @@ -30,11 +31,6 @@ ResponseStat::ResponseStat(int ignore_first_n, int num_filter_samples, void ResponseStat::query_started() { - if (m_ignore_first_n) - { - --m_ignore_first_n; - return; - } m_last_start = maxbase::Clock::now(); } @@ -57,6 +53,18 @@ void ResponseStat::query_ended() m_last_start = maxbase::TimePoint(); } +bool ResponseStat::make_valid() +{ + if (!m_average.num_samples() && m_sample_count) + { + maxbase::Duration new_sample = m_samples[m_sample_count / 2]; + m_average.add(std::chrono::duration(new_sample).count()); + m_sample_count = 0; + } + + return is_valid(); +} + bool ResponseStat::is_valid() const { return m_average.num_samples(); @@ -72,10 +80,12 @@ maxbase::Duration ResponseStat::average() const return maxbase::Duration(m_average.average()); } -bool ResponseStat::sync_time_reached(int num_synch_medians) +bool ResponseStat::sync_time_reached() { auto now = maxbase::Clock::now(); - bool reached = m_next_sync < now || m_average.num_samples() >= num_synch_medians; + bool reached = m_next_sync < now + || m_average.num_samples() >= m_num_synch_medians; + if (reached) { m_next_sync = now + m_sync_duration; diff --git a/server/modules/routing/readwritesplit/response_stat.hh b/server/modules/routing/readwritesplit/response_stat.hh index 1c6e0e7e6..90be34ed0 100644 --- a/server/modules/routing/readwritesplit/response_stat.hh +++ b/server/modules/routing/readwritesplit/response_stat.hh @@ -32,24 +32,26 @@ namespace maxscale class ResponseStat { public: - /* @param ignore_first_n - the first few queries tend to have more overhead - * @param n_filter_samples - collect num samples, use median - * @param num_synch_samples - this many medians before the average should be synced, or - * @param sync_duration - this much time between syncs. + /* + * @param num_filter_samples - collect num samples, use median + * @param num_synch_medians - this many medians before the average should be synced, or + * @param sync_duration - this much time between syncs. */ - ResponseStat(int ignore_first_n = 5, - int num_filter_samples = 3, + ResponseStat(int num_filter_samples = 5, + int num_synch_medians = 500, maxbase::Duration sync_duration = std::chrono::seconds(5)); + void query_started(); void query_ended();// ok to call without a query_started + bool make_valid(); // make valid even if there are too few filter_samples bool is_valid() const; int num_samples() const; maxbase::Duration average() const; - bool sync_time_reached(int num_synch_medians); // is it time to apply the average? + bool sync_time_reached(); // is it time to apply the average? void reset(); private: - int m_ignore_first_n; const int m_num_filter_samples; + const int m_num_synch_medians; const maxbase::Duration m_sync_duration; int m_sample_count; std::vector m_samples; // N sampels from which median is used diff --git a/server/modules/routing/readwritesplit/rwsplitsession.cc b/server/modules/routing/readwritesplit/rwsplitsession.cc index 4c20ae215..bee4c6faf 100644 --- a/server/modules/routing/readwritesplit/rwsplitsession.cc +++ b/server/modules/routing/readwritesplit/rwsplitsession.cc @@ -100,8 +100,9 @@ void RWSplitSession::close() for (auto& backend : m_backends) { - const ResponseStat& stat = backend->response_stat(); - if (stat.is_valid()) + ResponseStat& stat = backend->response_stat(); + + if (stat.make_valid()) { server_add_response_average(backend->server(), stat.average().secs(), stat.num_samples()); @@ -628,7 +629,8 @@ void RWSplitSession::clientReply(GWBUF *writebuf, DCB *backend_dcb) ResponseStat& stat = backend->response_stat(); stat.query_ended(); - if (stat.is_valid() && stat.sync_time_reached(500)) // nantti, TODO + if (stat.is_valid() && (stat.sync_time_reached() || + backend->server()->response_time->num_samples()==0)) { server_add_response_average(backend->server(), stat.average().secs(), stat.num_samples());