@@ -49,6 +49,9 @@ using std::tr1::static_pointer_cast;
4949using namespace std ;
5050using namespace epics ::pvData;
5151
52+ static const float maxBeaconLifetime = 180 .f * 2 .f;
53+ static const int maxTrackedBeacons = 2048 ;
54+
5255namespace epics {
5356namespace pvAccess {
5457
@@ -3038,7 +3041,43 @@ enum ContextState {
30383041};
30393042
30403043
3044+ /* *
3045+ * Handles cleanup of old beacons.
3046+ */
3047+ class BeaconCleanupHandler
3048+ {
3049+ public:
3050+ POINTER_DEFINITIONS (BeaconCleanupHandler);
3051+
3052+ class Callback : public TimerCallback
3053+ {
3054+ public:
3055+ Callback (BeaconCleanupHandler& handler) : m_handler(handler)
3056+ {
3057+ }
3058+
3059+ virtual void callback () OVERRIDE FINAL;
3060+ virtual void timerStopped () OVERRIDE FINAL;
30413061
3062+ BeaconCleanupHandler& m_handler;
3063+ };
3064+
3065+ BeaconCleanupHandler (InternalClientContextImpl& impl, osiSockAddr addr);
3066+ ~BeaconCleanupHandler ();
3067+
3068+ /* *
3069+ * Extend the lifetime of the beacon, resetting removal countdown to 0
3070+ */
3071+ void touch () { epicsAtomicSetIntT (&m_count, 0 ); }
3072+
3073+ private:
3074+ void remove ();
3075+
3076+ std::shared_ptr<BeaconCleanupHandler::Callback> m_callback;
3077+ osiSockAddr m_from;
3078+ InternalClientContextImpl& m_impl;
3079+ int m_count;
3080+ };
30423081
30433082class InternalClientContextImpl :
30443083 public ClientContextImpl,
@@ -4058,6 +4097,12 @@ class InternalClientContextImpl :
40584097
40594098 m_timer->close ();
40604099
4100+ // Remove all beacons
4101+ {
4102+ Lock guard (m_beaconMapMutex);
4103+ m_beaconHandlers.clear ();
4104+ }
4105+
40614106 m_channelSearchManager->cancel ();
40624107
40634108 // this will also close all PVA transports
@@ -4079,11 +4124,6 @@ class InternalClientContextImpl :
40794124 while ((transportCount = m_transportRegistry.size ()) && tries--)
40804125 epicsThreadSleep (0.025 );
40814126
4082- {
4083- Lock guard (m_beaconMapMutex);
4084- m_beaconHandlers.clear ();
4085- }
4086-
40874127 if (transportCount)
40884128 LOG (logLevelDebug, " PVA client context destroyed with %u transport(s) active." , (unsigned )transportCount);
40894129 }
@@ -4351,12 +4391,25 @@ class InternalClientContextImpl :
43514391 BeaconHandler::shared_pointer handler;
43524392 if (it == m_beaconHandlers.end ())
43534393 {
4394+ /* If we're tracking too many beacons, we'll just ignore this one */
4395+ if (m_beaconHandlers.size () >= maxTrackedBeacons)
4396+ {
4397+ char ipa[64 ];
4398+ sockAddrToDottedIP (&responseFrom->sa , ipa, sizeof (ipa));
4399+ LOG (logLevelDebug, " Tracked beacon limit reached (%d), ignoring %s\n " , maxTrackedBeacons, ipa);
4400+ return nullptr ;
4401+ }
4402+
43544403 // stores weak_ptr
43554404 handler.reset (new BeaconHandler (internal_from_this (), responseFrom));
4405+ handler->_callback .reset (new BeaconCleanupHandler (*this , *responseFrom));
43564406 m_beaconHandlers[*responseFrom] = handler;
43574407 }
43584408 else
4409+ {
43594410 handler = it->second ;
4411+ handler->_callback ->touch (); /* Update the callback's latest use time */
4412+ }
43604413 return handler;
43614414 }
43624415
@@ -4556,8 +4609,45 @@ class InternalClientContextImpl :
45564609 Configuration::shared_pointer m_configuration;
45574610
45584611 TransportRegistry::transportVector_t m_flushTransports;
4612+
4613+ friend class BeaconCleanupHandler ;
45594614};
45604615
4616+
4617+ BeaconCleanupHandler::BeaconCleanupHandler (InternalClientContextImpl& impl, osiSockAddr addr) :
4618+ m_from (addr),
4619+ m_impl (impl),
4620+ m_count (0 )
4621+ {
4622+ m_callback.reset (new Callback (*this ));
4623+ m_impl.m_timer ->schedulePeriodic (m_callback, maxBeaconLifetime / 4 , maxBeaconLifetime / 4 );
4624+ }
4625+
4626+ BeaconCleanupHandler::~BeaconCleanupHandler ()
4627+ {
4628+ m_impl.m_timer ->cancel (m_callback);
4629+ }
4630+
4631+ void BeaconCleanupHandler::Callback::callback ()
4632+ {
4633+ if (epicsAtomicIncrIntT (&m_handler.m_count ) == 5 ) {
4634+ printf (" Beacon deleted\n " );
4635+ m_handler.remove ();
4636+ }
4637+ }
4638+
4639+ void BeaconCleanupHandler::Callback::timerStopped ()
4640+ {
4641+ m_handler.remove ();
4642+ }
4643+
4644+ void BeaconCleanupHandler::remove ()
4645+ {
4646+ Lock guard (m_impl.m_beaconMapMutex );
4647+ m_impl.m_timer ->cancel (m_callback);
4648+ m_impl.m_beaconHandlers .erase (m_from);
4649+ }
4650+
45614651size_t InternalClientContextImpl::num_instances;
45624652size_t InternalClientContextImpl::InternalChannelImpl::num_instances;
45634653size_t InternalClientContextImpl::InternalChannelImpl::num_active;
0 commit comments