Skip to content

Commit d62d80b

Browse files
[ReadHandler] Removed Scheduling of report from OnReadHandlerCreated (#28536)
* Removed Scheduling of report from OnReadHandlerCreated since it caused immediate scheduling before the intervals are negotiated * Separated Read reports from Subscription reports and renamed flags and accessors for clarity * Apply suggestions from code review Co-authored-by: Boris Zbarsky <bzbarsky@apple.com> * Put back rescheduling in the OnReadHandlerSubscribed, added a CanEmitReadReport() method for readhandler for read request. Fixed call order in TestReportScheduler tests * Removed redundancy by removing un-necessary OnSubscriptionAction(), added comment for OnReadHandlerSubscribed and modified reporting condition for Read reports to be sent independently from the report scheduler * Apply suggestions from code review Co-authored-by: Boris Zbarsky <bzbarsky@apple.com> * Appplied change to method name and fixe condition in SetStateFlag * Update src/app/ReadHandler.h Co-authored-by: Boris Zbarsky <bzbarsky@apple.com> * Removed un-necessary check in SetStateFlag --------- Co-authored-by: Boris Zbarsky <bzbarsky@apple.com>
1 parent 94c3882 commit d62d80b

8 files changed

+128
-128
lines changed

src/app/ReadHandler.cpp

+23-19
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,6 @@ ReadHandler::ReadHandler(ManagementCallback & apCallback, Messaging::ExchangeCon
7979

8080
VerifyOrDie(observer != nullptr);
8181
mObserver = observer;
82-
mObserver->OnReadHandlerCreated(this);
8382
}
8483

8584
#if CHIP_CONFIG_PERSIST_SUBSCRIPTIONS
@@ -92,7 +91,6 @@ ReadHandler::ReadHandler(ManagementCallback & apCallback, Observer * observer) :
9291

9392
VerifyOrDie(observer != nullptr);
9493
mObserver = observer;
95-
mObserver->OnReadHandlerCreated(this);
9694
}
9795

9896
void ReadHandler::ResumeSubscription(CASESessionManager & caseSessionManager,
@@ -235,6 +233,7 @@ CHIP_ERROR ReadHandler::OnStatusResponse(Messaging::ExchangeContext * apExchange
235233
{
236234
appCallback->OnSubscriptionEstablished(*this);
237235
}
236+
mObserver->OnSubscriptionEstablished(this);
238237
}
239238
}
240239
else
@@ -246,10 +245,10 @@ CHIP_ERROR ReadHandler::OnStatusResponse(Messaging::ExchangeContext * apExchange
246245
return CHIP_NO_ERROR;
247246
}
248247

249-
MoveToState(HandlerState::GeneratingReports);
248+
MoveToState(HandlerState::CanStartReporting);
250249
break;
251250

252-
case HandlerState::GeneratingReports:
251+
case HandlerState::CanStartReporting:
253252
case HandlerState::Idle:
254253
default:
255254
err = CHIP_ERROR_INCORRECT_STATE;
@@ -262,7 +261,7 @@ CHIP_ERROR ReadHandler::OnStatusResponse(Messaging::ExchangeContext * apExchange
262261

263262
CHIP_ERROR ReadHandler::SendStatusReport(Protocols::InteractionModel::Status aStatus)
264263
{
265-
VerifyOrReturnLogError(mState == HandlerState::GeneratingReports, CHIP_ERROR_INCORRECT_STATE);
264+
VerifyOrReturnLogError(mState == HandlerState::CanStartReporting, CHIP_ERROR_INCORRECT_STATE);
266265
if (IsPriming() || IsChunkedReport())
267266
{
268267
mSessionHandle.Grab(mExchangeCtx->GetSessionHandle());
@@ -286,7 +285,7 @@ CHIP_ERROR ReadHandler::SendStatusReport(Protocols::InteractionModel::Status aSt
286285

287286
CHIP_ERROR ReadHandler::SendReportData(System::PacketBufferHandle && aPayload, bool aMoreChunks)
288287
{
289-
VerifyOrReturnLogError(mState == HandlerState::GeneratingReports, CHIP_ERROR_INCORRECT_STATE);
288+
VerifyOrReturnLogError(mState == HandlerState::CanStartReporting, CHIP_ERROR_INCORRECT_STATE);
290289
VerifyOrDie(!IsAwaitingReportResponse()); // Should not be reportable!
291290
if (IsPriming() || IsChunkedReport())
292291
{
@@ -335,7 +334,7 @@ CHIP_ERROR ReadHandler::SendReportData(System::PacketBufferHandle && aPayload, b
335334
// Priming reports are handled when we send a SubscribeResponse.
336335
if (IsType(InteractionType::Subscribe) && !IsPriming() && !IsChunkedReport())
337336
{
338-
mObserver->OnSubscriptionAction(this);
337+
mObserver->OnSubscriptionReportSent(this);
339338
}
340339
}
341340
if (!aMoreChunks)
@@ -456,7 +455,7 @@ CHIP_ERROR ReadHandler::ProcessReadRequest(System::PacketBufferHandle && aPayloa
456455
ReturnErrorOnFailure(readRequestParser.GetIsFabricFiltered(&isFabricFiltered));
457456
SetStateFlag(ReadHandlerFlags::FabricFiltered, isFabricFiltered);
458457
ReturnErrorOnFailure(readRequestParser.ExitContainer());
459-
MoveToState(HandlerState::GeneratingReports);
458+
MoveToState(HandlerState::CanStartReporting);
460459

461460
mExchangeCtx->WillSendMessage();
462461

@@ -574,8 +573,8 @@ const char * ReadHandler::GetStateStr() const
574573
return "Idle";
575574
case HandlerState::AwaitingDestruction:
576575
return "AwaitingDestruction";
577-
case HandlerState::GeneratingReports:
578-
return "GeneratingReports";
576+
case HandlerState::CanStartReporting:
577+
return "CanStartReporting";
579578

580579
case HandlerState::AwaitingReportResponse:
581580
return "AwaitingReportResponse";
@@ -603,10 +602,17 @@ void ReadHandler::MoveToState(const HandlerState aTargetState)
603602
// If we just unblocked sending reports, let's go ahead and schedule the reporting
604603
// engine to run to kick that off.
605604
//
606-
if (aTargetState == HandlerState::GeneratingReports)
605+
if (aTargetState == HandlerState::CanStartReporting)
607606
{
608-
// mObserver will take care of scheduling the report as soon as allowed
609-
mObserver->OnBecameReportable(this);
607+
if (ShouldReportUnscheduled())
608+
{
609+
InteractionModelEngine::GetInstance()->GetReportingEngine().ScheduleRun();
610+
}
611+
else
612+
{
613+
// If we became reportable, the scheduler will schedule a run as soon as allowed
614+
mObserver->OnBecameReportable(this);
615+
}
610616
}
611617
}
612618

@@ -647,8 +653,6 @@ CHIP_ERROR ReadHandler::SendSubscribeResponse()
647653
ReturnErrorOnFailure(writer.Finalize(&packet));
648654
VerifyOrReturnLogError(mExchangeCtx, CHIP_ERROR_INCORRECT_STATE);
649655

650-
mObserver->OnSubscriptionAction(this);
651-
652656
ClearStateFlag(ReadHandlerFlags::PrimingReports);
653657
return mExchangeCtx->SendMessage(Protocols::InteractionModel::MsgType::SubscribeResponse, std::move(packet));
654658
}
@@ -785,7 +789,7 @@ CHIP_ERROR ReadHandler::ProcessSubscribeRequest(System::PacketBufferHandle && aP
785789
SetStateFlag(ReadHandlerFlags::FabricFiltered, isFabricFiltered);
786790
ReturnErrorOnFailure(Crypto::DRBG_get_bytes(reinterpret_cast<uint8_t *>(&mSubscriptionId), sizeof(mSubscriptionId)));
787791
ReturnErrorOnFailure(subscribeRequestParser.ExitContainer());
788-
MoveToState(HandlerState::GeneratingReports);
792+
MoveToState(HandlerState::CanStartReporting);
789793

790794
mExchangeCtx->WillSendMessage();
791795

@@ -872,11 +876,11 @@ void ReadHandler::ForceDirtyState()
872876

873877
void ReadHandler::SetStateFlag(ReadHandlerFlags aFlag, bool aValue)
874878
{
875-
bool oldReportable = IsReportable();
879+
bool oldReportable = ShouldStartReporting();
876880
mFlags.Set(aFlag, aValue);
877881

878882
// If we became reportable, schedule a reporting run.
879-
if (!oldReportable && IsReportable())
883+
if (!oldReportable && ShouldStartReporting())
880884
{
881885
// If we became reportable, the scheduler will schedule a run as soon as allowed
882886
mObserver->OnBecameReportable(this);
@@ -895,7 +899,7 @@ void ReadHandler::HandleDeviceConnected(void * context, Messaging::ExchangeManag
895899

896900
_this->mSessionHandle.Grab(sessionHandle);
897901

898-
_this->MoveToState(HandlerState::GeneratingReports);
902+
_this->MoveToState(HandlerState::CanStartReporting);
899903

900904
ObjectList<AttributePathParams> * attributePath = _this->mpAttributePathList;
901905
while (attributePath)

src/app/ReadHandler.h

+28-16
Original file line numberDiff line numberDiff line change
@@ -166,20 +166,23 @@ class ReadHandler : public Messaging::ExchangeDelegate
166166
public:
167167
virtual ~Observer() = default;
168168

169-
/// @brief Callback invoked to notify a ReadHandler was created and can be registered
170-
/// @param[in] apReadHandler ReadHandler getting added
171-
virtual void OnReadHandlerCreated(ReadHandler * apReadHandler) = 0;
172-
173-
/// @brief Callback invoked when a ReadHandler went from a non reportable state to a reportable state so a report can be
174-
/// sent immediately if the minimal interval allows it. Otherwise the report should be rescheduled to the earliest time
175-
/// allowed.
176-
/// @param[in] apReadHandler ReadHandler that became dirty
169+
/// @brief Callback invoked to notify a subscription was successfully established for the ReadHandler
170+
/// @param[in] apReadHandler ReadHandler that completed its subscription
171+
virtual void OnSubscriptionEstablished(ReadHandler * apReadHandler) = 0;
172+
173+
/// @brief Callback invoked when a ReadHandler went from a non reportable state to a reportable state. Indicates to the
174+
/// observer that a report should be emitted when the min interval allows it.
175+
///
176+
/// This will only be invoked for subscribe-type ReadHandler objects, and only after
177+
/// OnSubscriptionEstablished has been called.
178+
///
179+
/// @param[in] apReadHandler ReadHandler that became dirty and in HandlerState::CanStartReporting state
177180
virtual void OnBecameReportable(ReadHandler * apReadHandler) = 0;
178181

179182
/// @brief Callback invoked when the read handler needs to make sure to send a message to the subscriber within the next
180183
/// maxInterval time period.
181184
/// @param[in] apReadHandler ReadHandler that has generated a report
182-
virtual void OnSubscriptionAction(ReadHandler * apReadHandler) = 0;
185+
virtual void OnSubscriptionReportSent(ReadHandler * apReadHandler) = 0;
183186

184187
/// @brief Callback invoked when a ReadHandler is getting removed so it can be unregistered
185188
/// @param[in] apReadHandler ReadHandler getting destroyed
@@ -333,13 +336,22 @@ class ReadHandler : public Messaging::ExchangeDelegate
333336
bool IsIdle() const { return mState == HandlerState::Idle; }
334337

335338
/// @brief Returns whether the ReadHandler is in a state where it can send a report and there is data to report.
336-
bool IsReportable() const
339+
bool ShouldStartReporting() const
337340
{
338-
// Important: Anything that changes the state IsReportable must call mObserver->OnBecameReportable(this) for the scheduler
339-
// to plan the next run accordingly.
340-
return mState == HandlerState::GeneratingReports && IsDirty();
341+
// Important: Anything that changes ShouldStartReporting() from false to true
342+
// (which can only happen for subscriptions) must call
343+
// mObserver->OnBecameReportable(this).
344+
return CanStartReporting() && (ShouldReportUnscheduled() || IsDirty());
345+
}
346+
/// @brief CanStartReporting() is true if the ReadHandler is in a state where it could generate
347+
/// a (possibly empty) report if someone asked it to.
348+
bool CanStartReporting() const { return mState == HandlerState::CanStartReporting; }
349+
/// @brief ShouldReportUnscheduled() is true if the ReadHandler should be asked to generate reports
350+
/// without consulting the report scheduler.
351+
bool ShouldReportUnscheduled() const
352+
{
353+
return CanStartReporting() && (IsType(ReadHandler::InteractionType::Read) || IsPriming());
341354
}
342-
bool IsGeneratingReports() const { return mState == HandlerState::GeneratingReports; }
343355
bool IsAwaitingReportResponse() const { return mState == HandlerState::AwaitingReportResponse; }
344356

345357
// Resets the path iterator to the beginning of the whole report for generating a series of new reports.
@@ -418,14 +430,14 @@ class ReadHandler : public Messaging::ExchangeDelegate
418430
friend class chip::app::reporting::Engine;
419431
friend class chip::app::InteractionModelEngine;
420432

421-
// The report scheduler needs to be able to access StateFlag private functions IsReportable(), IsGeneratingReports(),
433+
// The report scheduler needs to be able to access StateFlag private functions ShouldStartReporting(), CanStartReporting(),
422434
// ForceDirtyState() and IsDirty() to know when to schedule a run so it is declared as a friend class.
423435
friend class chip::app::reporting::ReportScheduler;
424436

425437
enum class HandlerState : uint8_t
426438
{
427439
Idle, ///< The handler has been initialized and is ready
428-
GeneratingReports, ///< The handler has is now capable of generating reports and may generate one immediately
440+
CanStartReporting, ///< The handler has is now capable of generating reports and may generate one immediately
429441
///< or later when other criteria are satisfied (e.g hold-off for min reporting interval).
430442
AwaitingReportResponse, ///< The handler has sent the report to the client and is awaiting a status response.
431443
AwaitingDestruction, ///< The object has completed its work and is awaiting destruction by the application.

src/app/reporting/Engine.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -638,7 +638,7 @@ void Engine::Run()
638638
ReadHandler * readHandler = imEngine->ActiveHandlerAt(mCurReadHandlerIdx % (uint32_t) imEngine->mReadHandlers.Allocated());
639639
VerifyOrDie(readHandler != nullptr);
640640

641-
if (imEngine->GetReportScheduler()->IsReportableNow(readHandler))
641+
if (readHandler->ShouldReportUnscheduled() || imEngine->GetReportScheduler()->IsReportableNow(readHandler))
642642
{
643643
mRunningReadHandler = readHandler;
644644
CHIP_ERROR err = BuildAndSendSingleReportData(readHandler);
@@ -831,7 +831,7 @@ CHIP_ERROR Engine::SetDirty(AttributePathParams & aAttributePath)
831831
// We call AttributePathIsDirty for both read interactions and subscribe interactions, since we may send inconsistent
832832
// attribute data between two chunks. AttributePathIsDirty will not schedule a new run for read handlers which are
833833
// waiting for a response to the last message chunk for read interactions.
834-
if (handler->IsGeneratingReports() || handler->IsAwaitingReportResponse())
834+
if (handler->CanStartReporting() || handler->IsAwaitingReportResponse())
835835
{
836836
for (auto object = handler->GetAttributePathList(); object != nullptr; object = object->mpNext)
837837
{

src/app/reporting/ReportScheduler.h

+7-3
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ class ReportScheduler : public ReadHandler::Observer, public ICDStateObserver
8282
{
8383
Timestamp now = mTimerDelegate->GetCurrentMonotonicTimestamp();
8484

85-
return (mReadHandler->IsGeneratingReports() &&
85+
return (mReadHandler->CanStartReporting() &&
8686
(now >= mMinTimestamp && (mReadHandler->IsDirty() || now >= mMaxTimestamp || now >= mSyncTimestamp)));
8787
}
8888

@@ -139,9 +139,13 @@ class ReportScheduler : public ReadHandler::Observer, public ICDStateObserver
139139

140140
/// @brief Check whether a ReadHandler is reportable right now, taking into account its minimum and maximum intervals.
141141
/// @param aReadHandler read handler to check
142-
bool IsReportableNow(ReadHandler * aReadHandler) { return FindReadHandlerNode(aReadHandler)->IsReportableNow(); }
142+
bool IsReportableNow(ReadHandler * aReadHandler)
143+
{
144+
ReadHandlerNode * node = FindReadHandlerNode(aReadHandler);
145+
return (nullptr != node) ? node->IsReportableNow() : false;
146+
}
143147
/// @brief Check if a ReadHandler is reportable without considering the timing
144-
bool IsReadHandlerReportable(ReadHandler * aReadHandler) const { return aReadHandler->IsReportable(); }
148+
bool IsReadHandlerReportable(ReadHandler * aReadHandler) const { return aReadHandler->ShouldStartReporting(); }
145149
/// @brief Sets the ForceDirty flag of a ReadHandler
146150
void HandlerForceDirtyState(ReadHandler * aReadHandler) { aReadHandler->ForceDirtyState(); }
147151

src/app/reporting/ReportSchedulerImpl.cpp

+5-8
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,10 @@ void ReportSchedulerImpl::OnEnterActiveMode()
5454
#endif
5555
}
5656

57-
/// @brief When a ReadHandler is added, register it, which will schedule an engine run
58-
void ReportSchedulerImpl::OnReadHandlerCreated(ReadHandler * aReadHandler)
57+
/// @brief When a ReadHandler is added, register it in the scheduler node pool. Scheduling the report here is un-necessary since the
58+
/// ReadHandler will call MoveToState(HandlerState::CanStartReporting);, which will call OnBecameReportable() and schedule the
59+
/// report.
60+
void ReportSchedulerImpl::OnSubscriptionEstablished(ReadHandler * aReadHandler)
5961
{
6062
ReadHandlerNode * newNode = FindReadHandlerNode(aReadHandler);
6163
// Handler must not be registered yet; it's just being constructed.
@@ -68,11 +70,6 @@ void ReportSchedulerImpl::OnReadHandlerCreated(ReadHandler * aReadHandler)
6870
"Registered a ReadHandler that will schedule a report between system Timestamp: %" PRIu64
6971
" and system Timestamp %" PRIu64 ".",
7072
newNode->GetMinTimestamp().count(), newNode->GetMaxTimestamp().count());
71-
72-
Milliseconds32 newTimeout;
73-
// No need to check for error here, since the node is already in the list otherwise we would have Died
74-
CalculateNextReportTimeout(newTimeout, newNode);
75-
ScheduleReport(newTimeout, newNode);
7673
}
7774

7875
/// @brief When a ReadHandler becomes reportable, schedule, recalculate and reschedule the report.
@@ -85,7 +82,7 @@ void ReportSchedulerImpl::OnBecameReportable(ReadHandler * aReadHandler)
8582
ScheduleReport(newTimeout, node);
8683
}
8784

88-
void ReportSchedulerImpl::OnSubscriptionAction(ReadHandler * aReadHandler)
85+
void ReportSchedulerImpl::OnSubscriptionReportSent(ReadHandler * aReadHandler)
8986
{
9087
ReadHandlerNode * node = FindReadHandlerNode(aReadHandler);
9188
VerifyOrReturn(nullptr != node);

src/app/reporting/ReportSchedulerImpl.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,9 @@ class ReportSchedulerImpl : public ReportScheduler
3636
void OnEnterActiveMode() override;
3737

3838
// ReadHandlerObserver
39-
void OnReadHandlerCreated(ReadHandler * aReadHandler) final;
39+
void OnSubscriptionEstablished(ReadHandler * aReadHandler) final;
4040
void OnBecameReportable(ReadHandler * aReadHandler) final;
41-
void OnSubscriptionAction(ReadHandler * aReadHandler) final;
41+
void OnSubscriptionReportSent(ReadHandler * aReadHandler) final;
4242
void OnReadHandlerDestroyed(ReadHandler * aReadHandler) override;
4343

4444
bool IsReportScheduled(ReadHandler * aReadHandler);

src/app/tests/TestReadInteraction.cpp

+4-4
Original file line numberDiff line numberDiff line change
@@ -2234,7 +2234,7 @@ void TestReadInteraction::TestSubscribeUrgentWildcardEvent(nlTestSuite * apSuite
22342234
reportScheduler->GetMinTimestampForHandler(delegate.mpReadHandler) <
22352235
System::SystemClock().GetMonotonicTimestamp());
22362236
NL_TEST_ASSERT(apSuite, !delegate.mpReadHandler->IsDirty());
2237-
NL_TEST_ASSERT(apSuite, !delegate.mpReadHandler->IsReportable());
2237+
NL_TEST_ASSERT(apSuite, !delegate.mpReadHandler->ShouldStartReporting());
22382238

22392239
// And the non-urgent one should not have changed state either, since
22402240
// it's waiting for the max-interval.
@@ -2245,7 +2245,7 @@ void TestReadInteraction::TestSubscribeUrgentWildcardEvent(nlTestSuite * apSuite
22452245
reportScheduler->GetMaxTimestampForHandler(nonUrgentDelegate.mpReadHandler) >
22462246
System::SystemClock().GetMonotonicTimestamp());
22472247
NL_TEST_ASSERT(apSuite, !nonUrgentDelegate.mpReadHandler->IsDirty());
2248-
NL_TEST_ASSERT(apSuite, !nonUrgentDelegate.mpReadHandler->IsReportable());
2248+
NL_TEST_ASSERT(apSuite, !nonUrgentDelegate.mpReadHandler->ShouldStartReporting());
22492249

22502250
// There should be no reporting run scheduled. This is very important;
22512251
// otherwise we can get a false-positive pass below because the run was
@@ -2257,12 +2257,12 @@ void TestReadInteraction::TestSubscribeUrgentWildcardEvent(nlTestSuite * apSuite
22572257

22582258
// Urgent read handler should now be dirty, and reportable.
22592259
NL_TEST_ASSERT(apSuite, delegate.mpReadHandler->IsDirty());
2260-
NL_TEST_ASSERT(apSuite, delegate.mpReadHandler->IsReportable());
2260+
NL_TEST_ASSERT(apSuite, delegate.mpReadHandler->ShouldStartReporting());
22612261
NL_TEST_ASSERT(apSuite, reportScheduler->IsReadHandlerReportable(delegate.mpReadHandler));
22622262

22632263
// Non-urgent read handler should not be reportable.
22642264
NL_TEST_ASSERT(apSuite, !nonUrgentDelegate.mpReadHandler->IsDirty());
2265-
NL_TEST_ASSERT(apSuite, !nonUrgentDelegate.mpReadHandler->IsReportable());
2265+
NL_TEST_ASSERT(apSuite, !nonUrgentDelegate.mpReadHandler->ShouldStartReporting());
22662266

22672267
// Still no reporting should have happened.
22682268
NL_TEST_ASSERT(apSuite, !delegate.mGotEventResponse);

0 commit comments

Comments
 (0)