@@ -151,6 +151,20 @@ - (nullable instancetype)initWithController:(MTRDeviceController *)controller
151
151
return self;
152
152
}
153
153
154
+ - (void )fetchAttributeDataForAllDevices : (MTRDeviceControllerDataStoreClusterDataHandler)clusterDataHandler
155
+ {
156
+ __block NSDictionary <NSString *, id > * dataStoreSecureLocalValues = nil ;
157
+ dispatch_sync (_storageDelegateQueue, ^{
158
+ if ([self ->_storageDelegate respondsToSelector: @selector (valuesForController:securityLevel:sharingType: )]) {
159
+ dataStoreSecureLocalValues = [self ->_storageDelegate valuesForController: self ->_controller securityLevel: MTRStorageSecurityLevelSecure sharingType: MTRStorageSharingTypeNotShared];
160
+ }
161
+ });
162
+
163
+ if (dataStoreSecureLocalValues.count ) {
164
+ clusterDataHandler ([self _getClusterDataFromSecureLocalValues: dataStoreSecureLocalValues]);
165
+ }
166
+ }
167
+
154
168
- (nullable MTRCASESessionResumptionInfo *)findResumptionInfoByNodeID : (NSNumber *)nodeID
155
169
{
156
170
return [self _findResumptionInfoWithKey: ResumptionByNodeIDKey (nodeID)];
@@ -337,6 +351,14 @@ - (BOOL)_storeAttributeCacheValue:(id)value forKey:(NSString *)key
337
351
sharingType: MTRStorageSharingTypeNotShared];
338
352
}
339
353
354
+ - (BOOL )_bulkStoreAttributeCacheValues : (NSDictionary <NSString *, id<NSSecureCoding >> *)values
355
+ {
356
+ return [_storageDelegate controller: _controller
357
+ storeValues: values
358
+ securityLevel: MTRStorageSecurityLevelSecure
359
+ sharingType: MTRStorageSharingTypeNotShared];
360
+ }
361
+
340
362
- (BOOL )_removeAttributeCacheValueForKey : (NSString *)key
341
363
{
342
364
return [_storageDelegate controller: _controller
@@ -968,6 +990,76 @@ - (void)clearAllStoredAttributes
968
990
return clusterDataToReturn;
969
991
}
970
992
993
+ // Utility for constructing dictionary of nodeID to cluster data from dictionary of storage keys
994
+ - (nullable NSDictionary <NSNumber *, NSDictionary<MTRClusterPath *, MTRDeviceClusterData *> *> *)_getClusterDataFromSecureLocalValues : (NSDictionary <NSString *, id> *)secureLocalValues
995
+ {
996
+ NSMutableDictionary <NSNumber *, NSDictionary <MTRClusterPath *, MTRDeviceClusterData *> *> * clusterDataByNodeToReturn = nil ;
997
+
998
+ if (![secureLocalValues isKindOfClass: [NSDictionary class ]]) {
999
+ return nil ;
1000
+ }
1001
+
1002
+ // Fetch node index
1003
+ NSArray <NSNumber *> * nodeIndex = secureLocalValues[sAttributeCacheNodeIndexKey ];
1004
+
1005
+ if (![nodeIndex isKindOfClass: [NSArray class ]]) {
1006
+ return nil ;
1007
+ }
1008
+
1009
+ for (NSNumber * nodeID in nodeIndex) {
1010
+ if (![nodeID isKindOfClass: [NSNumber class ]]) {
1011
+ continue ;
1012
+ }
1013
+
1014
+ NSMutableDictionary <MTRClusterPath *, MTRDeviceClusterData *> * clusterDataForNode = nil ;
1015
+ NSArray <NSNumber *> * endpointIndex = secureLocalValues[[self _endpointIndexKeyForNodeID: nodeID]];
1016
+
1017
+ if (![endpointIndex isKindOfClass: [NSArray class ]]) {
1018
+ continue ;
1019
+ }
1020
+
1021
+ for (NSNumber * endpointID in endpointIndex) {
1022
+ if (![endpointID isKindOfClass: [NSNumber class ]]) {
1023
+ continue ;
1024
+ }
1025
+
1026
+ NSArray <NSNumber *> * clusterIndex = secureLocalValues[[self _clusterIndexKeyForNodeID: nodeID endpointID: endpointID]];
1027
+
1028
+ if (![clusterIndex isKindOfClass: [NSArray class ]]) {
1029
+ continue ;
1030
+ }
1031
+
1032
+ for (NSNumber * clusterID in clusterIndex) {
1033
+ if (![clusterID isKindOfClass: [NSNumber class ]]) {
1034
+ continue ;
1035
+ }
1036
+
1037
+ MTRDeviceClusterData * clusterData = secureLocalValues[[self _clusterDataKeyForNodeID: nodeID endpointID: endpointID clusterID: clusterID]];
1038
+ if (!clusterData) {
1039
+ continue ;
1040
+ }
1041
+ if (![clusterData isKindOfClass: [MTRDeviceClusterData class ]]) {
1042
+ continue ;
1043
+ }
1044
+ MTRClusterPath * clusterPath = [MTRClusterPath clusterPathWithEndpointID: endpointID clusterID: clusterID];
1045
+ if (!clusterDataForNode) {
1046
+ clusterDataForNode = [NSMutableDictionary dictionary ];
1047
+ }
1048
+ clusterDataForNode[clusterPath] = clusterData;
1049
+ }
1050
+ }
1051
+
1052
+ if (clusterDataForNode.count ) {
1053
+ if (!clusterDataByNodeToReturn) {
1054
+ clusterDataByNodeToReturn = [NSMutableDictionary dictionary ];
1055
+ }
1056
+ clusterDataByNodeToReturn[nodeID] = clusterDataForNode;
1057
+ }
1058
+ }
1059
+
1060
+ return clusterDataByNodeToReturn;
1061
+ }
1062
+
971
1063
- (void )storeClusterData : (NSDictionary <MTRClusterPath *, MTRDeviceClusterData *> *)clusterData forNodeID : (NSNumber *)nodeID
972
1064
{
973
1065
if (!nodeID) {
@@ -983,6 +1075,11 @@ - (void)storeClusterData:(NSDictionary<MTRClusterPath *, MTRDeviceClusterData *>
983
1075
dispatch_async (_storageDelegateQueue, ^{
984
1076
NSUInteger storeFailures = 0 ;
985
1077
1078
+ NSMutableDictionary <NSString *, id <NSSecureCoding >> * bulkValuesToStore = nil ;
1079
+ if ([self ->_storageDelegate respondsToSelector: @selector (controller:storeValues:securityLevel:sharingType: )]) {
1080
+ bulkValuesToStore = [NSMutableDictionary dictionary ];
1081
+ }
1082
+
986
1083
// A map of endpoint => list of clusters modified for that endpoint so cluster indexes can be updated later
987
1084
NSMutableDictionary <NSNumber *, NSMutableSet <NSNumber *> *> * clustersModified = [NSMutableDictionary dictionary ];
988
1085
@@ -993,11 +1090,15 @@ - (void)storeClusterData:(NSDictionary<MTRClusterPath *, MTRDeviceClusterData *>
993
1090
MTR_LOG_INFO (" Attempt to store clusterData @ node 0x%016llX endpoint %u cluster 0x%08lX" , nodeID.unsignedLongLongValue , path.endpoint .unsignedShortValue , path.cluster .unsignedLongValue );
994
1091
#endif
995
1092
996
- // Store cluster data
997
- BOOL storeFailed = ![self _storeClusterData: data forNodeID: nodeID endpointID: path.endpoint clusterID: path.cluster];
998
- if (storeFailed) {
999
- storeFailures++;
1000
- MTR_LOG_INFO (" Store failed for clusterDAta @ node 0x%016llX endpoint %u cluster 0x%08lX" , nodeID.unsignedLongLongValue , path.endpoint .unsignedShortValue , path.cluster .unsignedLongValue );
1093
+ if (bulkValuesToStore) {
1094
+ bulkValuesToStore[[self _clusterDataKeyForNodeID: nodeID endpointID: path.endpoint clusterID: path.cluster]] = data;
1095
+ } else {
1096
+ // Store cluster data
1097
+ BOOL storeFailed = ![self _storeClusterData: data forNodeID: nodeID endpointID: path.endpoint clusterID: path.cluster];
1098
+ if (storeFailed) {
1099
+ storeFailures++;
1100
+ MTR_LOG_INFO (" Store failed for clusterData @ node 0x%016llX endpoint %u cluster 0x%08lX" , nodeID.unsignedLongLongValue , path.endpoint .unsignedShortValue , path.cluster .unsignedLongValue );
1101
+ }
1001
1102
}
1002
1103
1003
1104
// Note the cluster as modified for the endpoint
@@ -1046,36 +1147,60 @@ - (void)storeClusterData:(NSDictionary<MTRClusterPath *, MTRDeviceClusterData *>
1046
1147
}
1047
1148
1048
1149
if (clusterIndexModified) {
1049
- BOOL storeFailed = ![self _storeClusterIndex: clusterIndexToStore forNodeID: nodeID endpointID: endpointID];
1050
- if (storeFailed) {
1051
- storeFailures++;
1052
- MTR_LOG_INFO (" Store failed for clusterIndex @ node 0x%016llX endpoint %u" , nodeID.unsignedLongLongValue , endpointID.unsignedShortValue );
1053
- continue ;
1150
+ if (bulkValuesToStore) {
1151
+ bulkValuesToStore[[self _clusterIndexKeyForNodeID: nodeID endpointID: endpointID]] = clusterIndexToStore;
1152
+ } else {
1153
+ BOOL storeFailed = ![self _storeClusterIndex: clusterIndexToStore forNodeID: nodeID endpointID: endpointID];
1154
+ if (storeFailed) {
1155
+ storeFailures++;
1156
+ MTR_LOG_INFO (" Store failed for clusterIndex @ node 0x%016llX endpoint %u" , nodeID.unsignedLongLongValue , endpointID.unsignedShortValue );
1157
+ continue ;
1158
+ }
1054
1159
}
1055
1160
}
1056
1161
}
1057
1162
1058
1163
// Update endpoint index as needed
1059
1164
if (endpointIndexModified) {
1060
- BOOL storeFailed = ![self _storeEndpointIndex: endpointIndexToStore forNodeID: nodeID];
1061
- if (storeFailed) {
1062
- storeFailures++;
1063
- MTR_LOG_INFO (" Store failed for endpointIndex @ node 0x%016llX" , nodeID.unsignedLongLongValue );
1165
+ if (bulkValuesToStore) {
1166
+ bulkValuesToStore[[self _endpointIndexKeyForNodeID: nodeID]] = endpointIndexToStore;
1167
+ } else {
1168
+ BOOL storeFailed = ![self _storeEndpointIndex: endpointIndexToStore forNodeID: nodeID];
1169
+ if (storeFailed) {
1170
+ storeFailures++;
1171
+ MTR_LOG_INFO (" Store failed for endpointIndex @ node 0x%016llX" , nodeID.unsignedLongLongValue );
1172
+ }
1064
1173
}
1065
1174
}
1066
1175
1067
- // Ensure node index exists
1176
+ // Check if node index needs updating / creation
1068
1177
NSArray <NSNumber *> * nodeIndex = [self _fetchNodeIndex ];
1069
- BOOL storeFailed = NO ;
1178
+ NSArray < NSNumber *> * nodeIndexToStore = nil ;
1070
1179
if (!nodeIndex) {
1071
- nodeIndex = [ NSArray arrayWithObject: nodeID];
1072
- storeFailed = ![ self _storeNodeIndex: nodeIndex ];
1180
+ // Ensure node index exists
1181
+ nodeIndexToStore = [ NSArray arrayWithObject: nodeID ];
1073
1182
} else if (![nodeIndex containsObject: nodeID]) {
1074
- storeFailed = ![ self _storeNodeIndex: [ nodeIndex arrayByAddingObject: nodeID] ];
1183
+ nodeIndexToStore = [ nodeIndex arrayByAddingObject: nodeID];
1075
1184
}
1076
- if (storeFailed) {
1077
- storeFailures++;
1078
- MTR_LOG_INFO (" Store failed for nodeIndex" );
1185
+
1186
+ if (nodeIndexToStore) {
1187
+ if (bulkValuesToStore) {
1188
+ bulkValuesToStore[sAttributeCacheNodeIndexKey ] = nodeIndexToStore;
1189
+ } else {
1190
+ BOOL storeFailed = ![self _storeNodeIndex: nodeIndexToStore];
1191
+ if (storeFailed) {
1192
+ storeFailures++;
1193
+ MTR_LOG_INFO (" Store failed for nodeIndex" );
1194
+ }
1195
+ }
1196
+ }
1197
+
1198
+ if (bulkValuesToStore) {
1199
+ BOOL storeFailed = ![self _bulkStoreAttributeCacheValues: bulkValuesToStore];
1200
+ if (storeFailed) {
1201
+ storeFailures++;
1202
+ MTR_LOG_INFO (" Store failed for bulk values count %lu" , static_cast <unsigned long >(bulkValuesToStore.count ));
1203
+ }
1079
1204
}
1080
1205
1081
1206
// In the rare event that store fails, allow all attribute store attempts to go through and prune empty branches at the end altogether.
0 commit comments