From 3319279a67083508f7f447132e8726df14d0f11e Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Fri, 5 Jul 2024 14:08:02 -0400 Subject: [PATCH] Add methods to clear data from the cluster state cache. (#34186) This allows consumers to clear stale data when they detects PartsList/ServerList/AttributeList changes. --- src/app/ClusterStateCache.cpp | 41 +++++++++++ src/app/ClusterStateCache.h | 16 +++++ src/app/tests/TestClusterStateCache.cpp | 93 +++++++++++++++++++++++++ 3 files changed, 150 insertions(+) diff --git a/src/app/ClusterStateCache.cpp b/src/app/ClusterStateCache.cpp index e3dd3dd8d84ca4..65ab12095bfeba 100644 --- a/src/app/ClusterStateCache.cpp +++ b/src/app/ClusterStateCache.cpp @@ -648,6 +648,47 @@ CHIP_ERROR ClusterStateCacheT::OnUpdateDataVersionFilterLi return err; } +template +void ClusterStateCacheT::ClearAttributes(EndpointId endpointId) +{ + mCache.erase(endpointId); +} + +template +void ClusterStateCacheT::ClearAttributes(const ConcreteClusterPath & cluster) +{ + // Can't use GetEndpointState here, since that only handles const things. + auto endpointIter = mCache.find(cluster.mEndpointId); + if (endpointIter == mCache.end()) + { + return; + } + + auto & endpointState = endpointIter->second; + endpointState.erase(cluster.mClusterId); +} + +template +void ClusterStateCacheT::ClearAttribute(const ConcreteAttributePath & attribute) +{ + // Can't use GetClusterState here, since that only handles const things. + auto endpointIter = mCache.find(attribute.mEndpointId); + if (endpointIter == mCache.end()) + { + return; + } + + auto & endpointState = endpointIter->second; + auto clusterIter = endpointState.find(attribute.mClusterId); + if (clusterIter == endpointState.end()) + { + return; + } + + auto & clusterState = clusterIter->second; + clusterState.mAttributes.erase(attribute.mAttributeId); +} + template CHIP_ERROR ClusterStateCacheT::GetLastReportDataPath(ConcreteClusterPath & aPath) { diff --git a/src/app/ClusterStateCache.h b/src/app/ClusterStateCache.h index 948a4dba8794b0..e17596e3bf515e 100644 --- a/src/app/ClusterStateCache.h +++ b/src/app/ClusterStateCache.h @@ -504,6 +504,22 @@ class ClusterStateCacheT : protected ReadClient::Callback } } + /* + * Clear out all the attribute data and DataVersions stored for a given endpoint. + */ + void ClearAttributes(EndpointId endpoint); + + /* + * Clear out all the attribute data and the DataVersion stored for a given cluster. + */ + void ClearAttributes(const ConcreteClusterPath & cluster); + + /* + * Clear out the data (or size, if not storing data) stored for an + * attribute. + */ + void ClearAttribute(const ConcreteAttributePath & attribute); + /* * Clear out the event data and status caches. * diff --git a/src/app/tests/TestClusterStateCache.cpp b/src/app/tests/TestClusterStateCache.cpp index b4f41df2278b14..782c8f07f87347 100644 --- a/src/app/tests/TestClusterStateCache.cpp +++ b/src/app/tests/TestClusterStateCache.cpp @@ -101,6 +101,11 @@ struct AttributeInstruction } } + ConcreteAttributePath GetAttributePath() const + { + return ConcreteAttributePath(mEndpointId, Clusters::UnitTesting::Id, GetAttributeId()); + } + static uint8_t sInstructionId; }; @@ -626,6 +631,94 @@ void RunAndValidateSequence(AttributeInstructionListType list) ++bufferSize; } while (true); + + // Now check clearing behavior. First for attributes. + ConcreteAttributePath firstAttr = list[0].GetAttributePath(); + + TLV::TLVReader reader; + CHIP_ERROR err = cache.Get(firstAttr, reader); + // Should have gotten a value or status for now. + EXPECT_NE(err, CHIP_ERROR_KEY_NOT_FOUND); + + cache.ClearAttribute(firstAttr); + + err = cache.Get(firstAttr, reader); + // Should have gotten no value. + EXPECT_EQ(err, CHIP_ERROR_KEY_NOT_FOUND); + + // Now clearing for clusters. First check that things that should be there are. + for (auto & listItem : list) + { + ConcreteAttributePath path = listItem.GetAttributePath(); + if (path == firstAttr) + { + // We removed this one already. + continue; + } + + err = cache.Get(path, reader); + + // Should have gotten a value or status for now. + EXPECT_NE(err, CHIP_ERROR_KEY_NOT_FOUND); + } + + auto firstCluster = ConcreteClusterPath(firstAttr); + cache.ClearAttributes(firstCluster); + + for (auto & listItem : list) + { + ConcreteAttributePath path = listItem.GetAttributePath(); + + err = cache.Get(path, reader); + + if (ConcreteClusterPath(path) == firstCluster) + { + EXPECT_EQ(err, CHIP_ERROR_KEY_NOT_FOUND); + } + else + { + // Should still have a value or status + EXPECT_NE(err, CHIP_ERROR_KEY_NOT_FOUND); + } + } + + // Now clearing for endpoints. First check that things that should be there are. + // TODO: Since all our attributes have the same cluster, this is not + // actually testing anything useful right now. + for (auto & listItem : list) + { + ConcreteAttributePath path = listItem.GetAttributePath(); + if (ConcreteClusterPath(path) == firstCluster) + { + // We removed this one already. + continue; + } + + err = cache.Get(path, reader); + + // Should have gotten a value or status for now. + EXPECT_NE(err, CHIP_ERROR_KEY_NOT_FOUND); + } + + auto firstEndpoint = firstAttr.mEndpointId; + cache.ClearAttributes(firstEndpoint); + + for (auto & listItem : list) + { + ConcreteAttributePath path = listItem.GetAttributePath(); + + err = cache.Get(path, reader); + + if (path.mEndpointId == firstEndpoint) + { + EXPECT_EQ(err, CHIP_ERROR_KEY_NOT_FOUND); + } + else + { + // Should still have a value or status + EXPECT_NE(err, CHIP_ERROR_KEY_NOT_FOUND); + } + } } /*