Use abstract_clock and improved tests, in ResourceManager

Conflicts:
	Builds/VisualStudio2012/RippleD.vcxproj.filters
This commit is contained in:
Vinnie Falco
2013-12-29 18:56:51 -08:00
parent 2d234e500d
commit b2feafa94c
10 changed files with 162 additions and 100 deletions

View File

@@ -2192,7 +2192,6 @@
<ClInclude Include="..\..\src\ripple\resource\impl\Key.h" /> <ClInclude Include="..\..\src\ripple\resource\impl\Key.h" />
<ClInclude Include="..\..\src\ripple\resource\impl\Kind.h" /> <ClInclude Include="..\..\src\ripple\resource\impl\Kind.h" />
<ClInclude Include="..\..\src\ripple\resource\impl\Logic.h" /> <ClInclude Include="..\..\src\ripple\resource\impl\Logic.h" />
<ClInclude Include="..\..\src\ripple\resource\impl\LogicType.h" />
<ClInclude Include="..\..\src\ripple\resource\impl\Tuning.h" /> <ClInclude Include="..\..\src\ripple\resource\impl\Tuning.h" />
<ClInclude Include="..\..\src\ripple\resource\ripple_resource.h" /> <ClInclude Include="..\..\src\ripple\resource\ripple_resource.h" />
<ClInclude Include="..\..\src\ripple\rocksdb\ripple_rocksdb.h" /> <ClInclude Include="..\..\src\ripple\rocksdb\ripple_rocksdb.h" />

View File

@@ -2559,9 +2559,6 @@
<ClInclude Include="..\..\src\ripple\resource\api\LegacyFees.h"> <ClInclude Include="..\..\src\ripple\resource\api\LegacyFees.h">
<Filter>[1] Ripple\resource\api</Filter> <Filter>[1] Ripple\resource\api</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\..\src\ripple\resource\impl\LogicType.h">
<Filter>[1] Ripple\resource\impl</Filter>
</ClInclude>
<ClInclude Include="..\..\src\ripple\peerfinder\impl\LogicType.h"> <ClInclude Include="..\..\src\ripple\peerfinder\impl\LogicType.h">
<Filter>[1] Ripple\peerfinder\impl</Filter> <Filter>[1] Ripple\peerfinder\impl</Filter>
</ClInclude> </ClInclude>

View File

@@ -26,9 +26,6 @@ namespace Resource {
struct Key; struct Key;
struct Entry; struct Entry;
/** Measures seconds from an unspecified fixed reference event in the past. */
typedef int DiscreteTime;
} }
} }

View File

@@ -23,6 +23,8 @@
namespace ripple { namespace ripple {
namespace Resource { namespace Resource {
typedef abstract_clock <std::chrono::seconds> clock_type;
// An entry in the table // An entry in the table
struct Entry : public List <Entry>::Node struct Entry : public List <Entry>::Node
{ {
@@ -57,14 +59,14 @@ struct Entry : public List <Entry>::Node
} }
// Balance including remote contributions // Balance including remote contributions
int balance (DiscreteTime const now) int balance (clock_type::rep const now)
{ {
return local_balance.value (now) + remote_balance; return local_balance.value (now) + remote_balance;
} }
// Add a charge and return normalized balance // Add a charge and return normalized balance
// including contributions from imports. // 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; return local_balance.add (charge, now) + remote_balance;
} }
@@ -85,10 +87,10 @@ struct Entry : public List <Entry>::Node
Disposition disposition; Disposition disposition;
// Time of the last warning // Time of the last warning
DiscreteTime lastWarningTime; clock_type::rep lastWarningTime;
// For inactive entries, time after which this entry will be erased // 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) std::ostream& operator<< (std::ostream& os, Entry const& v)

View File

@@ -39,7 +39,7 @@ struct Import
} }
// When the imported data expires // When the imported data expires
DiscreteTime whenExpires; clock_type::rep whenExpires;
// List of remote entries // List of remote entries
std::vector <Item> items; std::vector <Item> items;

View File

@@ -26,6 +26,7 @@ namespace Resource {
class Logic class Logic
{ {
public: public:
typedef abstract_clock <std::chrono::seconds> clock_type;
typedef boost::unordered_map <std::string, Import> Imports; typedef boost::unordered_map <std::string, Import> Imports;
typedef boost::unordered_map <Key, Entry, Key::hasher, Key::key_equal> Table; typedef boost::unordered_map <Key, Entry, Key::hasher, Key::key_equal> Table;
@@ -53,13 +54,13 @@ public:
typedef SharedData <State> SharedState; typedef SharedData <State> SharedState;
SharedState m_state; SharedState m_state;
DiscreteClock <DiscreteTime> m_clock; abstract_clock <std::chrono::seconds>& m_clock;
Journal m_journal; Journal m_journal;
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
Logic (DiscreteClock <DiscreteTime>::Source& source, Journal journal) Logic (clock_type& clock, Journal journal)
: m_clock (source) : m_clock (clock)
, m_journal (journal) , m_journal (journal)
{ {
} }
@@ -212,7 +213,7 @@ public:
Json::Value getJson (int threshold) Json::Value getJson (int threshold)
{ {
DiscreteTime const now (m_clock()); clock_type::rep const now (m_clock.elapsed());
Json::Value ret (Json::objectValue); Json::Value ret (Json::objectValue);
SharedState::Access state (m_state); SharedState::Access state (m_state);
@@ -262,7 +263,7 @@ public:
Gossip exportConsumers () Gossip exportConsumers ()
{ {
DiscreteTime const now (m_clock()); clock_type::rep const now (m_clock.elapsed());
Gossip gossip; Gossip gossip;
SharedState::Access state (m_state); SharedState::Access state (m_state);
@@ -288,7 +289,7 @@ public:
void importConsumers (std::string const& origin, Gossip const& gossip) 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); SharedState::Access state (m_state);
@@ -357,7 +358,7 @@ public:
{ {
SharedState::Access state (m_state); SharedState::Access state (m_state);
DiscreteTime const now (m_clock()); clock_type::rep const now (m_clock.elapsed());
for (List <Entry>::iterator iter ( for (List <Entry>::iterator iter (
state->inactive.begin()); iter != state->inactive.end();) state->inactive.begin()); iter != state->inactive.end();)
@@ -440,7 +441,7 @@ public:
break; break;
} }
state->inactive.push_back (entry); 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) 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)); int const balance (entry.add (fee.cost(), now));
m_journal.info << m_journal.info <<
"Charging " << entry << " for " << fee; "Charging " << entry << " for " << fee;
@@ -465,7 +466,7 @@ public:
bool warn (Entry& entry, SharedState::Access& state) bool warn (Entry& entry, SharedState::Access& state)
{ {
bool notify (false); bool notify (false);
DiscreteTime const now (m_clock()); clock_type::rep const now (m_clock.elapsed());
if (entry.balance (now) >= warningThreshold && now != entry.lastWarningTime) if (entry.balance (now) >= warningThreshold && now != entry.lastWarningTime)
{ {
charge (entry, feeWarning, state); charge (entry, feeWarning, state);
@@ -483,7 +484,7 @@ public:
bool disconnect (Entry& entry, SharedState::Access& state) bool disconnect (Entry& entry, SharedState::Access& state)
{ {
bool drop (false); bool drop (false);
DiscreteTime const now (m_clock()); clock_type::rep const now (m_clock.elapsed());
if (entry.balance (now) >= dropThreshold) if (entry.balance (now) >= dropThreshold)
{ {
charge (entry, feeDrop, state); charge (entry, feeDrop, state);
@@ -494,7 +495,7 @@ public:
int balance (Entry& entry, SharedState::Access& state) 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 ( void writeList (
DiscreteTime const now, clock_type::rep const now,
PropertyStream::Set& items, PropertyStream::Set& items,
List <Entry>& list) List <Entry>& list)
{ {
@@ -563,7 +564,7 @@ public:
void onWrite (PropertyStream::Map& map) void onWrite (PropertyStream::Map& map)
{ {
DiscreteTime const now (m_clock()); clock_type::rep const now (m_clock.elapsed());
SharedState::Access state (m_state); SharedState::Access state (m_state);

View File

@@ -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 DiscreteClockSourceType>
class LogicType
: private BaseFromMember <DiscreteClockSourceType>
, public Logic
{
public:
typedef typename DiscreteClockSourceType::DiscreteClockType DiscreteClockType;
explicit LogicType (Journal journal)
: Logic (BaseFromMember <DiscreteClockSourceType>::member(), journal)
{
}
DiscreteClockSourceType& clock()
{
return BaseFromMember <DiscreteClockSourceType>::member();
}
};
}
}
#endif

View File

@@ -26,12 +26,13 @@ class ManagerImp
{ {
public: public:
Journal m_journal; Journal m_journal;
LogicType <SimpleMonotonicClock> m_logic; Logic m_logic;
ManagerImp (Journal journal) ManagerImp (Journal journal)
: Thread ("Resource::Manager") : Thread ("Resource::Manager")
, m_journal (journal) , m_journal (journal)
, m_logic (journal) , m_logic (get_abstract_clock <
std::chrono::steady_clock, std::chrono::seconds> (), journal)
{ {
startThread (); startThread ();
} }

View File

@@ -23,6 +23,34 @@ namespace Resource {
class Tests : public UnitTest class Tests : public UnitTest
{ {
public: public:
class TestLogic
: private boost::base_from_member <manual_clock <std::chrono::seconds>>
, public Logic
{
private:
typedef boost::base_from_member <
manual_clock <std::chrono::seconds>> clock_type;
public:
explicit TestLogic (Journal journal)
: Logic (member, journal)
{
}
void advance ()
{
++member;
}
manual_clock <std::chrono::seconds>& clock ()
{
return member;
}
};
//--------------------------------------------------------------------------
void createGossip (Gossip& gossip) void createGossip (Gossip& gossip)
{ {
int const v (10 + random().nextInt (10)); 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"); beginTestCase ("Imports");
LogicType <ManualClock> logic (journal()); TestLogic logic (j);
Gossip g[5]; Gossip g[5];
@@ -55,11 +161,11 @@ public:
pass(); pass();
} }
void testImport () void testImport (Journal j)
{ {
beginTestCase ("Import"); beginTestCase ("Import");
LogicType <ManualClock> logic (journal()); TestLogic logic (j);
Gossip g; Gossip g;
Gossip::Item item; Gossip::Item item;
@@ -72,37 +178,41 @@ public:
pass(); pass();
} }
void testCharges () void testCharges (Journal j)
{ {
beginTestCase ("Charge"); beginTestCase ("Charge");
LogicType <ManualClock> logic (journal()); TestLogic logic (j);
{ {
IPAddress address (IPAddress::from_string ("207.127.82.1")); IPAddress address (IPAddress::from_string ("207.127.82.1"));
Consumer c (logic.newInboundEndpoint (address)); Consumer c (logic.newInboundEndpoint (address));
logMessage ("Charging " + c.to_string() + " 10,000 units"); Charge fee (1000);
c.charge (10000); j.info <<
"Charging " << c.to_string() << " " << fee << " per second";
c.charge (fee);
for (int i = 0; i < 128; ++i) for (int i = 0; i < 128; ++i)
{ {
logMessage ( j.info <<
"Time = " + String::fromNumber (logic.clock().now()) + "Time= " << logic.clock().now().time_since_epoch() <<
", Balance = " + String::fromNumber (c.balance())); ", Balance = " << c.balance();
++logic.clock().now(); logic.advance();
} }
} }
{ {
IPAddress address (IPAddress::from_string ("207.127.82.2")); IPAddress address (IPAddress::from_string ("207.127.82.2"));
Consumer c (logic.newInboundEndpoint (address)); 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) for (int i = 0; i < 128; ++i)
{ {
c.charge (1000); c.charge (fee);
logMessage ( j.info <<
"Time = " + String::fromNumber (logic.clock().now()) + "Time= " << logic.clock().now().time_since_epoch() <<
", Balance = " + String::fromNumber (c.balance())); ", Balance = " << c.balance();
++logic.clock().now(); logic.advance();
} }
} }
@@ -111,12 +221,16 @@ public:
void runTest () void runTest ()
{ {
testCharges(); //Journal j (journal());
testImports(); Journal j;
testImport();
testDrop (j);
testCharges (j);
testImports (j);
testImport (j);
} }
Tests () : UnitTest ("ResourceManager", "ripple", runManual) Tests () : UnitTest ("ResourceManager", "ripple")
{ {
} }
}; };

View File

@@ -22,9 +22,9 @@
#include "ripple_resource.h" #include "ripple_resource.h"
#include "../algorithm/api/DecayingSample.h" #include "../algorithm/api/DecayingSample.h"
#include "../algorithm/api/DiscreteClock.h"
#include "beast/modules/beast_core/system/BeforeBoost.h" #include "beast/modules/beast_core/system/BeforeBoost.h"
#include <boost/utility/base_from_member.hpp>
#include <boost/unordered_map.hpp> #include <boost/unordered_map.hpp>
#include "impl/Fees.cpp" #include "impl/Fees.cpp"
@@ -35,7 +35,6 @@
# include "impl/Import.h" # include "impl/Import.h"
#include "impl/Charge.cpp" #include "impl/Charge.cpp"
# include "impl/Logic.h" # include "impl/Logic.h"
# include "impl/LogicType.h"
#include "impl/Consumer.cpp" #include "impl/Consumer.cpp"
#include "impl/LegacyFees.cpp" #include "impl/LegacyFees.cpp"
#include "impl/Manager.cpp" #include "impl/Manager.cpp"