Matter SDK Coverage Report
Current view: top level - app - ClusterStateCache.h (source / functions) Coverage Total Hit
Test: SHA:b879ecb8e99e175eea0a293a888bda853da2b19c Lines: 6.8 % 59 4
Test Date: 2025-01-17 19:00:11 Functions: 2.5 % 79 2

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

Generated by: LCOV version 2.0-1