[coap] optimize retransmission timer scheduling (#12366)

This commit optimizes the CoAP retransmission timer logic by removing
the `ScheduleRetransmissionTimer()` method, which iterated over all
pending requests to determine the next fire time.

The logic is updated as follows:
- `HandleRetransmissionTimer()` now determines the next fire time
  while iterating over the `mPendingRequests` list to process
  retransmissions. This avoids a redundant second pass over the list.
- `NextFireTime` is used to track the earliest fire time.
- `CopyAndEnqueueMessage()` uses `Timer::FireAtIfEarlier()` to
  update the timer only if the new message's fire time is earlier
  than the current schedule.
- `DequeueMessage()` no longer triggers a schedule update. If the
  dequeued message was the next to expire, the timer will fire,
  perform no actions, and then reschedule itself.
This commit is contained in:
Abtin Keshavarzian
2026-02-07 20:36:06 -08:00
committed by GitHub
parent c457b6b283
commit 54b3573761
2 changed files with 17 additions and 41 deletions
+17 -40
View File
@@ -483,31 +483,6 @@ exit:
return error;
}
void CoapBase::ScheduleRetransmissionTimer(void)
{
NextFireTime nextTime;
Metadata metadata;
for (const Message &message : mPendingRequests)
{
metadata.ReadFrom(message);
#if OPENTHREAD_CONFIG_COAP_OBSERVE_API_ENABLE
if (metadata.IsObserveSubscription())
{
// This is an RFC7641 subscription which is already acknowledged.
// We do not time it out, so skip it when determining the next
// fire time.
continue;
}
#endif
nextTime.UpdateIfEarlier(metadata.mTimerFireTime);
}
mRetransmissionTimer.FireAt(nextTime);
}
void CoapBase::HandleRetransmissionTimer(Timer &aTimer)
{
static_cast<Coap *>(static_cast<TimerMilliContext &>(aTimer).GetContext())->HandleRetransmissionTimer();
@@ -515,7 +490,7 @@ void CoapBase::HandleRetransmissionTimer(Timer &aTimer)
void CoapBase::HandleRetransmissionTimer(void)
{
TimeMilli now = TimerMilli::GetNow();
NextFireTime nextTime;
Metadata metadata;
Ip6::MessageInfo messageInfo;
@@ -523,22 +498,25 @@ void CoapBase::HandleRetransmissionTimer(void)
{
metadata.ReadFrom(message);
if (now >= metadata.mTimerFireTime)
{
#if OPENTHREAD_CONFIG_COAP_OBSERVE_API_ENABLE
if (metadata.IsObserveSubscription())
{
continue;
}
if (metadata.IsObserveSubscription())
{
// This is an RFC7641 subscription which is already
// acknowledged. We do not time it out, so skip it when
// determining the next fire time.
continue;
}
#endif
if (nextTime.GetNow() >= metadata.mTimerFireTime)
{
if (!metadata.ShouldRetransmit())
{
FinalizeCoapTransaction(message, metadata, nullptr, kErrorResponseTimeout);
continue;
}
metadata.UpdateRetxCounterAndTimeout(now);
metadata.UpdateRetxCounterAndTimeout(nextTime.GetNow());
metadata.UpdateIn(message);
if (!metadata.mAcknowledged)
@@ -547,9 +525,11 @@ void CoapBase::HandleRetransmissionTimer(void)
SendCopy(message, messageInfo);
}
}
nextTime.UpdateIfEarlier(metadata.mTimerFireTime);
}
ScheduleRetransmissionTimer();
mRetransmissionTimer.FireAt(nextTime);
}
void CoapBase::FinalizeCoapTransaction(Message &aRequest, const Metadata &aMetadata, Msg *aResponse, Error aResult)
@@ -597,18 +577,15 @@ Message *CoapBase::CopyAndEnqueueMessage(const Message &aMessage, uint16_t aCopy
SuccessOrExit(error = aMetadata.AppendTo(*messageCopy));
mPendingRequests.Enqueue(*messageCopy);
ScheduleRetransmissionTimer();
mRetransmissionTimer.FireAtIfEarlier(aMetadata.mTimerFireTime);
exit:
FreeAndNullMessageOnError(messageCopy, error);
return messageCopy;
}
void CoapBase::DequeueMessage(Message &aMessage)
{
mPendingRequests.DequeueAndFree(aMessage);
ScheduleRetransmissionTimer();
}
void CoapBase::DequeueMessage(Message &aMessage) { mPendingRequests.DequeueAndFree(aMessage); }
void CoapBase::SendCopy(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
{
-1
View File
@@ -847,7 +847,6 @@ private:
Message *InitMessage(Message *aMessage, Type aType, Uri aUri);
Message *InitResponse(Message *aMessage, const Message &aRequest);
void ScheduleRetransmissionTimer(void);
static void HandleRetransmissionTimer(Timer &aTimer);
void HandleRetransmissionTimer(void);
void ClearRequests(const Ip6::Address *aAddress);