Matter SDK Coverage Report
Current view: top level - app - ClusterStateCache.h (source / functions) Coverage Total Hit
Test: SHA:7c9b1260e3daa86aae0d41b894469b295eee70e8 Lines: 82.1 % 106 87
Test Date: 2025-09-07 07:12:04 Functions: 34.6 % 104 36

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

Generated by: LCOV version 2.0-1