From 3e9dadf340707f3ac7025cf1cb2d0176321e8d92 Mon Sep 17 00:00:00 2001 From: Geoffrey McRae Date: Thu, 6 Aug 2026 16:57:12 +1000 Subject: [PATCH] [idd] scheduler: reserve slots for frame subscribers Replace the oldest provisional schedule entry when the bounded client table has no empty slot. Never evict a client whose frame subscription has already been observed. This prevents rapid failed reconnects from filling every scheduler slot before a real frame subscriber can be registered. --- idd/LGIdd/CFrameScheduler.cpp | 54 +++++++++++++++++++++++------------ idd/LGIdd/CFrameScheduler.h | 1 + 2 files changed, 37 insertions(+), 18 deletions(-) diff --git a/idd/LGIdd/CFrameScheduler.cpp b/idd/LGIdd/CFrameScheduler.cpp index 4844724a..805f2fcc 100644 --- a/idd/LGIdd/CFrameScheduler.cpp +++ b/idd/LGIdd/CFrameScheduler.cpp @@ -84,6 +84,40 @@ CFrameScheduler::Client * CFrameScheduler::FindClient(uint32_t clientID) return nullptr; } +CFrameScheduler::Client * CFrameScheduler::FindOrAllocateClient( + uint32_t clientID) +{ + Client * client = FindClient(clientID); + if (client || !clientID) + return client; + + Client * replacement = nullptr; + for (Client& candidate : m_clients) + { + if (!candidate.clientID) + { + replacement = &candidate; + break; + } + + // A schedule can arrive before its frame subscriptions are visible. + // Such provisional entries must not prevent a real subscriber from + // obtaining one of the bounded scheduler slots. + if (candidate.subscribed || candidate.subscriptionSeen) + continue; + + if (!replacement || candidate.expiry < replacement->expiry) + replacement = &candidate; + } + + if (replacement) + { + *replacement = {}; + replacement->clientID = clientID; + } + return replacement; +} + CFrameScheduler::Publication * CFrameScheduler::FindPublication( const Schedule& schedule, uint32_t frameSerial) { @@ -272,15 +306,7 @@ void CFrameScheduler::UpdateSubscribers(const uint32_t * clientIDs, for (unsigned i = 0; i < count; ++i) { - Client * client = FindClient(clientIDs[i]); - if (!client) - for (Client& candidate : m_clients) - if (!candidate.clientID) - { - candidate.clientID = clientIDs[i]; - client = &candidate; - break; - } + Client * client = FindOrAllocateClient(clientIDs[i]); if (client) { @@ -362,15 +388,7 @@ bool CFrameScheduler::UpdateSchedule(uint32_t sourceClientID, return false; AcquireSRWLockExclusive(&m_lock); - Client * client = FindClient(schedule.clientID); - if (!client) - for (Client& candidate : m_clients) - if (!candidate.clientID) - { - candidate.clientID = schedule.clientID; - client = &candidate; - break; - } + Client * client = FindOrAllocateClient(schedule.clientID); if (!client) { diff --git a/idd/LGIdd/CFrameScheduler.h b/idd/LGIdd/CFrameScheduler.h index 1ac0349c..3c685531 100644 --- a/idd/LGIdd/CFrameScheduler.h +++ b/idd/LGIdd/CFrameScheduler.h @@ -114,6 +114,7 @@ private: uint64_t m_lastLogPublished = 0; Client * FindClient(uint32_t clientID); + Client * FindOrAllocateClient(uint32_t clientID); Publication * FindPublication(const Schedule& schedule, uint32_t frameSerial); bool ElectOwner(uint64_t now, uint32_t resetClientID = 0);