Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

clientContextImpl: Cap the number and age of beacons #191

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions src/remote/pv/beaconHandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@
#include <pv/remote.h>
#include <pv/pvAccess.h>

namespace
{
class InternalClientContextImpl;
class BeaconCleanupHandler;
}

namespace epics {
namespace pvAccess {

Expand Down Expand Up @@ -85,6 +91,10 @@ class BeaconHandler
* First beacon flag.
*/
bool _first;
/**
* Callback for cleaning up the beacon
*/
std::shared_ptr<BeaconCleanupHandler> _callback;

/**
* Update beacon.
Expand All @@ -100,6 +110,8 @@ class BeaconHandler
ServerGUID const &guid,
epics::pvData::int16 sequentalID,
epics::pvData::int16 changeCount);

friend class ::InternalClientContextImpl;
};

}
Expand Down
88 changes: 88 additions & 0 deletions src/remoteClient/clientContextImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ using std::tr1::static_pointer_cast;
using namespace std;
using namespace epics::pvData;

static const float maxBeaconLifetime = 180.f * 2.f;
static const int maxTrackedBeacons = 20000;

namespace epics {
namespace pvAccess {

Expand Down Expand Up @@ -3038,7 +3041,43 @@ enum ContextState {
};


/**
* Handles cleanup of old beacons.
*/
class BeaconCleanupHandler
{
public:
POINTER_DEFINITIONS(BeaconCleanupHandler);

class Callback : public TimerCallback
{
public:
Callback(BeaconCleanupHandler& handler) : m_handler(handler)
{
}

virtual void callback() OVERRIDE FINAL;
virtual void timerStopped() OVERRIDE FINAL;

BeaconCleanupHandler& m_handler;
};

BeaconCleanupHandler(InternalClientContextImpl& impl, osiSockAddr addr);
~BeaconCleanupHandler();

/**
* Set the last time used to the current time
*/
void touch() { epicsTimeGetCurrent(&m_lastTime); }

private:
void remove();

std::shared_ptr<Callback> m_callback;
osiSockAddr m_from;
InternalClientContextImpl& m_impl;
epicsTimeStamp m_lastTime;
};

class InternalClientContextImpl :
public ClientContextImpl,
Expand Down Expand Up @@ -4351,12 +4390,25 @@ class InternalClientContextImpl :
BeaconHandler::shared_pointer handler;
if (it == m_beaconHandlers.end())
{
/* If we're tracking too many beacons, we'll just ignore this one */
if (m_beaconHandlers.size() >= maxTrackedBeacons)
{
char ipa[64];
sockAddrToDottedIP(&responseFrom->sa, ipa, sizeof(ipa));
LOG(logLevelDebug, "Tracked beacon limit reached (%d), ignoring %s\n", maxTrackedBeacons, ipa);
Comment on lines +4394 to +4398
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To minimize log spam it would be friendlier to only log when size()==max. So once each time the limit is reached, but not again until falling below the limit. eg. consider if some PVA server gets stuck in a reset loop.

return nullptr;
}

// stores weak_ptr
handler.reset(new BeaconHandler(internal_from_this(), responseFrom));
handler->_callback = std::make_shared<BeaconCleanupHandler>(*this, *responseFrom);
m_beaconHandlers[*responseFrom] = handler;
}
else
{
handler = it->second;
handler->_callback->touch(); /* Update the callback's latest use time */
}
return handler;
}

Expand Down Expand Up @@ -4556,8 +4608,44 @@ class InternalClientContextImpl :
Configuration::shared_pointer m_configuration;

TransportRegistry::transportVector_t m_flushTransports;

friend class BeaconCleanupHandler;
};


BeaconCleanupHandler::BeaconCleanupHandler(InternalClientContextImpl& impl, osiSockAddr addr) :
m_callback(std::make_shared<Callback>(*this)),
m_from(addr),
m_impl(impl)
{
m_impl.m_timer->schedulePeriodic(m_callback, maxBeaconLifetime, maxBeaconLifetime);
}

BeaconCleanupHandler::~BeaconCleanupHandler()
{
m_impl.m_timer->cancel(m_callback);
}

void BeaconCleanupHandler::Callback::callback()
{
epicsTimeStamp ts;
epicsTimeGetCurrent(&ts);
if (epicsTimeDiffInSeconds(&ts, &m_handler.m_lastTime) > maxBeaconLifetime)
m_handler.remove();
}

void BeaconCleanupHandler::Callback::timerStopped()
{
m_handler.remove();
}

void BeaconCleanupHandler::remove()
{
Lock guard(m_impl.m_beaconMapMutex);
m_impl.m_timer->cancel(m_callback);
m_impl.m_beaconHandlers.erase(m_from); /* Erase the beacon entirely */
}

size_t InternalClientContextImpl::num_instances;
size_t InternalClientContextImpl::InternalChannelImpl::num_instances;
size_t InternalClientContextImpl::InternalChannelImpl::num_active;
Expand Down