LCOV - code coverage report
Current view: top level - app - ClusterStateCache.cpp (source / functions) Hit Total Coverage
Test: lcov_final.info Lines: 242 266 91.0 %
Date: 2024-02-15 08:20:41 Functions: 20 22 90.9 %

          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             : #include "system/SystemPacketBuffer.h"
      20             : #include <app/ClusterStateCache.h>
      21             : #include <app/InteractionModelEngine.h>
      22             : #include <tuple>
      23             : 
      24             : namespace chip {
      25             : namespace app {
      26             : 
      27             : namespace {
      28             : 
      29             : // Determine how much space a StatusIB takes up on the wire.
      30          36 : size_t SizeOfStatusIB(const StatusIB & aStatus)
      31             : {
      32             :     // 1 byte: anonymous tag control byte for struct.
      33             :     // 1 byte: control byte for uint8 value.
      34             :     // 1 byte: context-specific tag for uint8 value.
      35             :     // 1 byte: the uint8 value.
      36             :     // 1 byte: end of container.
      37          36 :     size_t size = 5;
      38             : 
      39          36 :     if (aStatus.mClusterStatus.HasValue())
      40             :     {
      41             :         // 1 byte: control byte for uint8 value.
      42             :         // 1 byte: context-specific tag for uint8 value.
      43             :         // 1 byte: the uint8 value.
      44           0 :         size += 3;
      45             :     }
      46             : 
      47          36 :     return size;
      48             : }
      49             : 
      50             : } // anonymous namespace
      51             : 
      52          80 : CHIP_ERROR ClusterStateCache::GetElementTLVSize(TLV::TLVReader * apData, size_t & aSize)
      53             : {
      54          80 :     Platform::ScopedMemoryBufferWithSize<uint8_t> backingBuffer;
      55             :     TLV::TLVReader reader;
      56          80 :     reader.Init(*apData);
      57          80 :     size_t totalBufSize = reader.GetTotalLength();
      58          80 :     backingBuffer.Calloc(totalBufSize);
      59          80 :     VerifyOrReturnError(backingBuffer.Get() != nullptr, CHIP_ERROR_NO_MEMORY);
      60          80 :     TLV::ScopedBufferTLVWriter writer(std::move(backingBuffer), totalBufSize);
      61          80 :     ReturnErrorOnFailure(writer.CopyElement(TLV::AnonymousTag(), reader));
      62          80 :     aSize = writer.GetLengthWritten();
      63          80 :     ReturnErrorOnFailure(writer.Finalize(backingBuffer));
      64          80 :     return CHIP_NO_ERROR;
      65          80 : }
      66             : 
      67         115 : CHIP_ERROR ClusterStateCache::UpdateCache(const ConcreteDataAttributePath & aPath, TLV::TLVReader * apData,
      68             :                                           const StatusIB & aStatus)
      69             : {
      70         115 :     AttributeState state;
      71         115 :     bool endpointIsNew = false;
      72             : 
      73         115 :     if (mCache.find(aPath.mEndpointId) == mCache.end())
      74             :     {
      75             :         //
      76             :         // Since we might potentially be creating a new entry at mCache[aPath.mEndpointId][aPath.mClusterId] that
      77             :         // wasn't there before, we need to check if an entry didn't exist there previously and remember that so that
      78             :         // we can appropriately notify our clients of the addition of a new endpoint.
      79             :         //
      80          15 :         endpointIsNew = true;
      81             :     }
      82             : 
      83         115 :     if (apData)
      84             :     {
      85          80 :         size_t elementSize = 0;
      86          80 :         ReturnErrorOnFailure(GetElementTLVSize(apData, elementSize));
      87             : 
      88          80 :         if (mCacheData)
      89             :         {
      90          74 :             Platform::ScopedMemoryBufferWithSize<uint8_t> backingBuffer;
      91          74 :             backingBuffer.Calloc(elementSize);
      92          74 :             VerifyOrReturnError(backingBuffer.Get() != nullptr, CHIP_ERROR_NO_MEMORY);
      93          74 :             TLV::ScopedBufferTLVWriter writer(std::move(backingBuffer), elementSize);
      94          74 :             ReturnErrorOnFailure(writer.CopyElement(TLV::AnonymousTag(), *apData));
      95          74 :             ReturnErrorOnFailure(writer.Finalize(backingBuffer));
      96             : 
      97          74 :             state.Set<AttributeData>(std::move(backingBuffer));
      98          74 :         }
      99             :         else
     100             :         {
     101           6 :             state.Set<size_t>(elementSize);
     102             :         }
     103             :         //
     104             :         // Clear out the committed data version and only set it again once we have received all data for this cluster.
     105             :         // Otherwise, we may have incomplete data that looks like it's complete since it has a valid data version.
     106             :         //
     107          80 :         mCache[aPath.mEndpointId][aPath.mClusterId].mCommittedDataVersion.ClearValue();
     108             : 
     109             :         // This commits a pending data version if the last report path is valid and it is different from the current path.
     110          80 :         if (mLastReportDataPath.IsValidConcreteClusterPath() && mLastReportDataPath != aPath)
     111             :         {
     112          12 :             CommitPendingDataVersion();
     113             :         }
     114             : 
     115          80 :         bool foundEncompassingWildcardPath = false;
     116         102 :         for (const auto & path : mRequestPathSet)
     117             :         {
     118          79 :             if (path.IncludesAllAttributesInCluster(aPath))
     119             :             {
     120          57 :                 foundEncompassingWildcardPath = true;
     121          57 :                 break;
     122             :             }
     123             :         }
     124             : 
     125             :         // if this data item is encompassed by a wildcard path, let's go ahead and update its pending data version.
     126          80 :         if (foundEncompassingWildcardPath)
     127             :         {
     128          57 :             mCache[aPath.mEndpointId][aPath.mClusterId].mPendingDataVersion = aPath.mDataVersion;
     129             :         }
     130             : 
     131          80 :         mLastReportDataPath = aPath;
     132             :     }
     133             :     else
     134             :     {
     135          35 :         if (mCacheData)
     136             :         {
     137          32 :             state.Set<StatusIB>(aStatus);
     138             :         }
     139             :         else
     140             :         {
     141           3 :             state.Set<size_t>(SizeOfStatusIB(aStatus));
     142             :         }
     143             :     }
     144             : 
     145             :     //
     146             :     // if the endpoint didn't exist previously, let's track the insertion
     147             :     // so that we can inform our callback of a new endpoint being added appropriately.
     148             :     //
     149         115 :     if (endpointIsNew)
     150             :     {
     151          15 :         mAddedEndpoints.push_back(aPath.mEndpointId);
     152             :     }
     153             : 
     154         115 :     mCache[aPath.mEndpointId][aPath.mClusterId].mAttributes[aPath.mAttributeId] = std::move(state);
     155             : 
     156         115 :     if (mCacheData)
     157             :     {
     158         106 :         mChangedAttributeSet.insert(aPath);
     159             :     }
     160             : 
     161         115 :     return CHIP_NO_ERROR;
     162         115 : }
     163             : 
     164          32 : CHIP_ERROR ClusterStateCache::UpdateEventCache(const EventHeader & aEventHeader, TLV::TLVReader * apData, const StatusIB * apStatus)
     165             : {
     166          32 :     if (apData)
     167             :     {
     168             :         //
     169             :         // If we've already seen this event before, there's no more work to be done.
     170             :         //
     171          32 :         if (mHighestReceivedEventNumber.HasValue() && aEventHeader.mEventNumber <= mHighestReceivedEventNumber.Value())
     172             :         {
     173           5 :             return CHIP_NO_ERROR;
     174             :         }
     175          27 :         if (mCacheData)
     176             :         {
     177          21 :             System::PacketBufferHandle handle = System::PacketBufferHandle::New(chip::app::kMaxSecureSduLengthBytes);
     178          21 :             VerifyOrReturnError(!handle.IsNull(), CHIP_ERROR_NO_MEMORY);
     179             : 
     180          21 :             System::PacketBufferTLVWriter writer;
     181          21 :             writer.Init(std::move(handle), false);
     182             : 
     183          21 :             ReturnErrorOnFailure(writer.CopyElement(TLV::AnonymousTag(), *apData));
     184          21 :             ReturnErrorOnFailure(writer.Finalize(&handle));
     185             : 
     186             :             //
     187             :             // Compact the buffer down to a more reasonably sized packet buffer
     188             :             // if we can.
     189             :             //
     190          21 :             handle.RightSize();
     191             : 
     192          21 :             EventData eventData;
     193          21 :             eventData.first  = aEventHeader;
     194          21 :             eventData.second = std::move(handle);
     195             : 
     196          21 :             mEventDataCache.insert(std::move(eventData));
     197          21 :         }
     198          27 :         mHighestReceivedEventNumber.SetValue(aEventHeader.mEventNumber);
     199             :     }
     200           0 :     else if (apStatus)
     201             :     {
     202           0 :         if (mCacheData)
     203             :         {
     204           0 :             mEventStatusCache[aEventHeader.mPath] = *apStatus;
     205             :         }
     206             :     }
     207             : 
     208          27 :     return CHIP_NO_ERROR;
     209             : }
     210             : 
     211          29 : void ClusterStateCache::OnReportBegin()
     212             : {
     213          29 :     mLastReportDataPath = ConcreteClusterPath(kInvalidEndpointId, kInvalidClusterId);
     214          29 :     mChangedAttributeSet.clear();
     215          29 :     mAddedEndpoints.clear();
     216          29 :     mCallback.OnReportBegin();
     217          29 : }
     218             : 
     219          41 : void ClusterStateCache::CommitPendingDataVersion()
     220             : {
     221          41 :     if (!mLastReportDataPath.IsValidConcreteClusterPath())
     222             :     {
     223           7 :         return;
     224             :     }
     225             : 
     226          34 :     auto & lastClusterInfo = mCache[mLastReportDataPath.mEndpointId][mLastReportDataPath.mClusterId];
     227          34 :     if (lastClusterInfo.mPendingDataVersion.HasValue())
     228             :     {
     229          19 :         lastClusterInfo.mCommittedDataVersion = lastClusterInfo.mPendingDataVersion;
     230          19 :         lastClusterInfo.mPendingDataVersion.ClearValue();
     231             :     }
     232             : }
     233             : 
     234          29 : void ClusterStateCache::OnReportEnd()
     235             : {
     236          29 :     CommitPendingDataVersion();
     237          29 :     mLastReportDataPath = ConcreteClusterPath(kInvalidEndpointId, kInvalidClusterId);
     238          29 :     std::set<std::tuple<EndpointId, ClusterId>> changedClusters;
     239             : 
     240             :     //
     241             :     // Add the EndpointId and ClusterId into a set so that we only
     242             :     // convey unique combinations in the subsequent OnClusterChanged callback.
     243             :     //
     244         131 :     for (auto & path : mChangedAttributeSet)
     245             :     {
     246         102 :         mCallback.OnAttributeChanged(this, path);
     247         102 :         changedClusters.insert(std::make_tuple(path.mEndpointId, path.mClusterId));
     248             :     }
     249             : 
     250          62 :     for (auto & item : changedClusters)
     251             :     {
     252          33 :         mCallback.OnClusterChanged(this, std::get<0>(item), std::get<1>(item));
     253             :     }
     254             : 
     255          44 :     for (auto endpoint : mAddedEndpoints)
     256             :     {
     257          15 :         mCallback.OnEndpointAdded(this, endpoint);
     258             :     }
     259             : 
     260          29 :     mCallback.OnReportEnd();
     261          29 : }
     262             : 
     263          74 : CHIP_ERROR ClusterStateCache::Get(const ConcreteAttributePath & path, TLV::TLVReader & reader) const
     264             : {
     265             :     CHIP_ERROR err;
     266          74 :     auto attributeState = GetAttributeState(path.mEndpointId, path.mClusterId, path.mAttributeId, err);
     267          74 :     ReturnErrorOnFailure(err);
     268          73 :     if (attributeState->Is<StatusIB>())
     269             :     {
     270           2 :         return CHIP_ERROR_IM_STATUS_CODE_RECEIVED;
     271             :     }
     272             : 
     273          71 :     if (!attributeState->Is<AttributeData>())
     274             :     {
     275           3 :         return CHIP_ERROR_KEY_NOT_FOUND;
     276             :     }
     277             : 
     278          68 :     reader.Init(attributeState->Get<AttributeData>().Get(), attributeState->Get<AttributeData>().AllocatedSize());
     279          68 :     return reader.Next();
     280             : }
     281             : 
     282          44 : CHIP_ERROR ClusterStateCache::Get(EventNumber eventNumber, TLV::TLVReader & reader) const
     283             : {
     284             :     CHIP_ERROR err;
     285             : 
     286          44 :     auto eventData = GetEventData(eventNumber, err);
     287          44 :     ReturnErrorOnFailure(err);
     288             : 
     289          44 :     System::PacketBufferTLVReader bufReader;
     290             : 
     291          44 :     bufReader.Init(eventData->second.Retain());
     292          44 :     ReturnErrorOnFailure(bufReader.Next());
     293             : 
     294          44 :     reader.Init(bufReader);
     295          44 :     return CHIP_NO_ERROR;
     296          44 : }
     297             : 
     298         114 : const ClusterStateCache::EndpointState * ClusterStateCache::GetEndpointState(EndpointId endpointId, CHIP_ERROR & err) const
     299             : {
     300         114 :     auto endpointIter = mCache.find(endpointId);
     301         114 :     if (endpointIter == mCache.end())
     302             :     {
     303           1 :         err = CHIP_ERROR_KEY_NOT_FOUND;
     304           1 :         return nullptr;
     305             :     }
     306             : 
     307         113 :     err = CHIP_NO_ERROR;
     308         113 :     return &endpointIter->second;
     309             : }
     310             : 
     311         114 : const ClusterStateCache::ClusterState * ClusterStateCache::GetClusterState(EndpointId endpointId, ClusterId clusterId,
     312             :                                                                            CHIP_ERROR & err) const
     313             : {
     314         114 :     auto endpointState = GetEndpointState(endpointId, err);
     315         114 :     if (err != CHIP_NO_ERROR)
     316             :     {
     317           1 :         return nullptr;
     318             :     }
     319             : 
     320         113 :     auto clusterState = endpointState->find(clusterId);
     321         113 :     if (clusterState == endpointState->end())
     322             :     {
     323           0 :         err = CHIP_ERROR_KEY_NOT_FOUND;
     324           0 :         return nullptr;
     325             :     }
     326             : 
     327         113 :     err = CHIP_NO_ERROR;
     328         113 :     return &clusterState->second;
     329             : }
     330             : 
     331          75 : const ClusterStateCache::AttributeState * ClusterStateCache::GetAttributeState(EndpointId endpointId, ClusterId clusterId,
     332             :                                                                                AttributeId attributeId, CHIP_ERROR & err) const
     333             : {
     334          75 :     auto clusterState = GetClusterState(endpointId, clusterId, err);
     335          75 :     if (err != CHIP_NO_ERROR)
     336             :     {
     337           1 :         return nullptr;
     338             :     }
     339             : 
     340          74 :     auto attributeState = clusterState->mAttributes.find(attributeId);
     341          74 :     if (attributeState == clusterState->mAttributes.end())
     342             :     {
     343           0 :         err = CHIP_ERROR_KEY_NOT_FOUND;
     344           0 :         return nullptr;
     345             :     }
     346             : 
     347          74 :     err = CHIP_NO_ERROR;
     348          74 :     return &attributeState->second;
     349             : }
     350             : 
     351          88 : const ClusterStateCache::EventData * ClusterStateCache::GetEventData(EventNumber eventNumber, CHIP_ERROR & err) const
     352             : {
     353          88 :     EventData compareKey;
     354             : 
     355          88 :     compareKey.first.mEventNumber = eventNumber;
     356          88 :     auto eventData                = mEventDataCache.find(std::move(compareKey));
     357          88 :     if (eventData == mEventDataCache.end())
     358             :     {
     359           0 :         err = CHIP_ERROR_KEY_NOT_FOUND;
     360           0 :         return nullptr;
     361             :     }
     362             : 
     363          88 :     err = CHIP_NO_ERROR;
     364          88 :     return &(*eventData);
     365          88 : }
     366             : 
     367         115 : void ClusterStateCache::OnAttributeData(const ConcreteDataAttributePath & aPath, TLV::TLVReader * apData, const StatusIB & aStatus)
     368             : {
     369             :     //
     370             :     // Since the cache itself is a ReadClient::Callback, it may be incorrectly passed in directly when registering with the
     371             :     // ReadClient. This should be avoided, since that bypasses the built-in buffered reader adapter callback that is needed for
     372             :     // lists to work correctly.
     373             :     //
     374             :     // Instead, the right callback should be retrieved using GetBufferedCallback().
     375             :     //
     376             :     // To catch such errors, we validate that the provided concrete path never indicates a raw list item operation (which the
     377             :     // buffered reader will handle and convert for us).
     378             :     //
     379             :     //
     380         115 :     VerifyOrDie(!aPath.IsListItemOperation());
     381             : 
     382             :     // Copy the reader for forwarding
     383             :     TLV::TLVReader dataSnapshot;
     384         115 :     if (apData)
     385             :     {
     386          80 :         dataSnapshot.Init(*apData);
     387             :     }
     388             : 
     389         115 :     UpdateCache(aPath, apData, aStatus);
     390             : 
     391             :     //
     392             :     // Forward the call through.
     393             :     //
     394         115 :     mCallback.OnAttributeData(aPath, apData ? &dataSnapshot : nullptr, aStatus);
     395         115 : }
     396             : 
     397          28 : CHIP_ERROR ClusterStateCache::GetVersion(const ConcreteClusterPath & aPath, Optional<DataVersion> & aVersion) const
     398             : {
     399          28 :     VerifyOrReturnError(aPath.IsValidConcreteClusterPath(), CHIP_ERROR_INVALID_ARGUMENT);
     400             :     CHIP_ERROR err;
     401          28 :     auto clusterState = GetClusterState(aPath.mEndpointId, aPath.mClusterId, err);
     402          28 :     ReturnErrorOnFailure(err);
     403          28 :     aVersion = clusterState->mCommittedDataVersion;
     404          28 :     return CHIP_NO_ERROR;
     405             : }
     406             : 
     407          32 : void ClusterStateCache::OnEventData(const EventHeader & aEventHeader, TLV::TLVReader * apData, const StatusIB * apStatus)
     408             : {
     409          32 :     VerifyOrDie(apData != nullptr || apStatus != nullptr);
     410             : 
     411             :     TLV::TLVReader dataSnapshot;
     412          32 :     if (apData)
     413             :     {
     414          32 :         dataSnapshot.Init(*apData);
     415             :     }
     416             : 
     417          32 :     UpdateEventCache(aEventHeader, apData, apStatus);
     418          32 :     mCallback.OnEventData(aEventHeader, apData ? &dataSnapshot : nullptr, apStatus);
     419          32 : }
     420             : 
     421           1 : CHIP_ERROR ClusterStateCache::GetStatus(const ConcreteAttributePath & path, StatusIB & status) const
     422             : {
     423             :     CHIP_ERROR err;
     424             : 
     425           1 :     auto attributeState = GetAttributeState(path.mEndpointId, path.mClusterId, path.mAttributeId, err);
     426           1 :     ReturnErrorOnFailure(err);
     427             : 
     428           1 :     if (!attributeState->Is<StatusIB>())
     429             :     {
     430           0 :         return CHIP_ERROR_INVALID_ARGUMENT;
     431             :     }
     432             : 
     433           1 :     status = attributeState->Get<StatusIB>();
     434           1 :     return CHIP_NO_ERROR;
     435             : }
     436             : 
     437           0 : CHIP_ERROR ClusterStateCache::GetStatus(const ConcreteEventPath & path, StatusIB & status) const
     438             : {
     439           0 :     auto statusIter = mEventStatusCache.find(path);
     440           0 :     if (statusIter == mEventStatusCache.end())
     441             :     {
     442           0 :         return CHIP_ERROR_KEY_NOT_FOUND;
     443             :     }
     444             : 
     445           0 :     status = statusIter->second;
     446           0 :     return CHIP_NO_ERROR;
     447             : }
     448             : 
     449         545 : void ClusterStateCache::GetSortedFilters(std::vector<std::pair<DataVersionFilter, size_t>> & aVector) const
     450             : {
     451        1167 :     for (auto const & endpointIter : mCache)
     452             :     {
     453         622 :         EndpointId endpointId = endpointIter.first;
     454        1254 :         for (auto const & clusterIter : endpointIter.second)
     455             :         {
     456         632 :             if (!clusterIter.second.mCommittedDataVersion.HasValue())
     457             :             {
     458          65 :                 continue;
     459             :             }
     460         567 :             DataVersion dataVersion = clusterIter.second.mCommittedDataVersion.Value();
     461         567 :             size_t clusterSize      = 0;
     462         567 :             ClusterId clusterId     = clusterIter.first;
     463             : 
     464        1263 :             for (auto const & attributeIter : clusterIter.second.mAttributes)
     465             :             {
     466         696 :                 if (attributeIter.second.Is<StatusIB>())
     467             :                 {
     468          33 :                     clusterSize += SizeOfStatusIB(attributeIter.second.Get<StatusIB>());
     469             :                 }
     470         663 :                 else if (attributeIter.second.Is<size_t>())
     471             :                 {
     472           0 :                     clusterSize += attributeIter.second.Get<size_t>();
     473             :                 }
     474             :                 else
     475             :                 {
     476         663 :                     VerifyOrDie(attributeIter.second.Is<AttributeData>());
     477             :                     TLV::TLVReader bufReader;
     478         663 :                     bufReader.Init(attributeIter.second.Get<AttributeData>().Get(),
     479         663 :                                    attributeIter.second.Get<AttributeData>().AllocatedSize());
     480         663 :                     ReturnOnFailure(bufReader.Next());
     481             :                     // Skip to the end of the element.
     482         663 :                     ReturnOnFailure(bufReader.Skip());
     483             : 
     484             :                     // Compute the amount of value data
     485         663 :                     clusterSize += bufReader.GetLengthRead();
     486             :                 }
     487             :             }
     488             : 
     489         567 :             if (clusterSize == 0)
     490             :             {
     491             :                 // No data in this cluster, so no point in sending a dataVersion
     492             :                 // along at all.
     493           0 :                 continue;
     494             :             }
     495             : 
     496         567 :             DataVersionFilter filter(endpointId, clusterId, dataVersion);
     497             : 
     498         567 :             aVector.push_back(std::make_pair(filter, clusterSize));
     499         567 :         }
     500             :     }
     501             : 
     502         545 :     std::sort(aVector.begin(), aVector.end(),
     503         156 :               [](const std::pair<DataVersionFilter, size_t> & x, const std::pair<DataVersionFilter, size_t> & y) {
     504         156 :                   return x.second > y.second;
     505             :               });
     506             : }
     507             : 
     508         545 : CHIP_ERROR ClusterStateCache::OnUpdateDataVersionFilterList(DataVersionFilterIBs::Builder & aDataVersionFilterIBsBuilder,
     509             :                                                             const Span<AttributePathParams> & aAttributePaths,
     510             :                                                             bool & aEncodedDataVersionList)
     511             : {
     512         545 :     CHIP_ERROR err = CHIP_NO_ERROR;
     513         545 :     TLV::TLVWriter backup;
     514             : 
     515             :     // Only put paths into mRequestPathSet if they cover clusters in their entirety and no other path in our path list
     516             :     // points to a specific attribute from any of those clusters.
     517             :     // this would help for data-out-of-sync issue when handling store data version for the particular case on two paths: (E1, C1,
     518             :     // wildcard), (wildcard, C1, A1)
     519        1111 :     for (auto & attribute1 : aAttributePaths)
     520             :     {
     521         566 :         if (attribute1.HasWildcardAttributeId())
     522             :         {
     523         544 :             bool intersected = false;
     524        1104 :             for (auto & attribute2 : aAttributePaths)
     525             :             {
     526         561 :                 if (attribute2.HasWildcardAttributeId())
     527             :                 {
     528         555 :                     continue;
     529             :                 }
     530             : 
     531           6 :                 if (attribute1.Intersects(attribute2))
     532             :                 {
     533           1 :                     intersected = true;
     534           1 :                     break;
     535             :                 }
     536             :             }
     537             : 
     538         544 :             if (!intersected)
     539             :             {
     540         543 :                 mRequestPathSet.insert(attribute1);
     541             :             }
     542             :         }
     543             :     }
     544             : 
     545         545 :     std::vector<std::pair<DataVersionFilter, size_t>> filterVector;
     546         545 :     GetSortedFilters(filterVector);
     547             : 
     548         545 :     aEncodedDataVersionList = false;
     549         939 :     for (auto & filter : filterVector)
     550             :     {
     551         549 :         bool intersected = false;
     552         549 :         aDataVersionFilterIBsBuilder.Checkpoint(backup);
     553             : 
     554             :         // if the particular cached cluster does not intersect with user provided attribute paths, skip the cached one
     555         556 :         for (const auto & attributePath : aAttributePaths)
     556             :         {
     557         553 :             if (attributePath.IncludesAttributesInCluster(filter.first))
     558             :             {
     559         546 :                 intersected = true;
     560         546 :                 break;
     561             :             }
     562             :         }
     563         549 :         if (!intersected)
     564             :         {
     565           3 :             continue;
     566             :         }
     567             : 
     568         546 :         DataVersionFilterIB::Builder & filterIB = aDataVersionFilterIBsBuilder.CreateDataVersionFilter();
     569         683 :         SuccessOrExit(err = aDataVersionFilterIBsBuilder.GetError());
     570         528 :         ClusterPathIB::Builder & filterPath = filterIB.CreatePath();
     571         528 :         SuccessOrExit(err = filterIB.GetError());
     572         501 :         SuccessOrExit(err = filterPath.Endpoint(filter.first.mEndpointId).Cluster(filter.first.mClusterId).EndOfClusterPathIB());
     573         418 :         SuccessOrExit(err = filterIB.DataVersion(filter.first.mDataVersion.Value()).EndOfDataVersionFilterIB());
     574         391 :         ChipLogProgress(DataManagement, "Update DataVersionFilter: Endpoint=%u Cluster=" ChipLogFormatMEI " Version=%" PRIu32,
     575             :                         filter.first.mEndpointId, ChipLogValueMEI(filter.first.mClusterId), filter.first.mDataVersion.Value());
     576             : 
     577         391 :         aEncodedDataVersionList = true;
     578             :     }
     579             : 
     580         545 : exit:
     581         545 :     if (err == CHIP_ERROR_NO_MEMORY || err == CHIP_ERROR_BUFFER_TOO_SMALL)
     582             :     {
     583         155 :         ChipLogProgress(DataManagement, "OnUpdateDataVersionFilterList out of space; rolling back");
     584         155 :         aDataVersionFilterIBsBuilder.Rollback(backup);
     585         155 :         err = CHIP_NO_ERROR;
     586             :     }
     587         545 :     return err;
     588         545 : }
     589             : 
     590           0 : CHIP_ERROR ClusterStateCache::GetLastReportDataPath(ConcreteClusterPath & aPath)
     591             : {
     592           0 :     if (mLastReportDataPath.IsValidConcreteClusterPath())
     593             :     {
     594           0 :         aPath = mLastReportDataPath;
     595           0 :         return CHIP_NO_ERROR;
     596             :     }
     597           0 :     return CHIP_ERROR_INCORRECT_STATE;
     598             : }
     599             : } // namespace app
     600             : } // namespace chip

Generated by: LCOV version 1.14