diff --git a/include/maxscale/server.h b/include/maxscale/server.h index 8e8e9af4d..0507d1d64 100644 --- a/include/maxscale/server.h +++ b/include/maxscale/server.h @@ -159,6 +159,9 @@ typedef struct server * by rwsplit. TODO: Move to rwsplit */ bool warn_ssl_not_enabled; /**< SSL not used for an SSL enabled server */ MxsDiskSpaceThreshold* disk_space_threshold; /**< Disk space thresholds */ + // TODO, this is a plain ptr to a C++ class. Soonish, when the server is new/deleted + // this will become a std::unique ptr. But not in this commit. + maxbase::EMAverage* response_time; /**< for calculating average response time */ } SERVER; /** @@ -444,6 +447,17 @@ json_t* server_list_to_json(const char* host); */ bool server_set_disk_space_threshold(SERVER *server, const char *disk_space_threshold); +/** + * @brief Add a response average to the server response average. + * + * @param server The server. + * @param ave Average. + * @param num_samples Number of samples the average consists of. + * + */ +void server_add_response_average(SERVER *server, double ave, int num_samples); + +extern int server_free(SERVER *server); extern SERVER *server_find_by_unique_name(const char *name); extern int server_find_by_unique_names(char **server_names, int size, SERVER*** output); extern SERVER *server_find(const char *servname, unsigned short port); @@ -455,7 +469,8 @@ extern void server_transfer_status(SERVER *dest_server, const SERVER *source_ser extern void server_add_mon_user(SERVER *server, const char *user, const char *passwd); extern size_t server_get_parameter(const SERVER *server, const char *name, char* out, size_t size); extern void server_update_credentials(SERVER *server, const char *user, const char *passwd); -extern DCB* server_get_persistent(SERVER *server, const char *user, const char* ip, const char *protocol, int id); +extern DCB* server_get_persistent(SERVER *server, const char *user, const char* ip, const char *protocol, + int id); extern void server_update_address(SERVER *server, const char *address); extern void server_update_port(SERVER *server, unsigned short port); extern uint64_t server_map_status(const char *str); diff --git a/maxutils/maxbase/src/average.cc b/maxutils/maxbase/src/average.cc index 242d1821f..bff3f7ab0 100644 --- a/maxutils/maxbase/src/average.cc +++ b/maxutils/maxbase/src/average.cc @@ -62,7 +62,9 @@ void CumulativeAverage::reset() } EMAverage::EMAverage(double min_alpha, double max_alpha, int sample_max) : - m_min_alpha{min_alpha}, m_max_alpha{max_alpha}, m_sample_max{sample_max} + m_min_alpha{min_alpha}, + m_max_alpha{max_alpha}, + m_sample_max{sample_max} { } diff --git a/server/core/config.cc b/server/core/config.cc index e0b245cd3..f6df90729 100644 --- a/server/core/config.cc +++ b/server/core/config.cc @@ -3608,6 +3608,11 @@ int create_new_server(CONFIG_CONTEXT *obj) } } + // nantti, TODO. Decide whether to expose some of this in config, or if the values + // can be calculated at runtime. The "500" or sample_max affects how often a + // session should updates this stat. sample_max should be slightly lower than max sample + // rate (which is less than qps due to the noise filter). + server->response_time = new (std::nothrow) maxbase::EMAverage(0.04, 0.35, 500); } else { @@ -4615,7 +4620,7 @@ bool get_suffixed_size(const char* value, uint64_t* dest) } bool config_parse_disk_space_threshold(MxsDiskSpaceThreshold* pDisk_space_threshold, - const char* zDisk_space_threshold) + const char* zDisk_space_threshold) { mxb_assert(pDisk_space_threshold); mxb_assert(zDisk_space_threshold); diff --git a/server/core/server.cc b/server/core/server.cc index 0dd825238..75505e779 100644 --- a/server/core/server.cc +++ b/server/core/server.cc @@ -28,6 +28,9 @@ #include #include #include +#include + +#include #include #include @@ -228,6 +231,7 @@ void server_free(Server* server) } delete server->disk_space_threshold; + delete server->response_time; delete server; } @@ -551,6 +555,18 @@ dprintServer(DCB *dcb, const SERVER *server) dcb_printf(dcb, "\tCurrent no. of conns: %d\n", server->stats.n_current); dcb_printf(dcb, "\tCurrent no. of operations: %d\n", server->stats.n_current_ops); dcb_printf(dcb, "\tNumber of routed packets: %lu\n", server->stats.packets); + std::ostringstream ave_os; + if (server->response_time->num_samples()) + { + maxbase::Duration dur(server->response_time->average()); + ave_os << dur; + } + else + { + ave_os << "not available"; + } + dcb_printf(dcb, "\tAverage response time: %s\n", ave_os.str().c_str()); + if (server->persistpoolmax) { dcb_printf(dcb, "\tPersistent pool size: %d\n", server->stats.n_persistent); @@ -1491,3 +1507,10 @@ bool server_set_disk_space_threshold(SERVER *server, const char *disk_space_thre return rv; } + +void server_add_response_average(SERVER *server, double ave, int num_samples) +{ + spinlock_acquire(&server->lock); + server->response_time->add(ave, num_samples); + spinlock_release(&server->lock); +} diff --git a/server/modules/routing/readwritesplit/readwritesplit.cc b/server/modules/routing/readwritesplit/readwritesplit.cc index c12fbb27d..90f81af4a 100644 --- a/server/modules/routing/readwritesplit/readwritesplit.cc +++ b/server/modules/routing/readwritesplit/readwritesplit.cc @@ -86,14 +86,15 @@ static bool rwsplit_process_router_options(Config& config, char **options) select_criteria_t c = GET_SELECT_CRITERIA(value); mxb_assert(c == LEAST_GLOBAL_CONNECTIONS || c == LEAST_ROUTER_CONNECTIONS || c == LEAST_BEHIND_MASTER || - c == LEAST_CURRENT_OPERATIONS || c == UNDEFINED_CRITERIA); + c == LEAST_CURRENT_OPERATIONS || c == LOWEST_RESPONSE_TIME || + c == UNDEFINED_CRITERIA); if (c == UNDEFINED_CRITERIA) { MXS_ERROR("Unknown slave selection criteria \"%s\". " "Allowed values are LEAST_GLOBAL_CONNECTIONS, " - "LEAST_ROUTER_CONNECTIONS, LEAST_BEHIND_MASTER," - "and LEAST_CURRENT_OPERATIONS.", + "LEAST_ROUTER_CONNECTIONS, LEAST_BEHIND_MASTER, " + "LEAST_CURRENT_OPERATIONS and LOWEST_RESPONSE_TIME.", STRCRITERIA(config.slave_selection_criteria)); success = false; } diff --git a/server/modules/routing/readwritesplit/readwritesplit.hh b/server/modules/routing/readwritesplit/readwritesplit.hh index 18c606d3f..0ef1e7532 100644 --- a/server/modules/routing/readwritesplit/readwritesplit.hh +++ b/server/modules/routing/readwritesplit/readwritesplit.hh @@ -66,7 +66,7 @@ enum select_criteria_t LEAST_ROUTER_CONNECTIONS, /**< connections established by this router */ LEAST_BEHIND_MASTER, LEAST_CURRENT_OPERATIONS, - DEFAULT_CRITERIA = LEAST_CURRENT_OPERATIONS, + LOWEST_RESPONSE_TIME, LAST_CRITERIA /**< not used except for an index */ }; @@ -103,6 +103,7 @@ static const MXS_ENUM_VALUE slave_selection_criteria_values[] = {"LEAST_ROUTER_CONNECTIONS", LEAST_ROUTER_CONNECTIONS}, {"LEAST_BEHIND_MASTER", LEAST_BEHIND_MASTER}, {"LEAST_CURRENT_OPERATIONS", LEAST_CURRENT_OPERATIONS}, + {"LOWEST_RESPONSE_TIME", LOWEST_RESPONSE_TIME}, {NULL} }; @@ -134,7 +135,9 @@ static const MXS_ENUM_VALUE master_failure_mode_values[] = strncmp(s,"LEAST_ROUTER_CONNECTIONS", strlen("LEAST_ROUTER_CONNECTIONS")) == 0 ? \ LEAST_ROUTER_CONNECTIONS : ( \ strncmp(s,"LEAST_CURRENT_OPERATIONS", strlen("LEAST_CURRENT_OPERATIONS")) == 0 ? \ - LEAST_CURRENT_OPERATIONS : UNDEFINED_CRITERIA)))) + LEAST_CURRENT_OPERATIONS : ( \ + strncmp(s,"LOWEST_RESPONSE_TIME", strlen("LOWEST_RESPONSE_TIME")) == 0 ? \ + LOWEST_RESPONSE_TIME : UNDEFINED_CRITERIA))))) #define BACKEND_TYPE(b) (server_is_master((b)->backend_server) ? BE_MASTER : \ (server_is_slave((b)->backend_server) ? BE_SLAVE : BE_UNDEFINED)); @@ -337,6 +340,9 @@ static inline const char* select_criteria_to_str(select_criteria_t type) case LEAST_CURRENT_OPERATIONS: return "LEAST_CURRENT_OPERATIONS"; + case LOWEST_RESPONSE_TIME: + return "LOWEST_RESPONSE_TIME"; + default: return "UNDEFINED_CRITERIA"; }