From b2feafa94cf9c5cd82ba2eb3f8b7f8442cfc29e5 Mon Sep 17 00:00:00 2001 From: Vinnie Falco Date: Sun, 29 Dec 2013 18:56:51 -0800 Subject: [PATCH] Use abstract_clock and improved tests, in ResourceManager Conflicts: Builds/VisualStudio2012/RippleD.vcxproj.filters --- Builds/VisualStudio2012/RippleD.vcxproj | 1 - .../VisualStudio2012/RippleD.vcxproj.filters | 3 - src/ripple/resource/api/Types.h | 3 - src/ripple/resource/impl/Entry.h | 10 +- src/ripple/resource/impl/Import.h | 2 +- src/ripple/resource/impl/Logic.h | 29 ++-- src/ripple/resource/impl/LogicType.h | 48 ------ src/ripple/resource/impl/Manager.cpp | 5 +- src/ripple/resource/impl/Tests.cpp | 158 +++++++++++++++--- src/ripple/resource/ripple_resource.cpp | 3 +- 10 files changed, 162 insertions(+), 100 deletions(-) delete mode 100644 src/ripple/resource/impl/LogicType.h diff --git a/Builds/VisualStudio2012/RippleD.vcxproj b/Builds/VisualStudio2012/RippleD.vcxproj index 833bc9e19..e34c07ff9 100644 --- a/Builds/VisualStudio2012/RippleD.vcxproj +++ b/Builds/VisualStudio2012/RippleD.vcxproj @@ -2192,7 +2192,6 @@ - diff --git a/Builds/VisualStudio2012/RippleD.vcxproj.filters b/Builds/VisualStudio2012/RippleD.vcxproj.filters index f293b033e..25fa02abd 100644 --- a/Builds/VisualStudio2012/RippleD.vcxproj.filters +++ b/Builds/VisualStudio2012/RippleD.vcxproj.filters @@ -2559,9 +2559,6 @@ [1] Ripple\resource\api - - [1] Ripple\resource\impl - [1] Ripple\peerfinder\impl diff --git a/src/ripple/resource/api/Types.h b/src/ripple/resource/api/Types.h index c788d53e3..b39ecc4a0 100644 --- a/src/ripple/resource/api/Types.h +++ b/src/ripple/resource/api/Types.h @@ -26,9 +26,6 @@ namespace Resource { struct Key; struct Entry; -/** Measures seconds from an unspecified fixed reference event in the past. */ -typedef int DiscreteTime; - } } diff --git a/src/ripple/resource/impl/Entry.h b/src/ripple/resource/impl/Entry.h index 7167659cf..35b3d0beb 100644 --- a/src/ripple/resource/impl/Entry.h +++ b/src/ripple/resource/impl/Entry.h @@ -23,6 +23,8 @@ namespace ripple { namespace Resource { +typedef abstract_clock clock_type; + // An entry in the table struct Entry : public List ::Node { @@ -57,14 +59,14 @@ struct Entry : public List ::Node } // Balance including remote contributions - int balance (DiscreteTime const now) + int balance (clock_type::rep const now) { return local_balance.value (now) + remote_balance; } // Add a charge and return normalized balance // including contributions from imports. - int add (int charge, DiscreteTime const now) + int add (int charge, clock_type::rep const now) { return local_balance.add (charge, now) + remote_balance; } @@ -85,10 +87,10 @@ struct Entry : public List ::Node Disposition disposition; // Time of the last warning - DiscreteTime lastWarningTime; + clock_type::rep lastWarningTime; // For inactive entries, time after which this entry will be erased - DiscreteTime whenExpires; + clock_type::rep whenExpires; }; std::ostream& operator<< (std::ostream& os, Entry const& v) diff --git a/src/ripple/resource/impl/Import.h b/src/ripple/resource/impl/Import.h index 43c222633..38723aa31 100644 --- a/src/ripple/resource/impl/Import.h +++ b/src/ripple/resource/impl/Import.h @@ -39,7 +39,7 @@ struct Import } // When the imported data expires - DiscreteTime whenExpires; + clock_type::rep whenExpires; // List of remote entries std::vector items; diff --git a/src/ripple/resource/impl/Logic.h b/src/ripple/resource/impl/Logic.h index 760f3afd1..d2c9e98fe 100644 --- a/src/ripple/resource/impl/Logic.h +++ b/src/ripple/resource/impl/Logic.h @@ -26,6 +26,7 @@ namespace Resource { class Logic { public: + typedef abstract_clock clock_type; typedef boost::unordered_map Imports; typedef boost::unordered_map Table; @@ -53,13 +54,13 @@ public: typedef SharedData SharedState; SharedState m_state; - DiscreteClock m_clock; + abstract_clock & m_clock; Journal m_journal; //-------------------------------------------------------------------------- - Logic (DiscreteClock ::Source& source, Journal journal) - : m_clock (source) + Logic (clock_type& clock, Journal journal) + : m_clock (clock) , m_journal (journal) { } @@ -212,7 +213,7 @@ public: Json::Value getJson (int threshold) { - DiscreteTime const now (m_clock()); + clock_type::rep const now (m_clock.elapsed()); Json::Value ret (Json::objectValue); SharedState::Access state (m_state); @@ -262,7 +263,7 @@ public: Gossip exportConsumers () { - DiscreteTime const now (m_clock()); + clock_type::rep const now (m_clock.elapsed()); Gossip gossip; SharedState::Access state (m_state); @@ -288,7 +289,7 @@ public: void importConsumers (std::string const& origin, Gossip const& gossip) { - DiscreteTime const now (m_clock()); + clock_type::rep const now (m_clock.elapsed()); { SharedState::Access state (m_state); @@ -357,7 +358,7 @@ public: { SharedState::Access state (m_state); - DiscreteTime const now (m_clock()); + clock_type::rep const now (m_clock.elapsed()); for (List ::iterator iter ( state->inactive.begin()); iter != state->inactive.end();) @@ -440,7 +441,7 @@ public: break; } state->inactive.push_back (entry); - entry.whenExpires = m_clock() + secondsUntilExpiration; + entry.whenExpires = m_clock.elapsed() + secondsUntilExpiration; } } @@ -455,7 +456,7 @@ public: Disposition charge (Entry& entry, Charge const& fee, SharedState::Access& state) { - DiscreteTime const now (m_clock()); + clock_type::rep const now (m_clock.elapsed()); int const balance (entry.add (fee.cost(), now)); m_journal.info << "Charging " << entry << " for " << fee; @@ -465,7 +466,7 @@ public: bool warn (Entry& entry, SharedState::Access& state) { bool notify (false); - DiscreteTime const now (m_clock()); + clock_type::rep const now (m_clock.elapsed()); if (entry.balance (now) >= warningThreshold && now != entry.lastWarningTime) { charge (entry, feeWarning, state); @@ -483,7 +484,7 @@ public: bool disconnect (Entry& entry, SharedState::Access& state) { bool drop (false); - DiscreteTime const now (m_clock()); + clock_type::rep const now (m_clock.elapsed()); if (entry.balance (now) >= dropThreshold) { charge (entry, feeDrop, state); @@ -494,7 +495,7 @@ public: int balance (Entry& entry, SharedState::Access& state) { - return entry.balance (m_clock()); + return entry.balance (m_clock.elapsed()); } //-------------------------------------------------------------------------- @@ -544,7 +545,7 @@ public: //-------------------------------------------------------------------------- void writeList ( - DiscreteTime const now, + clock_type::rep const now, PropertyStream::Set& items, List & list) { @@ -563,7 +564,7 @@ public: void onWrite (PropertyStream::Map& map) { - DiscreteTime const now (m_clock()); + clock_type::rep const now (m_clock.elapsed()); SharedState::Access state (m_state); diff --git a/src/ripple/resource/impl/LogicType.h b/src/ripple/resource/impl/LogicType.h deleted file mode 100644 index e33d9862b..000000000 --- a/src/ripple/resource/impl/LogicType.h +++ /dev/null @@ -1,48 +0,0 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_RESOURCE_LOGICTYPE_H_INCLUDED -#define RIPPLE_RESOURCE_LOGICTYPE_H_INCLUDED - -namespace ripple { -namespace Resource { - -template -class LogicType - : private BaseFromMember - , public Logic -{ -public: - typedef typename DiscreteClockSourceType::DiscreteClockType DiscreteClockType; - - explicit LogicType (Journal journal) - : Logic (BaseFromMember ::member(), journal) - { - } - - DiscreteClockSourceType& clock() - { - return BaseFromMember ::member(); - } -}; - -} -} - -#endif diff --git a/src/ripple/resource/impl/Manager.cpp b/src/ripple/resource/impl/Manager.cpp index 509122e65..0d7fff470 100644 --- a/src/ripple/resource/impl/Manager.cpp +++ b/src/ripple/resource/impl/Manager.cpp @@ -26,12 +26,13 @@ class ManagerImp { public: Journal m_journal; - LogicType m_logic; + Logic m_logic; ManagerImp (Journal journal) : Thread ("Resource::Manager") , m_journal (journal) - , m_logic (journal) + , m_logic (get_abstract_clock < + std::chrono::steady_clock, std::chrono::seconds> (), journal) { startThread (); } diff --git a/src/ripple/resource/impl/Tests.cpp b/src/ripple/resource/impl/Tests.cpp index cced99d0a..a7a1f40f8 100644 --- a/src/ripple/resource/impl/Tests.cpp +++ b/src/ripple/resource/impl/Tests.cpp @@ -23,6 +23,34 @@ namespace Resource { class Tests : public UnitTest { public: + class TestLogic + : private boost::base_from_member > + , public Logic + + { + private: + typedef boost::base_from_member < + manual_clock > clock_type; + + public: + explicit TestLogic (Journal journal) + : Logic (member, journal) + { + } + + void advance () + { + ++member; + } + + manual_clock & clock () + { + return member; + } + }; + + //-------------------------------------------------------------------------- + void createGossip (Gossip& gossip) { int const v (10 + random().nextInt (10)); @@ -38,11 +66,89 @@ public: } } - void testImports () + //-------------------------------------------------------------------------- + + enum + { + maxLoopCount = 10000 + }; + + void testDrop (Journal j) + { + beginTestCase ("Warn/drop"); + + Tests::TestLogic logic (j); + + Charge const fee (dropThreshold + 1); + IPAddress const addr ( + IPAddress::from_string ("207.127.82.2")); + + { + Consumer c (logic.newInboundEndpoint (addr)); + + // Create load until we get a warning + for (std::size_t n (maxLoopCount); n>=0; --n) + { + if (n == 0) + { + fail ("Loop count exceeded without warning"); + return; + } + + if (c.charge (fee) == warn) + { + pass (); + break; + } + ++logic.clock (); + } + + // Create load until we get dropped + for (std::size_t n (maxLoopCount); n>=0; --n) + { + if (n == 0) + { + fail ("Loop count exceeded without dropping"); + return; + } + + if (c.charge (fee) == drop) + { + pass (); + break; + } + ++logic.clock (); + } + + } + + { + Consumer c (logic.newInboundEndpoint (addr)); + expect (c.disconnect ()); + } + + for (std::size_t n (maxLoopCount); n>=0; --n) + { + Consumer c (logic.newInboundEndpoint (addr)); + if (n == 0) + { + fail ("Loop count exceeded without expiring black list"); + return; + } + + if (c.disposition() != drop) + { + pass (); + break; + } + } + } + + void testImports (Journal j) { beginTestCase ("Imports"); - LogicType logic (journal()); + TestLogic logic (j); Gossip g[5]; @@ -55,11 +161,11 @@ public: pass(); } - void testImport () + void testImport (Journal j) { beginTestCase ("Import"); - LogicType logic (journal()); + TestLogic logic (j); Gossip g; Gossip::Item item; @@ -72,37 +178,41 @@ public: pass(); } - void testCharges () + void testCharges (Journal j) { beginTestCase ("Charge"); - LogicType logic (journal()); + TestLogic logic (j); { IPAddress address (IPAddress::from_string ("207.127.82.1")); Consumer c (logic.newInboundEndpoint (address)); - logMessage ("Charging " + c.to_string() + " 10,000 units"); - c.charge (10000); + Charge fee (1000); + j.info << + "Charging " << c.to_string() << " " << fee << " per second"; + c.charge (fee); for (int i = 0; i < 128; ++i) { - logMessage ( - "Time = " + String::fromNumber (logic.clock().now()) + - ", Balance = " + String::fromNumber (c.balance())); - ++logic.clock().now(); + j.info << + "Time= " << logic.clock().now().time_since_epoch() << + ", Balance = " << c.balance(); + logic.advance(); } } { IPAddress address (IPAddress::from_string ("207.127.82.2")); Consumer c (logic.newInboundEndpoint (address)); - logMessage ("Charging " + c.to_string() + " 1000 units per second"); + Charge fee (1000); + j.info << + "Charging " << c.to_string() << " " << fee << " per second"; for (int i = 0; i < 128; ++i) { - c.charge (1000); - logMessage ( - "Time = " + String::fromNumber (logic.clock().now()) + - ", Balance = " + String::fromNumber (c.balance())); - ++logic.clock().now(); + c.charge (fee); + j.info << + "Time= " << logic.clock().now().time_since_epoch() << + ", Balance = " << c.balance(); + logic.advance(); } } @@ -111,12 +221,16 @@ public: void runTest () { - testCharges(); - testImports(); - testImport(); + //Journal j (journal()); + Journal j; + + testDrop (j); + testCharges (j); + testImports (j); + testImport (j); } - Tests () : UnitTest ("ResourceManager", "ripple", runManual) + Tests () : UnitTest ("ResourceManager", "ripple") { } }; diff --git a/src/ripple/resource/ripple_resource.cpp b/src/ripple/resource/ripple_resource.cpp index ac5c57ede..62db919d2 100644 --- a/src/ripple/resource/ripple_resource.cpp +++ b/src/ripple/resource/ripple_resource.cpp @@ -22,9 +22,9 @@ #include "ripple_resource.h" #include "../algorithm/api/DecayingSample.h" -#include "../algorithm/api/DiscreteClock.h" #include "beast/modules/beast_core/system/BeforeBoost.h" +#include #include #include "impl/Fees.cpp" @@ -35,7 +35,6 @@ # include "impl/Import.h" #include "impl/Charge.cpp" # include "impl/Logic.h" -# include "impl/LogicType.h" #include "impl/Consumer.cpp" #include "impl/LegacyFees.cpp" #include "impl/Manager.cpp"