diff --git a/src/darwin/Framework/CHIP/MTRDeviceController.mm b/src/darwin/Framework/CHIP/MTRDeviceController.mm index fa90eb2f542831..e7e21c6fc5dc01 100644 --- a/src/darwin/Framework/CHIP/MTRDeviceController.mm +++ b/src/darwin/Framework/CHIP/MTRDeviceController.mm @@ -44,6 +44,7 @@ #import "MTRPersistentStorageDelegateBridge.h" #import "MTRServerEndpoint_Internal.h" #import "MTRSetupPayload.h" +#import "MTRUnfairLock.h" #import "NSDataSpanConversion.h" #import "NSStringSpanConversion.h" #import @@ -607,6 +608,13 @@ - (BOOL)setupCommissioningSessionWithPayload:(MTRSetupPayload *)payload error:(NSError * __autoreleasing *)error { auto block = ^BOOL { + // First reset previous information about this new nodeID + os_unfair_lock_lock(&_deviceMapLock); + [self _removeDeviceWithNodeID:newNodeID device:nil]; + os_unfair_lock_unlock(&_deviceMapLock); + [_controllerDataStore clearResumptionInfoForNodeID:newNodeID]; + [_controllerDataStore clearStoredAttributesForNodeID:newNodeID]; + // Try to get a QR code if possible (because it has a better // discriminator, etc), then fall back to manual code if that fails. NSString * pairingCode = [payload qrCodeString:nil]; @@ -632,6 +640,13 @@ - (BOOL)setupCommissioningSessionWithDiscoveredDevice:(MTRCommissionableBrowserR error:(NSError * __autoreleasing *)error { auto block = ^BOOL { + // First reset previous information about this new nodeID + os_unfair_lock_lock(&_deviceMapLock); + [self _removeDeviceWithNodeID:newNodeID device:nil]; + os_unfair_lock_unlock(&_deviceMapLock); + [_controllerDataStore clearResumptionInfoForNodeID:newNodeID]; + [_controllerDataStore clearStoredAttributesForNodeID:newNodeID]; + chip::NodeId nodeId = [newNodeID unsignedLongLongValue]; self->_operationalCredentialsDelegate->SetDeviceID(nodeId); @@ -897,18 +912,30 @@ - (MTRDevice *)deviceForNodeID:(NSNumber *)nodeID return deviceToReturn; } -- (void)removeDevice:(MTRDevice *)device +// Remove a device from the device map, optionally with a specific object +- (void)_removeDeviceWithNodeID:(NSNumber *)nodeID device:(MTRDevice * _Nullable)deviceToRemove { - os_unfair_lock_lock(&_deviceMapLock); - auto * nodeID = device.nodeID; - MTRDevice * deviceToRemove = _nodeIDToDeviceMap[nodeID]; - if (deviceToRemove == device) { - [deviceToRemove invalidate]; - _nodeIDToDeviceMap[nodeID] = nil; - } else { - MTR_LOG_ERROR("Error: Cannot remove device %p with nodeID %llu", device, nodeID.unsignedLongLongValue); + os_unfair_lock_assert_owner(&_deviceMapLock); + + MTRDevice * device = _nodeIDToDeviceMap[nodeID]; + if (!device) { + MTR_LOG_INFO("No device to remove with nodeID %llu", nodeID.unsignedLongLongValue); + return; } - os_unfair_lock_unlock(&_deviceMapLock); + + if (deviceToRemove && (device != deviceToRemove)) { + MTR_LOG_ERROR("Error: Cannot remove device %p with nodeID %llu", deviceToRemove, nodeID.unsignedLongLongValue); + return; + } + + [deviceToRemove invalidate]; + _nodeIDToDeviceMap[nodeID] = nil; +} + +- (void)removeDevice:(MTRDevice *)device +{ + std::lock_guard lock(_deviceMapLock); + [self _removeDeviceWithNodeID:device.nodeID device:device]; } - (void)setDeviceControllerDelegate:(id)delegate queue:(dispatch_queue_t)queue diff --git a/src/darwin/Framework/CHIP/MTRDeviceControllerDataStore.h b/src/darwin/Framework/CHIP/MTRDeviceControllerDataStore.h index 8df10f63e1d27d..8c562ea78803e0 100644 --- a/src/darwin/Framework/CHIP/MTRDeviceControllerDataStore.h +++ b/src/darwin/Framework/CHIP/MTRDeviceControllerDataStore.h @@ -53,6 +53,7 @@ NS_ASSUME_NONNULL_BEGIN - (nullable MTRCASESessionResumptionInfo *)findResumptionInfoByNodeID:(NSNumber *)nodeID; - (nullable MTRCASESessionResumptionInfo *)findResumptionInfoByResumptionID:(NSData *)resumptionID; - (void)storeResumptionInfo:(MTRCASESessionResumptionInfo *)resumptionInfo; +- (void)clearResumptionInfoForNodeID:(NSNumber *)nodeID; - (void)clearAllResumptionInfo; /** diff --git a/src/darwin/Framework/CHIP/MTRDeviceControllerDataStore.mm b/src/darwin/Framework/CHIP/MTRDeviceControllerDataStore.mm index 0495211b76b449..fd123d9902bfee 100644 --- a/src/darwin/Framework/CHIP/MTRDeviceControllerDataStore.mm +++ b/src/darwin/Framework/CHIP/MTRDeviceControllerDataStore.mm @@ -193,27 +193,54 @@ - (void)storeResumptionInfo:(MTRCASESessionResumptionInfo *)resumptionInfo }); } +- (void)_clearResumptionInfoForNodeID:(NSNumber *)nodeID +{ + auto * oldInfo = [self findResumptionInfoByNodeID:nodeID]; + if (oldInfo != nil) { + dispatch_sync(_storageDelegateQueue, ^{ + [_storageDelegate controller:_controller + removeValueForKey:ResumptionByResumptionIDKey(oldInfo.resumptionID) + securityLevel:MTRStorageSecurityLevelSecure + sharingType:MTRStorageSharingTypeNotShared]; + [_storageDelegate controller:_controller + removeValueForKey:ResumptionByNodeIDKey(oldInfo.nodeID) + securityLevel:MTRStorageSecurityLevelSecure + sharingType:MTRStorageSharingTypeNotShared]; + }); + } +} + +- (void)clearResumptionInfoForNodeID:(NSNumber *)nodeID +{ + if ([_nodesWithResumptionInfo containsObject:nodeID]) { + [self _clearResumptionInfoForNodeID:nodeID]; + [_nodesWithResumptionInfo removeObject:nodeID]; + dispatch_sync(_storageDelegateQueue, ^{ + [_storageDelegate controller:_controller + storeValue:[_nodesWithResumptionInfo copy] + forKey:sResumptionNodeListKey + securityLevel:MTRStorageSecurityLevelSecure + sharingType:MTRStorageSharingTypeNotShared]; + }); + } +} + - (void)clearAllResumptionInfo { // Can we do less dispatch? We would need to have a version of // _findResumptionInfoWithKey that assumes we are already on the right queue. for (NSNumber * nodeID in _nodesWithResumptionInfo) { - auto * oldInfo = [self findResumptionInfoByNodeID:nodeID]; - if (oldInfo != nil) { - dispatch_sync(_storageDelegateQueue, ^{ - [_storageDelegate controller:_controller - removeValueForKey:ResumptionByResumptionIDKey(oldInfo.resumptionID) - securityLevel:MTRStorageSecurityLevelSecure - sharingType:MTRStorageSharingTypeNotShared]; - [_storageDelegate controller:_controller - removeValueForKey:ResumptionByNodeIDKey(oldInfo.nodeID) - securityLevel:MTRStorageSecurityLevelSecure - sharingType:MTRStorageSharingTypeNotShared]; - }); - } + [self clearResumptionInfoForNodeID:nodeID]; } [_nodesWithResumptionInfo removeAllObjects]; + + dispatch_sync(_storageDelegateQueue, ^{ + [_storageDelegate controller:_controller + removeValueForKey:sResumptionNodeListKey + securityLevel:MTRStorageSecurityLevelSecure + sharingType:MTRStorageSharingTypeNotShared]; + }); } - (CHIP_ERROR)storeLastLocallyUsedNOC:(MTRCertificateTLVBytes)noc @@ -329,12 +356,12 @@ - (BOOL)_storeAttributeCacheValue:(id)value forKey:(NSString *)key sharingType:MTRStorageSharingTypeNotShared]; } -- (void)_removeAttributeCacheValueForKey:(NSString *)key +- (BOOL)_removeAttributeCacheValueForKey:(NSString *)key { - [_storageDelegate controller:_controller - removeValueForKey:key - securityLevel:MTRStorageSecurityLevelSecure - sharingType:MTRStorageSharingTypeNotShared]; + return [_storageDelegate controller:_controller + removeValueForKey:key + securityLevel:MTRStorageSecurityLevelSecure + sharingType:MTRStorageSharingTypeNotShared]; } static NSString * sAttributeCacheNodeIndexKey = @"attrCacheNodeIndex"; @@ -349,9 +376,9 @@ - (BOOL)_storeNodeIndex:(NSArray *)nodeIndex return [self _storeAttributeCacheValue:nodeIndex forKey:sAttributeCacheNodeIndexKey]; } -- (void)_deleteNodeIndex +- (BOOL)_deleteNodeIndex { - [self _removeAttributeCacheValueForKey:sAttributeCacheNodeIndexKey]; + return [self _removeAttributeCacheValueForKey:sAttributeCacheNodeIndexKey]; } static NSString * sAttributeCacheEndpointIndexKeyPrefix = @"attrCacheEndpointIndex"; @@ -371,9 +398,9 @@ - (BOOL)_storeEndpointIndex:(NSArray *)endpointIndex forNodeID:(NSNu return [self _storeAttributeCacheValue:endpointIndex forKey:[self _endpointIndexKeyForNodeID:nodeID]]; } -- (void)_deleteEndpointIndexForNodeID:(NSNumber *)nodeID +- (BOOL)_deleteEndpointIndexForNodeID:(NSNumber *)nodeID { - [self _removeAttributeCacheValueForKey:[self _endpointIndexKeyForNodeID:nodeID]]; + return [self _removeAttributeCacheValueForKey:[self _endpointIndexKeyForNodeID:nodeID]]; } static NSString * sAttributeCacheClusterIndexKeyPrefix = @"attrCacheClusterIndex"; @@ -393,9 +420,9 @@ - (BOOL)_storeClusterIndex:(NSArray *)clusterIndex forNodeID:(NSNumb return [self _storeAttributeCacheValue:clusterIndex forKey:[self _clusterIndexKeyForNodeID:nodeID endpointID:endpointID]]; } -- (void)_deleteClusterIndexForNodeID:(NSNumber *)nodeID endpointID:(NSNumber *)endpointID +- (BOOL)_deleteClusterIndexForNodeID:(NSNumber *)nodeID endpointID:(NSNumber *)endpointID { - [self _removeAttributeCacheValueForKey:[self _clusterIndexKeyForNodeID:nodeID endpointID:endpointID]]; + return [self _removeAttributeCacheValueForKey:[self _clusterIndexKeyForNodeID:nodeID endpointID:endpointID]]; } static NSString * sAttributeCacheAttributeIndexKeyPrefix = @"attrCacheAttributeIndex"; @@ -415,9 +442,9 @@ - (BOOL)_storeAttributeIndex:(NSArray *)attributeIndex forNodeID:(NS return [self _storeAttributeCacheValue:attributeIndex forKey:[self _attributeIndexKeyForNodeID:nodeID endpointID:endpointID clusterID:clusterID]]; } -- (void)_deleteAttributeIndexForNodeID:(NSNumber *)nodeID endpointID:(NSNumber *)endpointID clusterID:(NSNumber *)clusterID +- (BOOL)_deleteAttributeIndexForNodeID:(NSNumber *)nodeID endpointID:(NSNumber *)endpointID clusterID:(NSNumber *)clusterID { - [self _removeAttributeCacheValueForKey:[self _attributeIndexKeyForNodeID:nodeID endpointID:endpointID clusterID:clusterID]]; + return [self _removeAttributeCacheValueForKey:[self _attributeIndexKeyForNodeID:nodeID endpointID:endpointID clusterID:clusterID]]; } static NSString * sAttributeCacheAttributeValueKeyPrefix = @"attrCacheAttributeValue"; @@ -437,13 +464,17 @@ - (BOOL)_storeAttributeValue:(NSDictionary *)value forNodeID:(NSNumber *)nodeID return [self _storeAttributeCacheValue:value forKey:[self _attributeValueKeyForNodeID:nodeID endpointID:endpointID clusterID:clusterID attributeID:attributeID]]; } -- (void)_deleteAttributeValueForNodeID:(NSNumber *)nodeID endpointID:(NSNumber *)endpointID clusterID:(NSNumber *)clusterID attributeID:(NSNumber *)attributeID +- (BOOL)_deleteAttributeValueForNodeID:(NSNumber *)nodeID endpointID:(NSNumber *)endpointID clusterID:(NSNumber *)clusterID attributeID:(NSNumber *)attributeID { - [self _removeAttributeCacheValueForKey:[self _attributeValueKeyForNodeID:nodeID endpointID:endpointID clusterID:clusterID attributeID:attributeID]]; + return [self _removeAttributeCacheValueForKey:[self _attributeValueKeyForNodeID:nodeID endpointID:endpointID clusterID:clusterID attributeID:attributeID]]; } #pragma - Attribute Cache management +#ifndef ATTRIBUTE_CACHE_VERBOSE_LOGGING +#define ATTRIBUTE_CACHE_VERBOSE_LOGGING 0 +#endif + - (nullable NSArray *)getStoredAttributesForNodeID:(NSNumber *)nodeID { __block NSMutableArray * attributesToReturn = nil; @@ -451,6 +482,10 @@ - (void)_deleteAttributeValueForNodeID:(NSNumber *)nodeID endpointID:(NSNumber * // Fetch node index NSArray * nodeIndex = [self _fetchNodeIndex]; +#if ATTRIBUTE_CACHE_VERBOSE_LOGGING + MTR_LOG_INFO("Fetch got %lu values for nodeIndex", static_cast(nodeIndex.count)); +#endif + if (![nodeIndex containsObject:nodeID]) { // Sanity check and delete if nodeID exists in index NSArray * endpointIndex = [self _fetchEndpointIndexForNodeID:nodeID]; @@ -458,6 +493,8 @@ - (void)_deleteAttributeValueForNodeID:(NSNumber *)nodeID endpointID:(NSNumber * MTR_LOG_ERROR("Persistent attribute cache contains orphaned entry for nodeID %@ - deleting", nodeID); [self clearStoredAttributesForNodeID:nodeID]; } + + MTR_LOG_INFO("Fetch got no value for endpointIndex @ 0x%016llX", nodeID.unsignedLongLongValue); attributesToReturn = nil; return; } @@ -465,17 +502,33 @@ - (void)_deleteAttributeValueForNodeID:(NSNumber *)nodeID endpointID:(NSNumber * // Fetch endpoint index NSArray * endpointIndex = [self _fetchEndpointIndexForNodeID:nodeID]; +#if ATTRIBUTE_CACHE_VERBOSE_LOGGING + MTR_LOG_INFO("Fetch got %lu values for endpointIndex @ 0x%016llX", static_cast(endpointIndex.count), nodeID.unsignedLongLongValue); +#endif + for (NSNumber * endpointID in endpointIndex) { // Fetch endpoint index NSArray * clusterIndex = [self _fetchClusterIndexForNodeID:nodeID endpointID:endpointID]; +#if ATTRIBUTE_CACHE_VERBOSE_LOGGING + MTR_LOG_INFO("Fetch got %lu values for clusterIndex @ 0x%016llX:0x%04X", static_cast(clusterIndex.count), nodeID.unsignedLongLongValue, endpointID.unsignedShortValue); +#endif + for (NSNumber * clusterID in clusterIndex) { // Fetch endpoint index NSArray * attributeIndex = [self _fetchAttributeIndexForNodeID:nodeID endpointID:endpointID clusterID:clusterID]; +#if ATTRIBUTE_CACHE_VERBOSE_LOGGING + MTR_LOG_INFO("Fetch got %lu values for attributeIndex @ 0x%016llX:0x%04X:0x%08lX", static_cast(attributeIndex.count), nodeID.unsignedLongLongValue, endpointID.unsignedShortValue, clusterID.unsignedLongValue); +#endif + for (NSNumber * attributeID in attributeIndex) { NSDictionary * value = [self _fetchAttributeValueForNodeID:nodeID endpointID:endpointID clusterID:clusterID attributeID:attributeID]; +#if ATTRIBUTE_CACHE_VERBOSE_LOGGING + MTR_LOG_INFO("Fetch got %u values for attribute value @ 0x%016llX:0x%04X:0x%08lX:0x%08lX", value ? 1 : 0, nodeID.unsignedLongLongValue, endpointID.unsignedShortValue, clusterID.unsignedLongValue, attributeID.unsignedLongValue); +#endif + if (value) { if (!attributesToReturn) { attributesToReturn = [NSMutableArray array]; @@ -499,79 +552,95 @@ - (void)_pruneEmptyStoredAttributesBranches { dispatch_assert_queue(_storageDelegateQueue); + NSUInteger storeFailures = 0; + // Fetch node index - NSMutableArray * nodeIndex = [self _fetchNodeIndex].mutableCopy; - NSUInteger nodeIndexCount = nodeIndex.count; + NSArray * nodeIndex = [self _fetchNodeIndex].mutableCopy; + NSMutableArray * nodeIndexCopy = nodeIndex.mutableCopy; - NSUInteger storeFailures = 0; for (NSNumber * nodeID in nodeIndex) { // Fetch endpoint index - NSMutableArray * endpointIndex = [self _fetchEndpointIndexForNodeID:nodeID].mutableCopy; - NSUInteger endpointIndexCount = endpointIndex.count; + NSArray * endpointIndex = [self _fetchEndpointIndexForNodeID:nodeID]; + NSMutableArray * endpointIndexCopy = endpointIndex.mutableCopy; for (NSNumber * endpointID in endpointIndex) { // Fetch endpoint index - NSMutableArray * clusterIndex = [self _fetchClusterIndexForNodeID:nodeID endpointID:endpointID].mutableCopy; - NSUInteger clusterIndexCount = clusterIndex.count; + NSArray * clusterIndex = [self _fetchClusterIndexForNodeID:nodeID endpointID:endpointID].mutableCopy; + NSMutableArray * clusterIndexCopy = clusterIndex.mutableCopy; for (NSNumber * clusterID in clusterIndex) { // Fetch endpoint index - NSMutableArray * attributeIndex = [self _fetchAttributeIndexForNodeID:nodeID endpointID:endpointID clusterID:clusterID].mutableCopy; - NSUInteger attributeIndexCount = attributeIndex.count; + NSArray * attributeIndex = [self _fetchAttributeIndexForNodeID:nodeID endpointID:endpointID clusterID:clusterID].mutableCopy; + NSMutableArray * attributeIndexCopy = attributeIndex.mutableCopy; for (NSNumber * attributeID in attributeIndex) { NSDictionary * value = [self _fetchAttributeValueForNodeID:nodeID endpointID:endpointID clusterID:clusterID attributeID:attributeID]; if (!value) { - [attributeIndex removeObject:attributeID]; + [attributeIndexCopy removeObject:attributeID]; } } - if (!attributeIndex.count) { - [clusterIndex removeObject:clusterID]; - } else if (attributeIndex.count != attributeIndexCount) { - BOOL success = [self _storeAttributeIndex:attributeIndex forNodeID:nodeID endpointID:endpointID clusterID:clusterID]; + if (attributeIndex.count != attributeIndexCopy.count) { + BOOL success; if (!success) { + if (attributeIndexCopy.count) { + success = [self _storeAttributeIndex:attributeIndexCopy forNodeID:nodeID endpointID:endpointID clusterID:clusterID]; + } else { + [clusterIndexCopy removeObject:clusterID]; + success = [self _deleteAttributeIndexForNodeID:nodeID endpointID:endpointID clusterID:clusterID]; + } storeFailures++; - MTR_LOG_INFO("Store failed for attributeIndex"); + MTR_LOG_INFO("Store failed in _pruneEmptyStoredAttributesBranches for attributeIndex @ 0x%016llX:0x%04X:0x%08lX", nodeID.unsignedLongLongValue, endpointID.unsignedShortValue, clusterID.unsignedLongValue); } } } - if (!clusterIndex.count) { - [endpointIndex removeObject:endpointID]; - } else if (clusterIndex.count != clusterIndexCount) { - BOOL success = [self _storeClusterIndex:clusterIndex forNodeID:nodeID endpointID:endpointID]; + if (clusterIndex.count != clusterIndexCopy.count) { + BOOL success; + if (clusterIndex.count) { + success = [self _storeClusterIndex:clusterIndexCopy forNodeID:nodeID endpointID:endpointID]; + } else { + [endpointIndexCopy removeObject:endpointID]; + success = [self _deleteClusterIndexForNodeID:nodeID endpointID:endpointID]; + } if (!success) { storeFailures++; - MTR_LOG_INFO("Store failed for clusterIndex"); + MTR_LOG_INFO("Store failed in _pruneEmptyStoredAttributesBranches for clusterIndex @ 0x%016llX:0x%04X", nodeID.unsignedLongLongValue, endpointID.unsignedShortValue); } } } - if (!endpointIndex.count) { - [nodeIndex removeObject:nodeID]; - } else if (endpointIndex.count != endpointIndexCount) { - BOOL success = [self _storeEndpointIndex:endpointIndex forNodeID:nodeID]; + if (endpointIndex.count != endpointIndexCopy.count) { + BOOL success; + if (endpointIndexCopy.count) { + success = [self _storeEndpointIndex:endpointIndexCopy forNodeID:nodeID]; + } else { + [nodeIndexCopy removeObject:nodeID]; + success = [self _deleteEndpointIndexForNodeID:nodeID]; + } if (!success) { storeFailures++; - MTR_LOG_INFO("Store failed for endpointIndex"); + MTR_LOG_INFO("Store failed in _pruneEmptyStoredAttributesBranches for endpointIndex @ 0x%016llX", nodeID.unsignedLongLongValue); } } } - if (!nodeIndex.count) { - [self _deleteNodeIndex]; - } else if (nodeIndex.count != nodeIndexCount) { - BOOL success = [self _storeNodeIndex:nodeIndex]; + if (nodeIndex.count != nodeIndexCopy.count) { + BOOL success; + if (!nodeIndex.count) { + success = [self _storeNodeIndex:nodeIndexCopy]; + } else { + success = [self _deleteNodeIndex]; + } if (!success) { storeFailures++; - MTR_LOG_INFO("Store failed for nodeIndex"); + MTR_LOG_INFO("Store failed in _pruneEmptyStoredAttributesBranches for nodeIndex"); } } if (storeFailures) { - MTR_LOG_ERROR("Store failed in _pruneEmptyStoredAttributesBranches: %lu", (unsigned long) storeFailures); + MTR_LOG_ERROR("Store failed in _pruneEmptyStoredAttributesBranches: total %lu", static_cast(storeFailures)); } } @@ -584,6 +653,10 @@ - (void)storeAttributeValues:(NSArray *)dataValues forNodeID:(NS MTRAttributePath * path = dataValue[MTRAttributePathKey]; NSDictionary * value = dataValue[MTRDataKey]; +#if ATTRIBUTE_CACHE_VERBOSE_LOGGING + MTR_LOG_INFO("Attempt to store attribute value @ 0x%016llX:0x%04X:0x%08lX:0x%08lX", nodeID.unsignedLongLongValue, path.endpoint.unsignedShortValue, path.cluster.unsignedLongValue, path.attribute.unsignedLongValue); +#endif + BOOL storeFailed = NO; // Ensure node index exists NSArray * nodeIndex = [self _fetchNodeIndex]; @@ -609,7 +682,7 @@ - (void)storeAttributeValues:(NSArray *)dataValues forNodeID:(NS } if (storeFailed) { storeFailures++; - MTR_LOG_INFO("Store failed for endpointIndex"); + MTR_LOG_INFO("Store failed for endpointIndex @ 0x%016llX", nodeID.unsignedLongLongValue); continue; } @@ -623,7 +696,7 @@ - (void)storeAttributeValues:(NSArray *)dataValues forNodeID:(NS } if (storeFailed) { storeFailures++; - MTR_LOG_INFO("Store failed for clusterIndex"); + MTR_LOG_INFO("Store failed for clusterIndex @ 0x%016llX:0x%04X", nodeID.unsignedLongLongValue, path.endpoint.unsignedShortValue); continue; } @@ -640,50 +713,80 @@ - (void)storeAttributeValues:(NSArray *)dataValues forNodeID:(NS } if (storeFailed) { storeFailures++; - MTR_LOG_INFO("Store failed for attributeIndex"); + MTR_LOG_INFO("Store failed for attributeIndex @ 0x%016llX:0x%04X:0x%08lX", nodeID.unsignedLongLongValue, path.endpoint.unsignedShortValue, path.cluster.unsignedLongValue); continue; } // Store value - storeFailed = [self _storeAttributeValue:value forNodeID:nodeID endpointID:path.endpoint clusterID:path.cluster attributeID:path.attribute]; + storeFailed = ![self _storeAttributeValue:value forNodeID:nodeID endpointID:path.endpoint clusterID:path.cluster attributeID:path.attribute]; if (storeFailed) { storeFailures++; - MTR_LOG_INFO("Store failed for attribute value"); + MTR_LOG_INFO("Store failed for attribute value @ 0x%016llX:0x%04X:0x%08lX:0x%08lX", nodeID.unsignedLongLongValue, path.endpoint.unsignedShortValue, path.cluster.unsignedLongValue, path.attribute.unsignedLongValue); } } // In the rare event that store fails, allow all attribute store attempts to go through and prune empty branches at the end altogether. if (storeFailures) { [self _pruneEmptyStoredAttributesBranches]; - MTR_LOG_ERROR("Store failed in -storeAttributeValues:forNodeID: %lu", (unsigned long) storeFailures); + MTR_LOG_ERROR("Store failed in -storeAttributeValues:forNodeID: total %lu", static_cast(storeFailures)); } }); } - (void)_clearStoredAttributesForNodeID:(NSNumber *)nodeID { + NSUInteger endpointsClearAttempts = 0; + NSUInteger clustersClearAttempts = 0; + NSUInteger attributesClearAttempts = 0; + NSUInteger endpointsCleared = 0; + NSUInteger clustersCleared = 0; + NSUInteger attributesCleared = 0; + // Fetch endpoint index NSArray * endpointIndex = [self _fetchEndpointIndexForNodeID:nodeID]; + endpointsClearAttempts += endpointIndex.count; for (NSNumber * endpointID in endpointIndex) { // Fetch cluster index NSArray * clusterIndex = [self _fetchClusterIndexForNodeID:nodeID endpointID:endpointID]; + clustersClearAttempts += clusterIndex.count; for (NSNumber * clusterID in clusterIndex) { // Fetch attribute index NSArray * attributeIndex = [self _fetchAttributeIndexForNodeID:nodeID endpointID:endpointID clusterID:clusterID]; + attributesClearAttempts += attributeIndex.count; for (NSNumber * attributeID in attributeIndex) { - [self _deleteAttributeValueForNodeID:nodeID endpointID:endpointID clusterID:clusterID attributeID:attributeID]; + BOOL success = [self _deleteAttributeValueForNodeID:nodeID endpointID:endpointID clusterID:clusterID attributeID:attributeID]; + if (!success) { + MTR_LOG_INFO("Delete failed for attribute value @ 0x%016llX:0x%04X:0x%08lX:0x%08lX", nodeID.unsignedLongLongValue, endpointID.unsignedShortValue, clusterID.unsignedLongValue, attributeID.unsignedLongValue); + } else { + attributesCleared++; + } + } + + BOOL success = [self _deleteAttributeIndexForNodeID:nodeID endpointID:endpointID clusterID:clusterID]; + if (!success) { + MTR_LOG_INFO("Delete failed for attributeIndex @ 0x%016llX:0x%04X:0x%08lX", nodeID.unsignedLongLongValue, endpointID.unsignedShortValue, clusterID.unsignedLongValue); + } else { + clustersCleared++; } + } - [self _deleteAttributeIndexForNodeID:nodeID endpointID:endpointID clusterID:clusterID]; + BOOL success = [self _deleteClusterIndexForNodeID:nodeID endpointID:endpointID]; + if (!success) { + MTR_LOG_INFO("Delete failed for clusterIndex @ 0x%016llX:0x%04X", nodeID.unsignedLongLongValue, endpointID.unsignedShortValue); + } else { + endpointsCleared++; } + } - [self _deleteClusterIndexForNodeID:nodeID endpointID:endpointID]; + BOOL success = [self _deleteEndpointIndexForNodeID:nodeID]; + if (!success) { + MTR_LOG_INFO("Delete failed for endpointrIndex @ 0x%016llX", nodeID.unsignedLongLongValue); } - [self _deleteEndpointIndexForNodeID:nodeID]; + MTR_LOG_INFO("clearStoredAttributesForNodeID: deleted endpoints %lu/%lu clusters %lu/%lu attributes %lu/%lu", static_cast(endpointsCleared), static_cast(endpointsClearAttempts), static_cast(clustersCleared), static_cast(clustersClearAttempts), static_cast(attributesCleared), static_cast(attributesClearAttempts)); } - (void)clearStoredAttributesForNodeID:(NSNumber *)nodeID @@ -703,7 +806,10 @@ - (void)clearAllStoredAttributes [self _clearStoredAttributesForNodeID:nodeID]; } - [self _deleteNodeIndex]; + BOOL success = [self _deleteNodeIndex]; + if (!success) { + MTR_LOG_INFO("Delete failed for nodeIndex"); + } }); }