LCOV - code coverage report
Current view: top level - app - ClusterStateCache.h (source / functions) Hit Total Coverage
Test: lcov_final.info Lines: 10 50 20.0 %
Date: 2024-02-15 08:20:41 Functions: 4 51 7.8 %

          Line data    Source code
       1             : /*
       2             :  *
       3             :  *    Copyright (c) 2021 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 "lib/core/CHIPError.h"
      22             : #include "system/SystemPacketBuffer.h"
      23             : #include "system/TLVPacketBufferBackingStore.h"
      24             : #include <app/AppConfig.h>
      25             : #include <app/AttributePathParams.h>
      26             : #include <app/BufferedReadCallback.h>
      27             : #include <app/ReadClient.h>
      28             : #include <app/data-model/DecodableList.h>
      29             : #include <app/data-model/Decode.h>
      30             : #include <lib/support/Variant.h>
      31             : #include <list>
      32             : #include <map>
      33             : #include <queue>
      34             : #include <set>
      35             : #include <vector>
      36             : 
      37             : #if CHIP_CONFIG_ENABLE_READ_CLIENT
      38             : namespace chip {
      39             : namespace app {
      40             : /*
      41             :  * This implements a cluster state cache designed to aggregate both attribute and event data received by a client
      42             :  * from either read or subscribe interactions and keep it resident and available for clients to
      43             :  * query at any time while the cache is active.
      44             :  *
      45             :  * The cache can be used with either read/subscribe, with the consumer connecting it up appropriately
      46             :  * to the right ReadClient instance.
      47             :  *
      48             :  * The cache provides an up-to-date and consistent view of the state of a target node, with the scope of the
      49             :  * state being determined by the associated ReadClient's path set.
      50             :  *
      51             :  * The cache provides a number of getters and helper functions to iterate over the topology
      52             :  * of the received data which is organized by endpoint, cluster and attribute ID (for attributes). These permit greater
      53             :  * flexibility when dealing with interactions that use wildcards heavily.
      54             :  *
      55             :  * For events, functions that permit iteration over the cached events sorted by event number are provided.
      56             :  *
      57             :  * The data is stored internally in the cache as TLV. This permits re-use of the existing cluster objects
      58             :  * to de-serialize the state on-demand.
      59             :  *
      60             :  * The cache serves as a callback adapter as well in that it 'forwards' the ReadClient::Callback calls transparently
      61             :  * through to a registered callback. In addition, it provides its own enhancements to the base ReadClient::Callback
      62             :  * to make it easier to know what has changed in the cache.
      63             :  *
      64             :  * **NOTE**
      65             :  * 1. This already includes the BufferedReadCallback, so there is no need to add that to the ReadClient callback chain.
      66             :  * 2. The same cache cannot be used by multiple subscribe/read interactions at the same time.
      67             :  *
      68             :  */
      69             : class ClusterStateCache : protected ReadClient::Callback
      70             : {
      71             : public:
      72             :     class Callback : public ReadClient::Callback
      73             :     {
      74             :     public:
      75           0 :         Callback() = default;
      76             : 
      77             :         // Callbacks are not expected to be copyable or movable.
      78             :         Callback(const Callback &)             = delete;
      79             :         Callback(Callback &&)                  = delete;
      80             :         Callback & operator=(const Callback &) = delete;
      81             :         Callback & operator=(Callback &&)      = delete;
      82             : 
      83             :         /*
      84             :          * Called anytime an attribute value has changed in the cache
      85             :          */
      86           0 :         virtual void OnAttributeChanged(ClusterStateCache * cache, const ConcreteAttributePath & path){};
      87             : 
      88             :         /*
      89             :          * Called anytime any attribute in a cluster has changed in the cache
      90             :          */
      91           0 :         virtual void OnClusterChanged(ClusterStateCache * cache, EndpointId endpointId, ClusterId clusterId){};
      92             : 
      93             :         /*
      94             :          * Called anytime an endpoint was added to the cache
      95             :          */
      96           0 :         virtual void OnEndpointAdded(ClusterStateCache * cache, EndpointId endpointId){};
      97             :     };
      98             : 
      99             :     /**
     100             :      *
     101             :      * @param [in] callback the derived callback which inherit from ReadClient::Callback
     102             :      * @param [in] highestReceivedEventNumber optional highest received event number, if cache receive the events with the number
     103             :      *             less than or equal to this value, skip those events
     104             :      * @param [in] cacheData boolean to decide whether this cache would store attribute/event data/status,
     105             :      *             the default is true.
     106             :      */
     107           0 :     ClusterStateCache(Callback & callback, Optional<EventNumber> highestReceivedEventNumber = Optional<EventNumber>::Missing(),
     108           0 :                       bool cacheData = true) :
     109           0 :         mCallback(callback),
     110           0 :         mBufferedReader(*this), mCacheData(cacheData)
     111             :     {
     112           0 :         mHighestReceivedEventNumber = highestReceivedEventNumber;
     113           0 :     }
     114             : 
     115             :     ClusterStateCache(const ClusterStateCache &)             = delete;
     116             :     ClusterStateCache(ClusterStateCache &&)                  = delete;
     117             :     ClusterStateCache & operator=(const ClusterStateCache &) = delete;
     118             :     ClusterStateCache & operator=(ClusterStateCache &&)      = delete;
     119             : 
     120             :     void SetHighestReceivedEventNumber(EventNumber highestReceivedEventNumber)
     121             :     {
     122             :         mHighestReceivedEventNumber.SetValue(highestReceivedEventNumber);
     123             :     }
     124             : 
     125             :     /*
     126             :      * When registering as a callback to the ReadClient, the ClusterStateCache cannot not be passed as a callback
     127             :      * directly. Instead, utilize this method below to correctly set up the callback chain such that
     128             :      * the buffered reader is the first callback in the chain before calling into cache subsequently.
     129             :      */
     130           0 :     ReadClient::Callback & GetBufferedCallback() { return mBufferedReader; }
     131             : 
     132             :     /*
     133             :      * Retrieve the value of an attribute from the cache (if present) given a concrete path by decoding
     134             :      * it using DataModel::Decode into the in-out argument 'value'.
     135             :      *
     136             :      * For some types of attributes, the value for the attribute is directly backed by the underlying TLV buffer
     137             :      * and has pointers into that buffer. (e.g octet strings, char strings and lists).  This buffer only remains
     138             :      * valid until the cached value for that path is updated, so it must not be held
     139             :      * across any async call boundaries.
     140             :      *
     141             :      * The template parameter AttributeObjectTypeT is generally expected to be a
     142             :      * ClusterName::Attributes::AttributeName::DecodableType, but any
     143             :      * object that can be decoded using the DataModel::Decode machinery will work.
     144             :      *
     145             :      * Notable return values:
     146             :      *      - If the provided attribute object's Cluster and Attribute IDs don't match that of the provided path,
     147             :      *        a CHIP_ERROR_SCHEMA_MISMATCH shall be returned.
     148             :      *
     149             :      *      - If neither data or status for the specified path don't exist in the cache, CHIP_ERROR_KEY_NOT_FOUND
     150             :      *        shall be returned.
     151             :      *
     152             :      *      - If a StatusIB is present in the cache instead of data, a CHIP_ERROR_IM_STATUS_CODE_RECEIVED error
     153             :      *        shall be returned from this call instead. The actual StatusIB can be retrieved using the GetStatus() API below.
     154             :      *
     155             :      */
     156             :     template <typename AttributeObjectTypeT>
     157           0 :     CHIP_ERROR Get(const ConcreteAttributePath & path, typename AttributeObjectTypeT::DecodableType & value) const
     158             :     {
     159             :         TLV::TLVReader reader;
     160             : 
     161           0 :         if (path.mClusterId != AttributeObjectTypeT::GetClusterId() || path.mAttributeId != AttributeObjectTypeT::GetAttributeId())
     162             :         {
     163           0 :             return CHIP_ERROR_SCHEMA_MISMATCH;
     164             :         }
     165             : 
     166           0 :         ReturnErrorOnFailure(Get(path, reader));
     167           0 :         return DataModel::Decode(reader, value);
     168             :     }
     169             : 
     170             :     /**
     171             :      * Get the value of a particular attribute for the given endpoint.  See the
     172             :      * documentation for Get() with a ConcreteAttributePath above.
     173             :      */
     174             :     template <typename AttributeObjectTypeT>
     175           0 :     CHIP_ERROR Get(EndpointId endpoint, typename AttributeObjectTypeT::DecodableType & value) const
     176             :     {
     177           0 :         ConcreteAttributePath path(endpoint, AttributeObjectTypeT::GetClusterId(), AttributeObjectTypeT::GetAttributeId());
     178           0 :         return Get<AttributeObjectTypeT>(path, value);
     179             :     }
     180             : 
     181             :     /*
     182             :      * Retrieve the StatusIB for a given attribute if one exists currently in the cache.
     183             :      *
     184             :      * Notable return values:
     185             :      *      - If neither data or status for the specified path don't exist in the cache, CHIP_ERROR_KEY_NOT_FOUND
     186             :      *        shall be returned.
     187             :      *
     188             :      *      - If data exists in the cache instead of status, CHIP_ERROR_INVALID_ARGUMENT shall be returned.
     189             :      *
     190             :      */
     191             :     CHIP_ERROR GetStatus(const ConcreteAttributePath & path, StatusIB & status) const;
     192             : 
     193             :     /*
     194             :      * Encapsulates a StatusIB and a ConcreteAttributePath pair.
     195             :      */
     196             :     struct AttributeStatus
     197             :     {
     198             :         AttributeStatus(const ConcreteAttributePath & path, StatusIB & status) : mPath(path), mStatus(status) {}
     199             :         ConcreteAttributePath mPath;
     200             :         StatusIB mStatus;
     201             :     };
     202             : 
     203             :     /*
     204             :      * Retrieve the value of an entire cluster instance from the cache (if present) given a path
     205             :      * and decode it using DataModel::Decode into the in-out argument 'value'. If any StatusIBs
     206             :      * are present in the cache instead of data, they will be provided in the statusList argument.
     207             :      *
     208             :      * For some types of attributes, the value for the attribute is directly backed by the underlying TLV buffer
     209             :      * and has pointers into that buffer. (e.g octet strings, char strings and lists).  This buffer only remains
     210             :      * valid until the cached value for that path is updated, so it must not be held
     211             :      * across any async call boundaries.
     212             :      *
     213             :      * The template parameter ClusterObjectT is generally expected to be a
     214             :      * ClusterName::Attributes::DecodableType, but any
     215             :      * object that can be decoded using the DataModel::Decode machinery will work.
     216             :      *
     217             :      * Notable return values:
     218             :      *      - If neither data or status for the specified path exist in the cache, CHIP_ERROR_KEY_NOT_FOUND
     219             :      *        shall be returned.
     220             :      *
     221             :      */
     222             :     template <typename ClusterObjectTypeT>
     223             :     CHIP_ERROR Get(EndpointId endpointId, ClusterId clusterId, ClusterObjectTypeT & value,
     224             :                    std::list<AttributeStatus> & statusList) const
     225             :     {
     226             :         statusList.clear();
     227             : 
     228             :         return ForEachAttribute(endpointId, clusterId, [&value, this, &statusList](const ConcreteAttributePath & path) {
     229             :             TLV::TLVReader reader;
     230             :             CHIP_ERROR err;
     231             : 
     232             :             err = Get(path, reader);
     233             :             if (err == CHIP_ERROR_IM_STATUS_CODE_RECEIVED)
     234             :             {
     235             :                 StatusIB status;
     236             :                 ReturnErrorOnFailure(GetStatus(path, status));
     237             :                 statusList.push_back(AttributeStatus(path, status));
     238             :                 err = CHIP_NO_ERROR;
     239             :             }
     240             :             else if (err == CHIP_NO_ERROR)
     241             :             {
     242             :                 ReturnErrorOnFailure(DataModel::Decode(reader, path, value));
     243             :             }
     244             :             else
     245             :             {
     246             :                 return err;
     247             :             }
     248             : 
     249             :             return CHIP_NO_ERROR;
     250             :         });
     251             :     }
     252             : 
     253             :     /*
     254             :      * Retrieve the value of an attribute by updating a in-out TLVReader to be positioned
     255             :      * right at the attribute value.
     256             :      *
     257             :      * The underlying TLV buffer only remains valid until the cached value for that path is updated, so it must
     258             :      * not be held across any async call boundaries.
     259             :      *
     260             :      * Notable return values:
     261             :      *      - If neither data nor status for the specified path exist in the cache, CHIP_ERROR_KEY_NOT_FOUND
     262             :      *        shall be returned.
     263             :      *
     264             :      *      - If a StatusIB is present in the cache instead of data, a CHIP_ERROR_IM_STATUS_CODE_RECEIVED error
     265             :      *        shall be returned from this call instead. The actual StatusIB can be retrieved using the GetStatus() API above.
     266             :      *
     267             :      */
     268             :     CHIP_ERROR Get(const ConcreteAttributePath & path, TLV::TLVReader & reader) const;
     269             : 
     270             :     /*
     271             :      * Retrieve the data version for the given cluster.  If there is no data for the specified path in the cache,
     272             :      * CHIP_ERROR_KEY_NOT_FOUND shall be returned.  Otherwise aVersion will be set to the
     273             :      * current data version for the cluster (which may have no value if we don't have a known data version
     274             :      * for it, for example because none of our paths were wildcards that covered the whole cluster).
     275             :      */
     276             :     CHIP_ERROR GetVersion(const ConcreteClusterPath & path, Optional<DataVersion> & aVersion) const;
     277             : 
     278             :     /*
     279             :      * Get highest received event number.
     280             :      */
     281           2 :     virtual CHIP_ERROR GetHighestReceivedEventNumber(Optional<EventNumber> & aEventNumber) final
     282             :     {
     283           2 :         aEventNumber = mHighestReceivedEventNumber;
     284           2 :         return CHIP_NO_ERROR;
     285             :     }
     286             : 
     287             :     /*
     288             :      * Retrieve the value of an event from the cache given an EventNumber by decoding
     289             :      * it using DataModel::Decode into the in-out argument 'value'.
     290             :      *
     291             :      * This should be used in conjunction with the ForEachEvent() iterator function to
     292             :      * retrieve the EventHeader (and corresponding metadata information for the event) along with its EventNumber.
     293             :      *
     294             :      * For some types of events, the values for the fields in the event are directly backed by the underlying TLV buffer
     295             :      * and have pointers into that buffer. (e.g octet strings, char strings and lists). Unlike its attribute counterpart,
     296             :      * these pointers are stable and will not change until a call to `ClearEventCache` happens.
     297             :      *
     298             :      * The template parameter EventObjectTypeT is generally expected to be a
     299             :      * ClusterName::Events::EventName::DecodableType, but any
     300             :      * object that can be decoded using the DataModel::Decode machinery will work.
     301             :      *
     302             :      * Notable return values:
     303             :      *      - If the provided event object's Cluster and Event IDs don't match those of the event in the cache,
     304             :      *        a CHIP_ERROR_SCHEMA_MISMATCH shall be returned.
     305             :      *
     306             :      *      - If event doesn't exist in the cache, CHIP_ERROR_KEY_NOT_FOUND
     307             :      *        shall be returned.
     308             :      */
     309             : 
     310             :     template <typename EventObjectTypeT>
     311             :     CHIP_ERROR Get(EventNumber eventNumber, EventObjectTypeT & value) const
     312             :     {
     313             :         TLV::TLVReader reader;
     314             :         CHIP_ERROR err;
     315             : 
     316             :         auto * eventData = GetEventData(eventNumber, err);
     317             :         ReturnErrorOnFailure(err);
     318             : 
     319             :         if (eventData->first.mPath.mClusterId != value.GetClusterId() || eventData->first.mPath.mEventId != value.GetEventId())
     320             :         {
     321             :             return CHIP_ERROR_SCHEMA_MISMATCH;
     322             :         }
     323             : 
     324             :         ReturnErrorOnFailure(Get(eventNumber, reader));
     325             :         return DataModel::Decode(reader, value);
     326             :     }
     327             : 
     328             :     /*
     329             :      * Retrieve the data of an event by updating a in-out TLVReader to be positioned
     330             :      * right at the structure that encapsulates the event payload.
     331             :      *
     332             :      * Notable return values:
     333             :      *      - If no event with a matching eventNumber exists in the cache, CHIP_ERROR_KEY_NOT_FOUND
     334             :      *        shall be returned.
     335             :      *
     336             :      */
     337             :     CHIP_ERROR Get(EventNumber eventNumber, TLV::TLVReader & reader) const;
     338             : 
     339             :     /*
     340             :      * Retrieve the StatusIB for a specific event from the event status cache (if one exists).
     341             :      * Otherwise, a CHIP_ERROR_KEY_NOT_FOUND error will be returned.
     342             :      *
     343             :      * This is to be used with the `ForEachEventStatus` iterator function.
     344             :      *
     345             :      * NOTE: Receipt of a StatusIB does not affect any pre-existing or future event data entries in the cache (and vice-versa).
     346             :      *
     347             :      */
     348             :     CHIP_ERROR GetStatus(const ConcreteEventPath & path, StatusIB & status) const;
     349             : 
     350             :     /*
     351             :      * Execute an iterator function that is called for every attribute
     352             :      * in a given endpoint and cluster. The function when invoked is provided a concrete attribute path
     353             :      * to every attribute that matches in the cache.
     354             :      *
     355             :      * The iterator is expected to have this signature:
     356             :      *      CHIP_ERROR IteratorFunc(const ConcreteAttributePath &path);
     357             :      *
     358             :      * Notable return values:
     359             :      *      - If a cluster instance corresponding to endpointId and clusterId doesn't exist in the cache,
     360             :      *        CHIP_ERROR_KEY_NOT_FOUND shall be returned.
     361             :      *
     362             :      *      - If func returns an error, that will result in termination of any further iteration over attributes
     363             :      *        and that error shall be returned back up to the original call to this function.
     364             :      *
     365             :      */
     366             :     template <typename IteratorFunc>
     367             :     CHIP_ERROR ForEachAttribute(EndpointId endpointId, ClusterId clusterId, IteratorFunc func) const
     368             :     {
     369             :         CHIP_ERROR err;
     370             : 
     371             :         auto clusterState = GetClusterState(endpointId, clusterId, err);
     372             :         ReturnErrorOnFailure(err);
     373             : 
     374             :         for (auto & attributeIter : clusterState->mAttributes)
     375             :         {
     376             :             const ConcreteAttributePath path(endpointId, clusterId, attributeIter.first);
     377             :             ReturnErrorOnFailure(func(path));
     378             :         }
     379             : 
     380             :         return CHIP_NO_ERROR;
     381             :     }
     382             : 
     383             :     /*
     384             :      * Execute an iterator function that is called for every attribute
     385             :      * for a given cluster across all endpoints in the cache. The function is passed a
     386             :      * concrete attribute path to every attribute that matches in the cache.
     387             :      *
     388             :      * The iterator is expected to have this signature:
     389             :      *      CHIP_ERROR IteratorFunc(const ConcreteAttributePath &path);
     390             :      *
     391             :      * Notable return values:
     392             :      *      - If func returns an error, that will result in termination of any further iteration over attributes
     393             :      *        and that error shall be returned back up to the original call to this function.
     394             :      *
     395             :      */
     396             :     template <typename IteratorFunc>
     397           0 :     CHIP_ERROR ForEachAttribute(ClusterId clusterId, IteratorFunc func) const
     398             :     {
     399           0 :         for (auto & endpointIter : mCache)
     400             :         {
     401           0 :             for (auto & clusterIter : endpointIter.second)
     402             :             {
     403           0 :                 if (clusterIter.first == clusterId)
     404             :                 {
     405           0 :                     for (auto & attributeIter : clusterIter.second.mAttributes)
     406             :                     {
     407           0 :                         const ConcreteAttributePath path(endpointIter.first, clusterId, attributeIter.first);
     408           0 :                         ReturnErrorOnFailure(func(path));
     409             :                     }
     410             :                 }
     411             :             }
     412             :         }
     413           0 :         return CHIP_NO_ERROR;
     414             :     }
     415             : 
     416             :     /*
     417             :      * Execute an iterator function that is called for every cluster
     418             :      * in a given endpoint and passed a ClusterId for every cluster that
     419             :      * matches.
     420             :      *
     421             :      * The iterator is expected to have this signature:
     422             :      *      CHIP_ERROR IteratorFunc(ClusterId clusterId);
     423             :      *
     424             :      * Notable return values:
     425             :      *      - If func returns an error, that will result in termination of any further iteration over attributes
     426             :      *        and that error shall be returned back up to the original call to this function.
     427             :      *
     428             :      */
     429             :     template <typename IteratorFunc>
     430             :     CHIP_ERROR ForEachCluster(EndpointId endpointId, IteratorFunc func) const
     431             :     {
     432             :         auto endpointIter = mCache.find(endpointId);
     433             :         if (endpointIter->first == endpointId)
     434             :         {
     435             :             for (auto & clusterIter : endpointIter->second)
     436             :             {
     437             :                 ReturnErrorOnFailure(func(clusterIter.first));
     438             :             }
     439             :         }
     440             :         return CHIP_NO_ERROR;
     441             :     }
     442             : 
     443             :     /*
     444             :      * Execute an iterator function that is called for every event in the event data cache that satisfies the following
     445             :      * conditions:
     446             :      *      - It matches the provided path filter
     447             :      *      - Its event number is greater than or equal to the provided minimum event number filter.
     448             :      *
     449             :      * Each filter argument can be omitted from the match criteria above by passing in an empty EventPathParams() and/or
     450             :      * a minimum event filter of 0.
     451             :      *
     452             :      * This iterator is called in increasing order from the event with the lowest event number to the highest.
     453             :      *
     454             :      * The function is passed a const reference to the EventHeader associated with that event.
     455             :      *
     456             :      * The iterator is expected to have this signature:
     457             :      *      CHIP_ERROR IteratorFunc(const EventHeader & eventHeader);
     458             :      *
     459             :      * Notable return values:
     460             :      *      - If func returns an error, that will result in termination of any further iteration over events
     461             :      *        and that error shall be returned back up to the original call to this function.
     462             :      *
     463             :      */
     464             :     template <typename IteratorFunc>
     465             :     CHIP_ERROR ForEachEventData(IteratorFunc func, EventPathParams pathFilter = EventPathParams(),
     466             :                                 EventNumber minEventNumberFilter = 0) const
     467             :     {
     468             :         for (const auto & item : mEventDataCache)
     469             :         {
     470             :             if (pathFilter.IsEventPathSupersetOf(item.first.mPath) && item.first.mEventNumber >= minEventNumberFilter)
     471             :             {
     472             :                 ReturnErrorOnFailure(func(item.first));
     473             :             }
     474             :         }
     475             : 
     476             :         return CHIP_NO_ERROR;
     477             :     }
     478             : 
     479             :     /*
     480             :      * Execute an iterator function that is called for every StatusIB in the event status cache.
     481             :      *
     482             :      * The iterator is expected to have this signature:
     483             :      *      CHIP_ERROR IteratorFunc(const ConcreteEventPath & eventPath, const StatusIB & statusIB);
     484             :      *
     485             :      * Notable return values:
     486             :      *      - If func returns an error, that will result in termination of any further iteration over events
     487             :      *        and that error shall be returned back up to the original call to this function.
     488             :      *
     489             :      * NOTE: Receipt of a StatusIB does not affect any pre-existing event data entries in the cache (and vice-versa).
     490             :      *
     491             :      */
     492             :     template <typename IteratorFunc>
     493             :     CHIP_ERROR ForEachEventStatus(IteratorFunc func) const
     494             :     {
     495             :         for (const auto & item : mEventStatusCache)
     496             :         {
     497             :             ReturnErrorOnFailure(func(item.first, item.second));
     498             :         }
     499             :     }
     500             : 
     501             :     /*
     502             :      * Clear out the event data and status caches.
     503             :      *
     504             :      * By default, this will not clear out any internally tracked event counters, specifically:
     505             :      *   - the highest event number seen so far. This is used in reads/subscribe requests to express to the receiving
     506             :      *    server to not send events that the client has already seen so far.
     507             :      *
     508             :      * That can be over-ridden by passing in 'true' to `resetTrackedEventCounters`.
     509             :      *
     510             :      */
     511             :     void ClearEventCache(bool resetTrackedEventCounters = false)
     512             :     {
     513             :         mEventDataCache.clear();
     514             :         if (resetTrackedEventCounters)
     515             :         {
     516             :             mHighestReceivedEventNumber.ClearValue();
     517             :         }
     518             : 
     519             :         mEventStatusCache.clear();
     520             :     }
     521             : 
     522             :     /*
     523             :      *  Get the last concrete report data path, if path is not concrete cluster path, return CHIP_ERROR_NOT_FOUND
     524             :      *
     525             :      */
     526             :     CHIP_ERROR GetLastReportDataPath(ConcreteClusterPath & aPath);
     527             : 
     528             : private:
     529             :     // An attribute state can be one of three things:
     530             :     // * If we got a path-specific error for the attribute, the corresponding
     531             :     //   status.
     532             :     // * If we got data for the attribute and we are storing data ourselves, the
     533             :     //   data.
     534             :     // * If we got data for the attribute and we are not storing data
     535             :     //   oureselves, the size of the data, so we can still prioritize sending
     536             :     //   DataVersions correctly.
     537             :     using AttributeData  = Platform::ScopedMemoryBufferWithSize<uint8_t>;
     538             :     using AttributeState = Variant<StatusIB, AttributeData, size_t>;
     539             :     // mPendingDataVersion represents a tentative data version for a cluster that we have gotten some reports for.
     540             :     //
     541             :     // mCurrentDataVersion represents a known data version for a cluster.  In order for this to have a
     542             :     // value the cluster must be included in a path in mRequestPathSet that has a wildcard attribute
     543             :     // and we must not be in the middle of receiving reports for that cluster.
     544             :     struct ClusterState
     545             :     {
     546             :         std::map<AttributeId, AttributeState> mAttributes;
     547             :         Optional<DataVersion> mPendingDataVersion;
     548             :         Optional<DataVersion> mCommittedDataVersion;
     549             :     };
     550             :     using EndpointState = std::map<ClusterId, ClusterState>;
     551             :     using NodeState     = std::map<EndpointId, EndpointState>;
     552             : 
     553             :     struct Comparator
     554             :     {
     555        1054 :         bool operator()(const AttributePathParams & x, const AttributePathParams & y) const
     556             :         {
     557        1054 :             return x.mEndpointId < y.mEndpointId || x.mClusterId < y.mClusterId;
     558             :         }
     559             :     };
     560             : 
     561             :     using EventData = std::pair<EventHeader, System::PacketBufferHandle>;
     562             : 
     563             :     //
     564             :     // This is a custom comparator for use with the std::set<EventData> below. Uniqueness
     565             :     // is determined solely by the event number associated with each event.
     566             :     //
     567             :     struct EventDataCompare
     568             :     {
     569         422 :         bool operator()(const EventData & lhs, const EventData & rhs) const
     570             :         {
     571         422 :             return (lhs.first.mEventNumber < rhs.first.mEventNumber);
     572             :         }
     573             :     };
     574             : 
     575             :     /*
     576             :      * These functions provide a way to index into the cached state with different sub-sets of a path, returning
     577             :      * appropriate slices of the data as requested.
     578             :      *
     579             :      * In all variants, the respective slice is returned if a valid path is provided. 'err' is updated to reflect
     580             :      * the status of the operation.
     581             :      *
     582             :      * Notable status values:
     583             :      *      - If a cluster instance corresponding to endpointId and clusterId doesn't exist in the cache,
     584             :      *        CHIP_ERROR_KEY_NOT_FOUND shall be returned.
     585             :      *
     586             :      */
     587             :     const EndpointState * GetEndpointState(EndpointId endpointId, CHIP_ERROR & err) const;
     588             :     const ClusterState * GetClusterState(EndpointId endpointId, ClusterId clusterId, CHIP_ERROR & err) const;
     589             :     const AttributeState * GetAttributeState(EndpointId endpointId, ClusterId clusterId, AttributeId attributeId,
     590             :                                              CHIP_ERROR & err) const;
     591             : 
     592             :     const EventData * GetEventData(EventNumber number, CHIP_ERROR & err) const;
     593             : 
     594             :     /*
     595             :      * Updates the state of an attribute in the cache given a reader. If the reader is null, the state is updated
     596             :      * with the provided status.
     597             :      */
     598             :     CHIP_ERROR UpdateCache(const ConcreteDataAttributePath & aPath, TLV::TLVReader * apData, const StatusIB & aStatus);
     599             : 
     600             :     /*
     601             :      * If apData is not null, updates the cached event set with the specified event header + payload.
     602             :      * If apData is null and apStatus is not null, the StatusIB is stored in the event status cache.
     603             :      *
     604             :      * Storage of either of these do not affect pre-existing data for the other events in the cache.
     605             :      *
     606             :      */
     607             :     CHIP_ERROR UpdateEventCache(const EventHeader & aEventHeader, TLV::TLVReader * apData, const StatusIB * apStatus);
     608             : 
     609             :     //
     610             :     // ReadClient::Callback
     611             :     //
     612             :     void OnReportBegin() override;
     613             :     void OnReportEnd() override;
     614             :     void OnAttributeData(const ConcreteDataAttributePath & aPath, TLV::TLVReader * apData, const StatusIB & aStatus) override;
     615           0 :     void OnError(CHIP_ERROR aError) override { return mCallback.OnError(aError); }
     616             : 
     617             :     void OnEventData(const EventHeader & aEventHeader, TLV::TLVReader * apData, const StatusIB * apStatus) override;
     618             : 
     619          20 :     void OnDone(ReadClient * apReadClient) override
     620             :     {
     621          20 :         mRequestPathSet.clear();
     622          20 :         return mCallback.OnDone(apReadClient);
     623             :     }
     624             : 
     625           0 :     void OnSubscriptionEstablished(SubscriptionId aSubscriptionId) override
     626             :     {
     627           0 :         mCallback.OnSubscriptionEstablished(aSubscriptionId);
     628           0 :     }
     629             : 
     630           0 :     CHIP_ERROR OnResubscriptionNeeded(ReadClient * apReadClient, CHIP_ERROR aTerminationCause) override
     631             :     {
     632           0 :         return mCallback.OnResubscriptionNeeded(apReadClient, aTerminationCause);
     633             :     }
     634             : 
     635           0 :     void OnDeallocatePaths(chip::app::ReadPrepareParams && aReadPrepareParams) override
     636             :     {
     637           0 :         mCallback.OnDeallocatePaths(std::move(aReadPrepareParams));
     638           0 :     }
     639             : 
     640             :     virtual CHIP_ERROR OnUpdateDataVersionFilterList(DataVersionFilterIBs::Builder & aDataVersionFilterIBsBuilder,
     641             :                                                      const Span<AttributePathParams> & aAttributePaths,
     642             :                                                      bool & aEncodedDataVersionList) override;
     643             : 
     644           0 :     void OnUnsolicitedMessageFromPublisher(ReadClient * apReadClient) override
     645             :     {
     646           0 :         return mCallback.OnUnsolicitedMessageFromPublisher(apReadClient);
     647             :     }
     648             : 
     649           0 :     void OnCASESessionEstablished(const SessionHandle & aSession, ReadPrepareParams & aSubscriptionParams) override
     650             :     {
     651           0 :         return mCallback.OnCASESessionEstablished(aSession, aSubscriptionParams);
     652             :     }
     653             : 
     654             :     // Commit the pending cluster data version, if there is one.
     655             :     void CommitPendingDataVersion();
     656             : 
     657             :     // Get our list of data version filters, sorted from larges to smallest by the total size of the TLV
     658             :     // payload for the filter's cluster.  Applying filters in this order should maximize space savings
     659             :     // on the wire if not all filters can be applied.
     660             :     void GetSortedFilters(std::vector<std::pair<DataVersionFilter, size_t>> & aVector) const;
     661             : 
     662             :     CHIP_ERROR GetElementTLVSize(TLV::TLVReader * apData, size_t & aSize);
     663             : 
     664             :     Callback & mCallback;
     665             :     NodeState mCache;
     666             :     std::set<ConcreteAttributePath> mChangedAttributeSet;
     667             :     std::set<AttributePathParams, Comparator> mRequestPathSet; // wildcard attribute request path only
     668             :     std::vector<EndpointId> mAddedEndpoints;
     669             : 
     670             :     std::set<EventData, EventDataCompare> mEventDataCache;
     671             :     Optional<EventNumber> mHighestReceivedEventNumber;
     672             :     std::map<ConcreteEventPath, StatusIB> mEventStatusCache;
     673             :     BufferedReadCallback mBufferedReader;
     674             :     ConcreteClusterPath mLastReportDataPath = ConcreteClusterPath(kInvalidEndpointId, kInvalidClusterId);
     675             :     const bool mCacheData                   = true;
     676             : };
     677             : 
     678             : };     // namespace app
     679             : };     // namespace chip
     680             : #endif // CHIP_CONFIG_ENABLE_READ_CLIENT

Generated by: LCOV version 1.14