From fcb8a32dbef4086efbd70c543e37544661544c89 Mon Sep 17 00:00:00 2001 From: nmlgc Date: Thu, 20 Apr 2017 01:56:19 +0200 Subject: [PATCH] update: Pick servers based on the average of the last 5 ping measurements. [V] At least in my test case, this (very arbitrary) value provided enough of a buffer against the ping time spikes that happen from time to time. Unfortunately, this is also as fast as we can possibly go right now, with wininet lacking support for either HTTP/1.1 pipelining or HTTP/2, and the console model expecting a linear sequence of downloads. (Or do you *really* want multiple parallel downloads being logged all over the place?) --- thcrap_update/src/update.cpp | 33 +++++++++++++++++++++++++++++---- thcrap_update/src/update.h | 25 ++++++++++++++++++++----- 2 files changed, 49 insertions(+), 9 deletions(-) diff --git a/thcrap_update/src/update.cpp b/thcrap_update/src/update.cpp index df12d85f..a4441816 100644 --- a/thcrap_update/src/update.cpp +++ b/thcrap_update/src/update.cpp @@ -145,6 +145,30 @@ void http_exit(void) /// Internal C++ server connection handling /// --------------------------------------- +LONGLONG server_t::ping_average() const +{ + LONGLONG ret = 0; + int divisor = 0; + for(auto i : this->ping) { + ret += i; + if(i != 0) { + divisor++; + } + } + if(divisor == 0) { + return 0; + } + return ret / divisor; +} + +void server_t::ping_push(LONGLONG newval) +{ + auto type_size = sizeof(this->ping[0]); + auto elements = sizeof(this->ping) / type_size; + memmove(&this->ping[0], &this->ping[1], (elements - 1) * type_size); + ping[elements - 1] = newval; +} + void* server_t::download( DWORD *file_size, get_result_t *ret, const char *fn, const DWORD *exp_crc ) @@ -228,7 +252,7 @@ void* server_t::download( "(%d b, %.1f + %.1f ms)\n", *file_size, diff_ping_ms, diff_transfer_ms ); - this->ping = diff_ping; + this->ping_push(diff_ping); if(exp_crc) { auto crc = crc32(0, ctx.file_buffer, ctx.file_size); @@ -254,8 +278,9 @@ int servers_t::get_first() const // Get fastest server from previous data for(i = 0; i < this->size(); i++) { const auto &server = (*this)[i]; - if(server.visited() && server.ping < last_time) { - last_time = server.ping; + auto ping_average = server.ping_average(); + if(server.visited() && ping_average < last_time) { + last_time = ping_average; fastest = i; } else if(server.unused()) { tryout = i; @@ -324,7 +349,7 @@ void servers_t::from(const json_t *servers) json_t *val = json_array_get(servers, i); assert(json_is_string(val)); (*this)[i].url = json_string_value(val); - (*this)[i].ping = 0; + (*this)[i].new_session(); } } diff --git a/thcrap_update/src/update.h b/thcrap_update/src/update.h index 6d475576..ac51e1f7 100644 --- a/thcrap_update/src/update.h +++ b/thcrap_update/src/update.h @@ -68,16 +68,28 @@ struct server_t { // compiler. const char *url = NULL; + // Last 5 ping times of this server. // The raw counter value is enough for our purposes, no need to lose // precision by dividing through the frequency. - LONGLONG ping = 0; + LONGLONG ping[5]; - bool active() const { return ping >= 0; } - bool unused() const { return ping == 0; } - bool visited() const { return ping > 0; } + LONGLONG ping_average() const; + void ping_push(LONGLONG newval); + + bool active() const { return this->ping_average() >= 0; } + bool unused() const { return this->ping_average() == 0; } + bool visited() const { return this->ping_average() > 0; } void disable() { - this->ping = -1; + for(auto& i : this->ping) { + i = -1; + } + } + + void new_session() { + for(auto& i : this->ping) { + i = 0; + } } // Single-server part of servers_t::download(). @@ -89,6 +101,9 @@ struct server_t { } server_t(const char *_url) : url(_url) { + // TODO: For consistency, ping should be initialized with {0}, + // but Visual Studio 2013 doesn't implement this. + new_session(); } };