LCOV - code coverage report
Current view: top level - app/reporting - SynchronizedReportSchedulerImpl.h (source / functions) Hit Total Coverage
Test: lcov_final.info Lines: 0 1 0.0 %
Date: 2024-02-15 08:20:41 Functions: 0 2 0.0 %

          Line data    Source code
       1             : /*
       2             :  *
       3             :  *    Copyright (c) 2023 Project CHIP Authors
       4             :  *    All rights reserved.
       5             :  *
       6             :  *    Licensed under the Apache License, Version 2.0 (the "License");
       7             :  *    you may not use this file except in compliance with the License.
       8             :  *    You may obtain a copy of the License at
       9             :  *
      10             :  *        http://www.apache.org/licenses/LICENSE-2.0
      11             :  *
      12             :  *    Unless required by applicable law or agreed to in writing, software
      13             :  *    distributed under the License is distributed on an "AS IS" BASIS,
      14             :  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      15             :  *    See the License for the specific language governing permissions and
      16             :  *    limitations under the License.
      17             :  */
      18             : 
      19             : #pragma once
      20             : 
      21             : #include <app/reporting/ReportSchedulerImpl.h>
      22             : 
      23             : namespace chip {
      24             : namespace app {
      25             : namespace reporting {
      26             : 
      27             : using Timeout         = System::Clock::Timeout;
      28             : using Timestamp       = System::Clock::Timestamp;
      29             : using Milliseconds64  = System::Clock::Milliseconds64;
      30             : using ReadHandlerNode = ReportScheduler::ReadHandlerNode;
      31             : using TimerDelegate   = ReportScheduler::TimerDelegate;
      32             : 
      33             : /**
      34             :  * @class Synchronized ReportSchedulerImpl
      35             :  *
      36             :  * @brief This class extends ReportSchedulerImpl and overrides it's scheduling logic.
      37             :  *
      38             :  * It only overrides Observers method where the scheduling logic make it necessary, the others are kept as is.
      39             :  *
      40             :  * It inherits from TimerContext so that it can be used as a TimerDelegate instead on relying on the nodes to schedule themselves.
      41             :  *
      42             :  * ## Scheduling Logic
      43             :  *
      44             :  * This class implements a scheduling logic that aims to make all ReadHandlers report at the same time when possible.
      45             :  * The goal is to minimize the different times a device wakes up to report, and thus this aims to schedule all reports at the latest
      46             :  * possible time while ensuring that all reports get sent before their max interval.
      47             :  *
      48             :  * The logic also aims to minimize the impact on the responsivity of the device.
      49             :  *
      50             :  * The scheduling logic is as follows:
      51             :  * - The CalculateNextReportTimeout is called by the same ReadHandler Observer callbacks than the non-synchronized implementation:
      52             :  *      * OnSubscriptionEstablished,
      53             :  *      * OnBecameReportable,
      54             :  *      * OnSubscriptionReportSent
      55             :  *
      56             :  * - The Synchronized Scheduler keeps track of the next min and max interval timestamps. It updates in CalculateNextReportTimeout
      57             :  *
      58             :  * - The next max interval is calculated as the earliest max interval of all the registered ReadHandlersNodes.
      59             :  *
      60             :  * - The next min interval is calculated as the latest min interval of the registered ReadHandlersNodes that:
      61             :  *     * Have a min timestamp greater than the current time
      62             :  *     * Are Reportable (this prevents a ReadHandler that is not reportable to hold the report of all the others)
      63             :  *       TODO: Assess if we want to keep this behavior or simply let the min interval be the earliest min interval to prevent cases
      64             :  *             where a ReadHandler with a dirty path but a very high min interval blocks all reports
      65             :  * - If no ReadHandlerNode matches min interval  the criteria, the next min interval is set to current timestamp.
      66             :  *
      67             :  * - The next report timeout is calculated in CalculatedNextReportTimeout based on the next min and max interval timestamps, as well
      68             :  * as the status of each ReadHandlerNode in the pool.
      69             :  *
      70             :  * @note Unlike the non-synchronized implementation, the Synchronized Scheduler will reschedule itself in the event where a timer
      71             :  * fires before a reportable timestamp is reached.
      72             :  *
      73             :  * @note In this implementation, nodes still keep track of their own min and max interval timestamps.
      74             :  */
      75             : class SynchronizedReportSchedulerImpl : public ReportSchedulerImpl, public TimerContext
      76             : {
      77             : public:
      78             :     void OnReadHandlerDestroyed(ReadHandler * aReadHandler) override;
      79             : 
      80             :     SynchronizedReportSchedulerImpl(TimerDelegate * aTimerDelegate) : ReportSchedulerImpl(aTimerDelegate) {}
      81           0 :     ~SynchronizedReportSchedulerImpl() override { UnregisterAllHandlers(); }
      82             : 
      83             :     void OnTransitionToIdle() override;
      84             : 
      85             :     bool IsReportScheduled(ReadHandler * ReadHandler) override;
      86             : 
      87             :     /** @brief Callback called when the report timer expires to schedule an engine run regardless of the state of the ReadHandlers,
      88             :      *
      89             :      * It loops through all handlers and sets their CanBeSynced flag to true if the current timstamp is greater than
      90             :      * their respective minimal timestamps.
      91             :      *
      92             :      * While looping, it checks if any handler is reportable now. If not, we recalculate the next report timeout and reschedule the
      93             :      * report.
      94             :      *
      95             :      * If a Readhangler is reportable now, an engine run is scheduled.
      96             :      *
      97             :      * If the timer expires after all nodes were unregistered, no action is taken.
      98             :      */
      99             :     void TimerFired() override;
     100             : 
     101             : protected:
     102             :     /**
     103             :      * @brief Schedule a report for the Scheduler.
     104             :      *
     105             :      * If a report is already scheduled, cancel it and schedule a new one.
     106             :      *
     107             :      * @param[in] timeout The timeout to schedule the report.
     108             :      * @param[in] node The node associated to the ReadHandler.
     109             :      * @param[in] now The current system timestamp.
     110             :      *
     111             :      * @return CHIP_ERROR CHIP_NO_ERROR on success, timer related error code otherwise (This can only fail on starting the timer)
     112             :      */
     113             :     CHIP_ERROR ScheduleReport(System::Clock::Timeout timeout, ReadHandlerNode * node, const Timestamp & now) override;
     114             :     void CancelReport();
     115             : 
     116             : private:
     117             :     friend class chip::app::reporting::TestReportScheduler;
     118             : 
     119             :     /**
     120             :      * @brief Find the highest minimum timestamp possible that still respects the lowest max timestamp and sets it as the common
     121             :      * minimum. If the max timestamp has not been updated and is in the past, or if no min timestamp is lower than the current max
     122             :      * timestamp, this will set now as the common minimum timestamp, thus allowing the report to be sent immediately.
     123             :      *
     124             :      * @param[in] now The current system timestamp, set by the event that triggered the call of this method.
     125             :      *
     126             :      * @return CHIP_ERROR on success or CHIP_ERROR_INVALID_LIST_LENGTH if the list is empty
     127             :      */
     128             :     CHIP_ERROR FindNextMinInterval(const Timestamp & now);
     129             : 
     130             :     /**
     131             :      * @brief Find the smallest maximum interval possible and set it as the common maximum
     132             :      *
     133             :      * @param[in] now The current system timestamp, set by the event that triggered the call of this method.
     134             :      *
     135             :      * @return CHIP_ERROR on success or CHIP_ERROR_INVALID_LIST_LENGTH if the list is empty
     136             :      */
     137             :     CHIP_ERROR FindNextMaxInterval(const Timestamp & now);
     138             : 
     139             :     /**
     140             :      *  @brief Calculate the next report timeout for all ReadHandlerNodes
     141             :      *
     142             :      * @param[out] timeout The timeout to calculate.
     143             :      * @param[in] aReadHandlerNode unused, kept to preserve the signature of the base class
     144             :      * @param[in] now The current system timestamp when the event leading to the call of this method happened.
     145             :      *
     146             :      *  The next report timeout is calculated by looping through all the ReadHandlerNodes and finding if any are reportable now
     147             :      *      or at min.
     148             :      *   * If a ReadHandlerNode is reportable now, the timeout is set to 0.
     149             :      *   * If a ReadHandlerNode is reportable at min, the timeout is set to the difference between the Scheduler's  min timestamp
     150             :      *      and the current time.
     151             :      *   * If no ReadHandlerNode is reportable, the timeout is set to the difference between the Scheduler's max timestamp and the
     152             :      *      current time.
     153             :      *
     154             :      * @note Since this method is called after the OnSubscriptionReportSent callback, to avoid an endless reporting loop, Nodes with
     155             :      * the IsEngineRunScheduled flag set are ignored when finding if the Scheduler should report at min, max or now.
     156             :      *
     157             :      * @note If a ReadHandler's report is Chunked, the IsEngineRunScheduled is ignored since we do want to keep rescheduling the
     158             :      *       report to the now timestamp until it is fully sent. IsChunkedReport is used to prevent starting a chunked report and
     159             :      * then waiting on the max interval after the first chunk is sent.
     160             :      */
     161             :     CHIP_ERROR CalculateNextReportTimeout(Timeout & timeout, ReadHandlerNode * aReadHandlerNode, const Timestamp & now) override;
     162             : 
     163             :     Timestamp mNextMaxTimestamp = Milliseconds64(0);
     164             :     Timestamp mNextMinTimestamp = Milliseconds64(0);
     165             : 
     166             :     // Timestamp of the next report to be scheduled, used by OnTransitionToIdle to determine whether we should emit a report before
     167             :     // the device goes to idle mode
     168             :     Timestamp mNextReportTimestamp = Milliseconds64(0);
     169             : };
     170             : 
     171             : } // namespace reporting
     172             : } // namespace app
     173             : } // namespace chip

Generated by: LCOV version 1.14