Fix Overlay stop on exit:

The stop sequence for Overlay had a race condition where autoconnect could
be called after close_all, resulting in a hang on exit. This resolves the
problem by putting the close and timer operations on a strand:
* Rename some Overlay members
* Put close on strand and tidy up members
* Use completion handler instead of coroutine for timer
* Use App io_service in PeerFinder
This commit is contained in:
Vinnie Falco
2014-11-02 10:00:36 -08:00
parent db82c35c17
commit 35f9499b67
9 changed files with 263 additions and 188 deletions

View File

@@ -2697,6 +2697,8 @@
</ClInclude> </ClInclude>
<ClInclude Include="..\..\src\ripple\peerfinder\impl\Tuning.h"> <ClInclude Include="..\..\src\ripple\peerfinder\impl\Tuning.h">
</ClInclude> </ClInclude>
<ClInclude Include="..\..\src\ripple\peerfinder\make_Manager.h">
</ClInclude>
<ClInclude Include="..\..\src\ripple\peerfinder\Manager.h"> <ClInclude Include="..\..\src\ripple\peerfinder\Manager.h">
</ClInclude> </ClInclude>
<None Include="..\..\src\ripple\peerfinder\README.md"> <None Include="..\..\src\ripple\peerfinder\README.md">

View File

@@ -3786,6 +3786,9 @@
<ClInclude Include="..\..\src\ripple\peerfinder\impl\Tuning.h"> <ClInclude Include="..\..\src\ripple\peerfinder\impl\Tuning.h">
<Filter>ripple\peerfinder\impl</Filter> <Filter>ripple\peerfinder\impl</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\..\src\ripple\peerfinder\make_Manager.h">
<Filter>ripple\peerfinder</Filter>
</ClInclude>
<ClInclude Include="..\..\src\ripple\peerfinder\Manager.h"> <ClInclude Include="..\..\src\ripple\peerfinder\Manager.h">
<Filter>ripple\peerfinder</Filter> <Filter>ripple\peerfinder</Filter>
</ClInclude> </ClInclude>

View File

@@ -21,6 +21,7 @@
#include <ripple/overlay/impl/OverlayImpl.h> #include <ripple/overlay/impl/OverlayImpl.h>
#include <ripple/overlay/impl/PeerDoor.h> #include <ripple/overlay/impl/PeerDoor.h>
#include <ripple/overlay/impl/PeerImp.h> #include <ripple/overlay/impl/PeerImp.h>
#include <ripple/peerfinder/make_Manager.h>
#include <beast/ByteOrder.h> #include <beast/ByteOrder.h>
#if DOXYGEN #if DOXYGEN
@@ -52,6 +53,64 @@ struct get_peer_json
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
OverlayImpl::Child::Child (OverlayImpl& overlay)
: overlay_(overlay)
{
}
OverlayImpl::Child::~Child()
{
overlay_.remove(*this);
}
//------------------------------------------------------------------------------
OverlayImpl::Timer::Timer (OverlayImpl& overlay)
: Child(overlay)
, timer_(overlay_.io_service_)
{
}
void
OverlayImpl::Timer::close()
{
error_code ec;
timer_.cancel(ec);
}
void
OverlayImpl::Timer::run()
{
error_code ec;
timer_.expires_from_now (std::chrono::seconds(1));
timer_.async_wait(overlay_.strand_.wrap(
std::bind(&Timer::on_timer, shared_from_this(),
beast::asio::placeholders::error)));
}
void
OverlayImpl::Timer::on_timer (error_code ec)
{
if (ec || overlay_.isStopping())
{
if (ec && ec != boost::asio::error::operation_aborted)
if (overlay_.journal_.error) overlay_.journal_.error <<
"on_timer: " << ec.message();
return;
}
overlay_.m_peerFinder->once_per_second();
overlay_.sendpeers();
overlay_.autoconnect();
timer_.expires_from_now (std::chrono::seconds(1));
timer_.async_wait(overlay_.strand_.wrap(std::bind(
&Timer::on_timer, shared_from_this(),
beast::asio::placeholders::error)));
}
//------------------------------------------------------------------------------
OverlayImpl::OverlayImpl ( OverlayImpl::OverlayImpl (
Setup const& setup, Setup const& setup,
Stoppable& parent, Stoppable& parent,
@@ -61,28 +120,30 @@ OverlayImpl::OverlayImpl (
Resolver& resolver, Resolver& resolver,
boost::asio::io_service& io_service) boost::asio::io_service& io_service)
: Overlay (parent) : Overlay (parent)
, io_service_ (io_service)
, work_ (boost::in_place(std::ref(io_service_)))
, strand_ (io_service_)
, setup_(setup) , setup_(setup)
, m_child_count (1) , journal_ (deprecatedLogs().journal("Overlay"))
, m_journal (deprecatedLogs().journal("Overlay"))
, m_resourceManager (resourceManager) , m_resourceManager (resourceManager)
, m_peerFinder (add (PeerFinder::Manager::New (*this, , m_peerFinder (PeerFinder::make_Manager (*this, io_service,
pathToDbFileOrDirectory, get_seconds_clock (), pathToDbFileOrDirectory, get_seconds_clock(),
deprecatedLogs().journal("PeerFinder")))) deprecatedLogs().journal("PeerFinder")))
, m_io_service (io_service)
, timer_(io_service)
, m_resolver (resolver) , m_resolver (resolver)
, m_nextShortId (0) , m_nextShortId (0)
{ {
beast::PropertyStream::Source::add (m_peerFinder.get());
} }
OverlayImpl::~OverlayImpl () OverlayImpl::~OverlayImpl ()
{ {
close();
// Block until dependent objects have been destroyed. // Block until dependent objects have been destroyed.
// This is just to catch improper use of the Stoppable API. // This is just to catch improper use of the Stoppable API.
// //
std::unique_lock <decltype(m_mutex)> lock (m_mutex); std::unique_lock <decltype(mutex_)> lock (mutex_);
m_cond.wait (lock, [this] { cond_.wait (lock, [this] { return list_.empty(); });
return this->m_child_count == 0; });
} }
void void
@@ -114,31 +175,25 @@ OverlayImpl::accept (socket_type&& socket)
*m_peerFinder, slot, setup_.context)); *m_peerFinder, slot, setup_.context));
{ {
std::lock_guard <decltype(m_mutex)> lock (m_mutex); std::lock_guard <decltype(mutex_)> lock (mutex_);
{ {
std::pair <PeersBySlot::iterator, bool> const result ( std::pair <PeersBySlot::iterator, bool> const result (
m_peers.emplace (slot, peer)); m_peers.emplace (slot, peer));
assert (result.second); assert (result.second);
(void) result.second; (void) result.second;
} }
++m_child_count; list_.emplace(peer.get(), peer);
// This has to happen while holding the lock, // This has to happen while holding the lock,
// otherwise the socket might not be canceled during a stop. // otherwise the socket might not be canceled during a stop.
peer->start (); peer->start();
} }
} }
void void
OverlayImpl::connect (beast::IP::Endpoint const& remote_endpoint) OverlayImpl::connect (beast::IP::Endpoint const& remote_endpoint)
{ {
if (isStopping()) assert(work_);
{
m_journal.debug <<
"Skipping " << remote_endpoint <<
" connect on stop";
return;
}
PeerFinder::Slot::ptr const slot ( PeerFinder::Slot::ptr const slot (
m_peerFinder->new_outbound_slot (remote_endpoint)); m_peerFinder->new_outbound_slot (remote_endpoint));
@@ -147,18 +202,18 @@ OverlayImpl::connect (beast::IP::Endpoint const& remote_endpoint)
return; return;
PeerImp::ptr const peer (std::make_shared <PeerImp> ( PeerImp::ptr const peer (std::make_shared <PeerImp> (
remote_endpoint, m_io_service, *this, m_resourceManager, remote_endpoint, io_service_, *this, m_resourceManager,
*m_peerFinder, slot, setup_.context)); *m_peerFinder, slot, setup_.context));
{ {
std::lock_guard <decltype(m_mutex)> lock (m_mutex); std::lock_guard <decltype(mutex_)> lock (mutex_);
{ {
std::pair <PeersBySlot::iterator, bool> const result ( std::pair <PeersBySlot::iterator, bool> const result (
m_peers.emplace (slot, peer)); m_peers.emplace (slot, peer));
assert (result.second); assert (result.second);
(void) result.second; (void) result.second;
} }
++m_child_count; list_.emplace(peer.get(), peer);
// This has to happen while holding the lock, // This has to happen while holding the lock,
// otherwise the socket might not be canceled during a stop. // otherwise the socket might not be canceled during a stop.
@@ -174,41 +229,13 @@ OverlayImpl::next_id()
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
// Check for the stopped condition
// Caller must hold the mutex
void
OverlayImpl::check_stopped ()
{
// To be stopped, child Stoppable objects must be stopped
// and the count of dependent objects must be zero
if (areChildrenStopped () && m_child_count == 0)
{
m_cond.notify_all ();
m_journal.info <<
"Stopped.";
stopped ();
}
}
// Decrement the count of dependent objects
// Caller must hold the mutex
void
OverlayImpl::release ()
{
if (--m_child_count == 0)
check_stopped ();
}
void void
OverlayImpl::remove (PeerFinder::Slot::ptr const& slot) OverlayImpl::remove (PeerFinder::Slot::ptr const& slot)
{ {
std::lock_guard <decltype(m_mutex)> lock (m_mutex); std::lock_guard <decltype(mutex_)> lock (mutex_);
PeersBySlot::iterator const iter (m_peers.find (slot)); PeersBySlot::iterator const iter (m_peers.find (slot));
assert (iter != m_peers.end ()); assert (iter != m_peers.end ());
m_peers.erase (iter); m_peers.erase (iter);
release();
} }
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
@@ -290,62 +317,36 @@ OverlayImpl::onPrepare ()
if (! getConfig ().RUN_STANDALONE) if (! getConfig ().RUN_STANDALONE)
{ {
m_doorDirect = make_PeerDoor (*this, getConfig ().PEER_IP, m_doorDirect = make_PeerDoor (*this, getConfig ().PEER_IP,
getConfig ().peerListeningPort, m_io_service); getConfig ().peerListeningPort, io_service_);
} }
} }
void void
OverlayImpl::onStart () OverlayImpl::onStart ()
{ {
// mutex not needed since we aren't running auto const timer = std::make_shared<Timer>(*this);
++m_child_count; std::lock_guard <decltype(mutex_)> lock (mutex_);
boost::asio::spawn (m_io_service, std::bind ( list_.emplace(timer.get(), timer);
&OverlayImpl::do_timer, this, std::placeholders::_1)); timer_ = timer;
} timer->run();
/** Close all peer connections.
If `graceful` is true then active
Requirements:
Caller must hold the mutex.
*/
void
OverlayImpl::close_all (bool graceful)
{
for (auto const& entry : m_peers)
{
PeerImp::ptr const peer (entry.second.lock());
// VFALCO The only case where the weak_ptr is expired should be if
// ~PeerImp is pre-empted before it calls m_peers.remove()
//
if (peer != nullptr)
peer->close();
}
} }
void void
OverlayImpl::onStop () OverlayImpl::onStop ()
{ {
error_code ec;
timer_.cancel(ec);
if (m_doorDirect) if (m_doorDirect)
m_doorDirect->stop(); m_doorDirect->stop();
if (m_doorProxy) if (m_doorProxy)
m_doorProxy->stop(); m_doorProxy->stop();
std::lock_guard <decltype(m_mutex)> lock (m_mutex); strand_.dispatch(std::bind(&OverlayImpl::close, this));
// Take off the extra count we added in the constructor
release();
close_all (false);
} }
void void
OverlayImpl::onChildrenStopped () OverlayImpl::onChildrenStopped ()
{ {
std::lock_guard <decltype(m_mutex)> lock (m_mutex); std::lock_guard <decltype(mutex_)> lock (mutex_);
check_stopped (); checkStopped ();
} }
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
@@ -368,7 +369,7 @@ OverlayImpl::onWrite (beast::PropertyStream::Map& stream)
void void
OverlayImpl::activate (Peer::ptr const& peer) OverlayImpl::activate (Peer::ptr const& peer)
{ {
std::lock_guard <decltype(m_mutex)> lock (m_mutex); std::lock_guard <decltype(mutex_)> lock (mutex_);
// Now track this peer // Now track this peer
{ {
@@ -389,7 +390,7 @@ OverlayImpl::activate (Peer::ptr const& peer)
(void) result.second; (void) result.second;
} }
m_journal.debug << journal_.debug <<
"activated " << peer->getRemoteAddress() << "activated " << peer->getRemoteAddress() <<
" (" << peer->getShortId() << " (" << peer->getShortId() <<
":" << RipplePublicKey(peer->getNodePublic()) << ")"; ":" << RipplePublicKey(peer->getNodePublic()) << ")";
@@ -406,7 +407,7 @@ OverlayImpl::activate (Peer::ptr const& peer)
void void
OverlayImpl::onPeerDisconnect (Peer::ptr const& peer) OverlayImpl::onPeerDisconnect (Peer::ptr const& peer)
{ {
std::lock_guard <decltype(m_mutex)> lock (m_mutex); std::lock_guard <decltype(mutex_)> lock (mutex_);
m_shortIdMap.erase (peer->getShortId ()); m_shortIdMap.erase (peer->getShortId ());
m_publicKeyMap.erase (peer->getNodePublic ()); m_publicKeyMap.erase (peer->getNodePublic ());
} }
@@ -416,9 +417,9 @@ OverlayImpl::onPeerDisconnect (Peer::ptr const& peer)
and are running the Ripple protocol. and are running the Ripple protocol.
*/ */
std::size_t std::size_t
OverlayImpl::size () OverlayImpl::size()
{ {
std::lock_guard <decltype(m_mutex)> lock (m_mutex); std::lock_guard <decltype(mutex_)> lock (mutex_);
return m_publicKeyMap.size (); return m_publicKeyMap.size ();
} }
@@ -434,7 +435,7 @@ OverlayImpl::getActivePeers ()
{ {
Overlay::PeerSequence ret; Overlay::PeerSequence ret;
std::lock_guard <decltype(m_mutex)> lock (m_mutex); std::lock_guard <decltype(mutex_)> lock (mutex_);
ret.reserve (m_publicKeyMap.size ()); ret.reserve (m_publicKeyMap.size ());
@@ -450,7 +451,7 @@ OverlayImpl::getActivePeers ()
Peer::ptr Peer::ptr
OverlayImpl::findPeerByShortID (Peer::ShortId const& id) OverlayImpl::findPeerByShortID (Peer::ShortId const& id)
{ {
std::lock_guard <decltype(m_mutex)> lock (m_mutex); std::lock_guard <decltype(mutex_)> lock (mutex_);
PeerByShortId::iterator const iter ( PeerByShortId::iterator const iter (
m_shortIdMap.find (id)); m_shortIdMap.find (id));
if (iter != m_shortIdMap.end ()) if (iter != m_shortIdMap.end ())
@@ -461,11 +462,38 @@ OverlayImpl::findPeerByShortID (Peer::ShortId const& id)
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
void void
OverlayImpl::autoconnect() OverlayImpl::remove (Child& child)
{ {
auto const result = m_peerFinder->autoconnect(); std::lock_guard<decltype(mutex_)> lock(mutex_);
for (auto addr : result) list_.erase(&child);
connect (addr); if (list_.empty())
checkStopped();
}
void
OverlayImpl::close()
{
std::lock_guard<decltype(mutex_)> lock(mutex_);
if (work_)
{
work_ = boost::none;
for (auto& _ : list_)
{
auto const child = _.second.lock();
// Happens when the child is about to be destroyed
if (child != nullptr)
child->close();
}
}
}
// Check for the stopped condition
// Caller must hold the mutex
void
OverlayImpl::checkStopped ()
{
if (isStopping() && areChildrenStopped () && list_.empty())
stopped();
} }
void void
@@ -477,7 +505,7 @@ OverlayImpl::sendpeers()
// VFALCO TODO Make sure this doesn't race with closing the peer // VFALCO TODO Make sure this doesn't race with closing the peer
PeerImp::ptr peer; PeerImp::ptr peer;
{ {
std::lock_guard <decltype(m_mutex)> lock (m_mutex); std::lock_guard <decltype(mutex_)> lock (mutex_);
PeersBySlot::iterator const iter = m_peers.find (e.first); PeersBySlot::iterator const iter = m_peers.find (e.first);
if (iter != m_peers.end()) if (iter != m_peers.end())
peer = iter->second.lock(); peer = iter->second.lock();
@@ -488,24 +516,11 @@ OverlayImpl::sendpeers()
} }
void void
OverlayImpl::do_timer (yield_context yield) OverlayImpl::autoconnect()
{ {
for(;;) auto const result = m_peerFinder->autoconnect();
{ for (auto addr : result)
m_peerFinder->once_per_second(); connect (addr);
sendpeers();
autoconnect();
timer_.expires_from_now (std::chrono::seconds(1));
error_code ec;
timer_.async_wait (yield[ec]);
if (ec == boost::asio::error::operation_aborted)
break;
}
// Take off a reference
std::lock_guard <decltype(m_mutex)> lock (m_mutex);
release();
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------

View File

@@ -31,6 +31,7 @@
#include <boost/asio/ssl/context.hpp> #include <boost/asio/ssl/context.hpp>
#include <boost/asio/basic_waitable_timer.hpp> #include <boost/asio/basic_waitable_timer.hpp>
#include <boost/asio/spawn.hpp> #include <boost/asio/spawn.hpp>
#include <boost/container/flat_map.hpp>
#include <beast/cxx14/memory.h> // <memory> #include <beast/cxx14/memory.h> // <memory>
#include <atomic> #include <atomic>
#include <cassert> #include <cassert>
@@ -46,38 +47,69 @@ class PeerImp;
class OverlayImpl : public Overlay class OverlayImpl : public Overlay
{ {
public:
class Child
{
protected:
OverlayImpl& overlay_;
explicit
Child (OverlayImpl& overlay);
virtual ~Child();
public:
virtual void close() = 0;
};
private: private:
using clock_type = std::chrono::steady_clock; using clock_type = std::chrono::steady_clock;
using socket_type = boost::asio::ip::tcp::socket; using socket_type = boost::asio::ip::tcp::socket;
using error_code = boost::system::error_code; using error_code = boost::system::error_code;
using yield_context = boost::asio::yield_context; using yield_context = boost::asio::yield_context;
typedef hash_map <PeerFinder::Slot::ptr, using PeersBySlot = hash_map <PeerFinder::Slot::ptr,
std::weak_ptr <PeerImp>> PeersBySlot; std::weak_ptr <PeerImp>>;
typedef hash_map <RippleAddress, Peer::ptr> PeerByPublicKey; using PeerByPublicKey = hash_map<RippleAddress, Peer::ptr>;
typedef hash_map <Peer::ShortId, Peer::ptr> PeerByShortId; using PeerByShortId = hash_map<Peer::ShortId, Peer::ptr>;
struct Timer
: Child
, std::enable_shared_from_this<Timer>
{
boost::asio::basic_waitable_timer <clock_type> timer_;
explicit
Timer (OverlayImpl& overlay);
void
close() override;
void
run();
void
on_timer (error_code ec);
};
boost::asio::io_service& io_service_;
boost::optional<boost::asio::io_service::work> work_;
boost::asio::io_service::strand strand_;
std::recursive_mutex mutex_; // VFALCO use std::mutex
std::condition_variable_any cond_;
std::weak_ptr<Timer> timer_;
boost::container::flat_map<
Child*, std::weak_ptr<Child>> list_;
Setup setup_; Setup setup_;
beast::Journal journal_;
// VFALCO TODO Change to regular mutex and eliminate re-entrancy
std::recursive_mutex m_mutex;
// Blocks us until dependent objects have been destroyed
std::condition_variable_any m_cond;
// Number of dependencies that must be destroyed before we can stop
std::size_t m_child_count;
beast::Journal m_journal;
Resource::Manager& m_resourceManager; Resource::Manager& m_resourceManager;
std::unique_ptr <PeerFinder::Manager> m_peerFinder; std::unique_ptr <PeerFinder::Manager> m_peerFinder;
boost::asio::io_service& m_io_service;
boost::asio::basic_waitable_timer <clock_type> timer_;
/** Associates slots to peers. */ /** Associates slots to peers. */
PeersBySlot m_peers; PeersBySlot m_peers;
@@ -165,32 +197,21 @@ private:
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
void
check_stopped ();
// //
// Stoppable // Stoppable
// //
void void
onPrepare () override; onPrepare() override;
void void
onStart () override; onStart() override;
/** Close all peer connections.
If `graceful` is true then active
Requirements:
Caller must hold the mutex.
*/
void
close_all (bool graceful);
void void
onStop () override; onStop() override;
void void
onChildrenStopped () override; onChildrenStopped() override;
// //
// PropertyStream // PropertyStream
@@ -202,16 +223,19 @@ private:
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
void void
release(); remove (Child& child);
void
close();
void
checkStopped ();
void void
sendpeers(); sendpeers();
void void
autoconnect(); autoconnect();
void
do_timer (yield_context yield);
}; };
} // ripple } // ripple

View File

@@ -30,7 +30,8 @@ PeerImp::PeerImp (socket_type&& socket, beast::IP::Endpoint remoteAddress,
OverlayImpl& overlay, Resource::Manager& resourceManager, OverlayImpl& overlay, Resource::Manager& resourceManager,
PeerFinder::Manager& peerFinder, PeerFinder::Slot::ptr const& slot, PeerFinder::Manager& peerFinder, PeerFinder::Slot::ptr const& slot,
std::shared_ptr<boost::asio::ssl::context> const& context) std::shared_ptr<boost::asio::ssl::context> const& context)
: journal_ (deprecatedLogs().journal("Peer")) : Child (overlay)
, journal_ (deprecatedLogs().journal("Peer"))
, ssl_bundle_(std::make_unique<beast::asio::ssl_bundle>( , ssl_bundle_(std::make_unique<beast::asio::ssl_bundle>(
context, std::move(socket))) context, std::move(socket)))
, socket_ (ssl_bundle_->socket) , socket_ (ssl_bundle_->socket)
@@ -53,7 +54,8 @@ PeerImp::PeerImp (beast::IP::Endpoint remoteAddress,
Resource::Manager& resourceManager, PeerFinder::Manager& peerFinder, Resource::Manager& resourceManager, PeerFinder::Manager& peerFinder,
PeerFinder::Slot::ptr const& slot, PeerFinder::Slot::ptr const& slot,
std::shared_ptr<boost::asio::ssl::context> const& context) std::shared_ptr<boost::asio::ssl::context> const& context)
: journal_ (deprecatedLogs().journal("Peer")) : Child (overlay)
, journal_ (deprecatedLogs().journal("Peer"))
, ssl_bundle_(std::make_unique<beast::asio::ssl_bundle>( , ssl_bundle_(std::make_unique<beast::asio::ssl_bundle>(
context, io_service)) context, io_service))
, socket_ (ssl_bundle_->socket) , socket_ (ssl_bundle_->socket)

View File

@@ -62,6 +62,7 @@ std::ostream& operator<< (std::ostream& os, PeerImp const* peer);
class PeerImp class PeerImp
: public Peer : public Peer
, public std::enable_shared_from_this <PeerImp> , public std::enable_shared_from_this <PeerImp>
, public OverlayImpl::Child
, private beast::LeakChecked <Peer> , private beast::LeakChecked <Peer>
, private abstract_protocol_handler , private abstract_protocol_handler
{ {
@@ -202,15 +203,15 @@ public:
// Begin asynchronous initiation function calls // Begin asynchronous initiation function calls
void void
start (); start();
// Cancel all I/O and close the socket
void
close();
void void
getLedger (protocol::TMGetLedger& packet); getLedger (protocol::TMGetLedger& packet);
// Cancel all I/O and close the socket
void
close() override;
// //
// Network // Network
// //

View File

@@ -121,11 +121,6 @@ protected:
explicit Manager (Stoppable& parent); explicit Manager (Stoppable& parent);
public: public:
/** Create a new Manager. */
static Manager* New (Stoppable& parent,
beast::File const& pathToDbFileOrDirectory,
clock_type& clock, beast::Journal journal);
/** Destroy the object. /** Destroy the object.
Any pending source fetch operations are aborted. Any pending source fetch operations are aborted.
There may be some listener calls made before the There may be some listener calls made before the

View File

@@ -24,6 +24,7 @@
#include <ripple/peerfinder/impl/StoreSqdb.h> #include <ripple/peerfinder/impl/StoreSqdb.h>
#include <boost/asio/io_service.hpp> #include <boost/asio/io_service.hpp>
#include <boost/optional.hpp> #include <boost/optional.hpp>
#include <beast/cxx14/memory.h> // <memory>
#include <thread> #include <thread>
#if DOXYGEN #if DOXYGEN
@@ -38,6 +39,8 @@ class ManagerImp
, public beast::LeakChecked <ManagerImp> , public beast::LeakChecked <ManagerImp>
{ {
public: public:
boost::asio::io_service &io_service_;
boost::optional <boost::asio::io_service::work> work_;
beast::File m_databaseFile; beast::File m_databaseFile;
clock_type& m_clock; clock_type& m_clock;
beast::Journal m_journal; beast::Journal m_journal;
@@ -45,19 +48,17 @@ public:
Checker<boost::asio::ip::tcp> checker_; Checker<boost::asio::ip::tcp> checker_;
Logic <decltype(checker_)> m_logic; Logic <decltype(checker_)> m_logic;
// Temporary
std::thread thread_;
boost::asio::io_service io_service_;
boost::optional <boost::asio::io_service::work> work_;
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
ManagerImp ( ManagerImp (
Stoppable& stoppable, Stoppable& stoppable,
boost::asio::io_service& io_service,
beast::File const& pathToDbFileOrDirectory, beast::File const& pathToDbFileOrDirectory,
clock_type& clock, clock_type& clock,
beast::Journal journal) beast::Journal journal)
: Manager (stoppable) : Manager (stoppable)
, io_service_(io_service)
, work_(boost::in_place(std::ref(io_service_)))
, m_databaseFile (pathToDbFileOrDirectory) , m_databaseFile (pathToDbFileOrDirectory)
, m_clock (clock) , m_clock (clock)
, m_journal (journal) , m_journal (journal)
@@ -67,23 +68,21 @@ public:
{ {
if (m_databaseFile.isDirectory ()) if (m_databaseFile.isDirectory ())
m_databaseFile = m_databaseFile.getChildFile("peerfinder.sqlite"); m_databaseFile = m_databaseFile.getChildFile("peerfinder.sqlite");
work_ = boost::in_place (std::ref(io_service_));
thread_ = std::thread ([&]() { this->io_service_.run(); });
} }
~ManagerImp() ~ManagerImp()
{ {
stop(); close();
} }
void void
stop() close()
{ {
if (thread_.joinable()) if (work_)
{ {
work_ = boost::none; work_ = boost::none;
thread_.join(); checker_.stop();
m_logic.stop();
} }
} }
@@ -228,15 +227,8 @@ public:
void onStop () void onStop ()
{ {
m_journal.debug << "Stopping"; close();
checker_.stop();
m_logic.stop();
stopped(); stopped();
/*
signalThreadShouldExit();
m_queue.dispatch (m_context.wrap (
std::bind (&Thread::signalThreadShouldExit, this)));
*/
} }
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
@@ -259,10 +251,12 @@ Manager::Manager (Stoppable& parent)
{ {
} }
Manager* Manager::New (Stoppable& parent, beast::File const& databaseFile, std::unique_ptr<Manager>
clock_type& clock, beast::Journal journal) make_Manager (beast::Stoppable& parent, boost::asio::io_service& io_service,
beast::File const& databaseFile, clock_type& clock, beast::Journal journal)
{ {
return new ManagerImp (parent, databaseFile, clock, journal); return std::make_unique<ManagerImp> (
parent, io_service, databaseFile, clock, journal);
} }
} }

View File

@@ -0,0 +1,39 @@
//------------------------------------------------------------------------------
/*
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_PEERFINDER_MAKE_MANAGER_H_INCLUDED
#define RIPPLE_PEERFINDER_MAKE_MANAGER_H_INCLUDED
#include <ripple/peerfinder/Manager.h>
#include <boost/asio/io_service.hpp>
#include <memory>
namespace ripple {
namespace PeerFinder {
/** Create a new Manager. */
std::unique_ptr<Manager>
make_Manager (beast::Stoppable& parent, boost::asio::io_service& io_service,
beast::File const& pathToDbFileOrDirectory,
clock_type& clock, beast::Journal journal);
}
}
#endif