From a9ce319e7697422ed17ae042789ede03cb764b8d Mon Sep 17 00:00:00 2001 From: Stephen Shelton Date: Mon, 1 Jun 2020 09:26:31 -0600 Subject: [PATCH] Make llarp_time_t serializable in sqlite_orm --- llarp/peerstats/orm.hpp | 55 +++++++++++++++++++++++++++++++-- llarp/peerstats/peer_db.cpp | 12 +++---- llarp/peerstats/types.cpp | 16 +++++----- llarp/peerstats/types.hpp | 6 ++-- test/peerstats/test_peer_db.cpp | 29 ++++++++--------- 5 files changed, 85 insertions(+), 33 deletions(-) diff --git a/llarp/peerstats/orm.hpp b/llarp/peerstats/orm.hpp index 3cf3a3143..ed2d6b07a 100644 --- a/llarp/peerstats/orm.hpp +++ b/llarp/peerstats/orm.hpp @@ -29,10 +29,61 @@ namespace llarp make_column("numDistinctRCsReceived", &PeerStats::numDistinctRCsReceived), make_column("numLateRCs", &PeerStats::numLateRCs), make_column("peakBandwidthBytesPerSec", &PeerStats::peakBandwidthBytesPerSec), - make_column("longestRCReceiveIntervalMs", &PeerStats::longestRCReceiveIntervalMs), - make_column("mostExpiredRCMs", &PeerStats::mostExpiredRCMs))); + make_column("longestRCReceiveInterval", &PeerStats::longestRCReceiveInterval), + make_column("leastRCRemainingLifetime", &PeerStats::leastRCRemainingLifetime))); } using PeerDbStorage = decltype(initStorage("")); } // namespace llarp + +/// "custom" types for sqlite_orm +/// reference: https://github.com/fnc12/sqlite_orm/blob/master/examples/enum_binding.cpp +namespace sqlite_orm +{ + template <> + struct type_printer : public integer_printer + { + }; + + template <> + struct statement_binder + { + int + bind(sqlite3_stmt* stmt, int index, const llarp_time_t& value) + { + return statement_binder().bind(stmt, index, value.count()); + } + }; + + template <> + struct field_printer + { + std::string + operator()(const llarp_time_t& value) const + { + std::stringstream stream; + stream << value.count(); + return stream.str(); + } + }; + + template <> + struct row_extractor + { + llarp_time_t + extract(const char* row_value) + { + int64_t raw = static_cast(atoi(row_value)); + return llarp_time_t(raw); + } + + llarp_time_t + extract(sqlite3_stmt* stmt, int columnIndex) + { + auto str = sqlite3_column_text(stmt, columnIndex); + return this->extract((const char*)str); + } + }; + +} // namespace sqlite_orm diff --git a/llarp/peerstats/peer_db.cpp b/llarp/peerstats/peer_db.cpp index 8b3cb26ab..77fe40871 100644 --- a/llarp/peerstats/peer_db.cpp +++ b/llarp/peerstats/peer_db.cpp @@ -203,7 +203,7 @@ namespace llarp auto& stats = m_peerStats[id]; stats.routerId = id.ToString(); - const bool isNewRC = (stats.lastRCUpdated < rc.last_updated.count()); + const bool isNewRC = (stats.lastRCUpdated < rc.last_updated); if (isNewRC) { @@ -211,20 +211,20 @@ namespace llarp if (stats.numDistinctRCsReceived > 1) { - const int64_t prevRCExpiration = (stats.lastRCUpdated + RouterContact::Lifetime.count()); + auto prevRCExpiration = (stats.lastRCUpdated + RouterContact::Lifetime); // we track max expiry as the delta between (last expiration time - time received), // and this value will be negative for an unhealthy router // TODO: handle case where new RC is also expired? just ignore? - int64_t expiry = (prevRCExpiration - now.count()); + auto expiry = prevRCExpiration - now; if (stats.numDistinctRCsReceived == 2) - stats.mostExpiredRCMs = expiry; + stats.leastRCRemainingLifetime = expiry; else - stats.mostExpiredRCMs = std::min(stats.mostExpiredRCMs, expiry); + stats.leastRCRemainingLifetime = std::min(stats.leastRCRemainingLifetime, expiry); } - stats.lastRCUpdated = rc.last_updated.count(); + stats.lastRCUpdated = rc.last_updated; stats.stale = true; } } diff --git a/llarp/peerstats/types.cpp b/llarp/peerstats/types.cpp index f3cd5368c..21aefa4e3 100644 --- a/llarp/peerstats/types.cpp +++ b/llarp/peerstats/types.cpp @@ -27,9 +27,8 @@ namespace llarp numLateRCs += other.numLateRCs; peakBandwidthBytesPerSec = std::max(peakBandwidthBytesPerSec, other.peakBandwidthBytesPerSec); - longestRCReceiveIntervalMs = - std::max(longestRCReceiveIntervalMs, other.longestRCReceiveIntervalMs); - mostExpiredRCMs = std::max(mostExpiredRCMs, other.mostExpiredRCMs); + longestRCReceiveInterval = std::max(longestRCReceiveInterval, other.longestRCReceiveInterval); + leastRCRemainingLifetime = std::max(leastRCRemainingLifetime, other.leastRCRemainingLifetime); lastRCUpdated = std::max(lastRCUpdated, other.lastRCUpdated); return *this; @@ -52,8 +51,9 @@ namespace llarp and numLateRCs == other.numLateRCs and peakBandwidthBytesPerSec == other.peakBandwidthBytesPerSec - and longestRCReceiveIntervalMs == other.longestRCReceiveIntervalMs - and mostExpiredRCMs == other.mostExpiredRCMs and lastRCUpdated == other.lastRCUpdated; + and longestRCReceiveInterval == other.longestRCReceiveInterval + and leastRCRemainingLifetime == other.leastRCRemainingLifetime + and lastRCUpdated == other.lastRCUpdated; } util::StatusObject @@ -73,9 +73,9 @@ namespace llarp {"numDistinctRCsReceived", numDistinctRCsReceived}, {"numLateRCs", numLateRCs}, // {"peakBandwidthBytesPerSec", peakBandwidthBytesPerSec}, - {"longestRCReceiveIntervalMs", longestRCReceiveIntervalMs}, - {"mostExpiredRCMs", mostExpiredRCMs}, - {"lastRCUpdated", lastRCUpdated}, + {"longestRCReceiveInterval", longestRCReceiveInterval.count()}, + {"leastRCRemainingLifetime", leastRCRemainingLifetime.count()}, + {"lastRCUpdated", lastRCUpdated.count()}, }; } diff --git a/llarp/peerstats/types.hpp b/llarp/peerstats/types.hpp index c7987c6e8..81be0a9bc 100644 --- a/llarp/peerstats/types.hpp +++ b/llarp/peerstats/types.hpp @@ -31,9 +31,9 @@ namespace llarp int32_t numLateRCs = 0; double peakBandwidthBytesPerSec = 0; - int64_t longestRCReceiveIntervalMs = 0; - int64_t mostExpiredRCMs = 0; - int64_t lastRCUpdated = 0; + llarp_time_t longestRCReceiveInterval = 0ms; + llarp_time_t leastRCRemainingLifetime = 0ms; + llarp_time_t lastRCUpdated = 0ms; // not serialized bool stale = true; diff --git a/test/peerstats/test_peer_db.cpp b/test/peerstats/test_peer_db.cpp index 414b49fda..2e2401a06 100644 --- a/test/peerstats/test_peer_db.cpp +++ b/test/peerstats/test_peer_db.cpp @@ -131,27 +131,27 @@ TEST_CASE("Test PeerDb handleGossipedRC", "[PeerDb]") auto stats = db.getCurrentPeerStats(id); CHECK(stats.has_value()); - CHECK(stats.value().mostExpiredRCMs == 0); // not calculated on first received RC + CHECK(stats.value().leastRCRemainingLifetime == 0ms); // not calculated on first received RC CHECK(stats.value().numDistinctRCsReceived == 1); - CHECK(stats.value().lastRCUpdated == 10000); + CHECK(stats.value().lastRCUpdated == 10000ms); now = 9s; db.handleGossipedRC(rc, now); stats = db.getCurrentPeerStats(id); CHECK(stats.has_value()); // these values should remain unchanged, this is not a new RC - CHECK(stats.value().mostExpiredRCMs == 0); + CHECK(stats.value().leastRCRemainingLifetime == 0ms); CHECK(stats.value().numDistinctRCsReceived == 1); - CHECK(stats.value().lastRCUpdated == 10000); + CHECK(stats.value().lastRCUpdated == 10000ms); rc.last_updated = 11s; db.handleGossipedRC(rc, now); stats = db.getCurrentPeerStats(id); // should be (previous expiration time - new received time) - CHECK(stats.value().mostExpiredRCMs == ((10s + rcLifetime) - now).count()); + CHECK(stats.value().leastRCRemainingLifetime == ((10s + rcLifetime) - now)); CHECK(stats.value().numDistinctRCsReceived == 2); - CHECK(stats.value().lastRCUpdated == 11000); + CHECK(stats.value().lastRCUpdated == 11000ms); } TEST_CASE("Test PeerDb handleGossipedRC expiry calcs", "[PeerDb]") @@ -194,24 +194,25 @@ TEST_CASE("Test PeerDb handleGossipedRC expiry calcs", "[PeerDb]") db.handleGossipedRC(rc1, r1); auto stats1 = db.getCurrentPeerStats(id); CHECK(stats1.has_value()); - CHECK(stats1.value().mostExpiredRCMs == 0); + CHECK(stats1.value().leastRCRemainingLifetime == 0ms); CHECK(stats1.value().numDistinctRCsReceived == 1); - CHECK(stats1.value().lastRCUpdated == s1.count()); + CHECK(stats1.value().lastRCUpdated == s1); db.handleGossipedRC(rc2, r2); auto stats2 = db.getCurrentPeerStats(id); CHECK(stats2.has_value()); - CHECK(stats2.value().mostExpiredRCMs == (e1 - r2).count()); - CHECK(stats2.value().mostExpiredRCMs > 0); // ensure positive indicates healthy + CHECK(stats2.value().leastRCRemainingLifetime == (e1 - r2)); + CHECK(stats2.value().leastRCRemainingLifetime > 0ms); // ensure positive indicates healthy CHECK(stats2.value().numDistinctRCsReceived == 2); - CHECK(stats2.value().lastRCUpdated == s2.count()); + CHECK(stats2.value().lastRCUpdated == s2); db.handleGossipedRC(rc3, r3); auto stats3 = db.getCurrentPeerStats(id); CHECK(stats3.has_value()); - CHECK(stats3.value().mostExpiredRCMs == (e2 - r3).count()); + CHECK(stats3.value().leastRCRemainingLifetime == (e2 - r3)); CHECK( - stats3.value().mostExpiredRCMs < 0); // ensure negative indicates unhealthy and we use min() + stats3.value().leastRCRemainingLifetime + < 0ms); // ensure negative indicates unhealthy and we use min() CHECK(stats3.value().numDistinctRCsReceived == 3); - CHECK(stats3.value().lastRCUpdated == s3.count()); + CHECK(stats3.value().lastRCUpdated == s3); }