mirror of
https://github.com/meshtastic/Meshtastic-Apple.git
synced 2026-04-20 22:13:56 +00:00
* Fix: "Retrieving nodes" significantly slower after reconnect (#1424) The node database retrieval was calling context.save() for every single NodeInfo packet received (250 saves for 250 nodes). This caused severe performance degradation on reconnect when CoreData had accumulated state. Root Cause: - nodeInfoPacket() called context.save() immediately for each node - With 250 nodes, this meant 250 individual CoreData save operations - On first connection, CoreData is fresh and fast - On reconnect, CoreData has accumulated change tracking, undo management, and memory pressure, making each save progressively slower - This resulted in 10+ second retrieval times vs 1-2 seconds initially Solution: - Added deferSave parameter to nodeInfoPacket() function - During database retrieval (.retrievingDatabase state), defer all saves - Perform a single batch save when database retrieval completes (when NONCE_ONLY_DB configCompleteID is received) - This reduces 250 saves to 1 save Performance Impact: - Eliminates N individual saves during node database sync - Reduces database retrieval time back to 1-2 seconds on reconnect - Matches first-connection performance consistently Fixes #1424 * Revert *MessageListUnified files --------- Co-authored-by: Martin Bogomolni <martinbogo@gmail.com> Co-authored-by: Jake-B <jake-b@users.noreply.github.com>
This commit is contained in:
parent
9e0a1ffea9
commit
16e56e7f07
3 changed files with 24 additions and 6 deletions
|
|
@ -106,8 +106,11 @@ extension AccessoryManager {
|
|||
return
|
||||
}
|
||||
|
||||
// Check if we're in database retrieval mode to defer saves for performance
|
||||
let isRetrievingDatabase = if case .retrievingDatabase = self.state { true } else { false }
|
||||
|
||||
// TODO: nodeInfoPacket's channel: parameter is not used
|
||||
if let nodeInfo = nodeInfoPacket(nodeInfo: nodeInfo, channel: 0, context: context) {
|
||||
if let nodeInfo = nodeInfoPacket(nodeInfo: nodeInfo, channel: 0, context: context, deferSave: isRetrievingDatabase) {
|
||||
if let activeDevice = activeConnection?.device, activeDevice.num == nodeInfo.num {
|
||||
if let user = nodeInfo.user {
|
||||
updateDevice(deviceId: activeDevice.id, key: \.shortName, value: user.shortName ?? "?")
|
||||
|
|
|
|||
|
|
@ -665,6 +665,17 @@ class AccessoryManager: ObservableObject, MqttClientProxyManagerDelegate {
|
|||
self.firstDatabaseNodeInfoContinuation = nil
|
||||
}
|
||||
|
||||
// Perform a single batch save after database retrieval completes
|
||||
// This significantly improves performance on reconnect
|
||||
do {
|
||||
try context.save()
|
||||
Logger.data.info("💾 [Database] Batch saved all node info after database retrieval")
|
||||
} catch {
|
||||
context.rollback()
|
||||
let nsError = error as NSError
|
||||
Logger.data.error("💥 [Database] Error saving batch node info: \(nsError, privacy: .public)")
|
||||
}
|
||||
|
||||
default:
|
||||
Logger.transport.error("[Accessory] Unknown nonce completed: \(configCompleteID)")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -264,7 +264,7 @@ func deviceMetadataPacket (metadata: DeviceMetadata, fromNum: Int64, sessionPass
|
|||
}
|
||||
}
|
||||
|
||||
func nodeInfoPacket (nodeInfo: NodeInfo, channel: UInt32, context: NSManagedObjectContext) -> NodeInfoEntity? {
|
||||
func nodeInfoPacket (nodeInfo: NodeInfo, channel: UInt32, context: NSManagedObjectContext, deferSave: Bool = false) -> NodeInfoEntity? {
|
||||
|
||||
let logString = String.localizedStringWithFormat("[NodeInfo] received for: %@".localized, String(nodeInfo.num))
|
||||
Logger.mesh.info("📟 \(logString, privacy: .public)")
|
||||
|
|
@ -375,8 +375,10 @@ func nodeInfoPacket (nodeInfo: NodeInfo, channel: UInt32, context: NSManagedObje
|
|||
newNode.myInfo = fetchedMyInfo[0]
|
||||
}
|
||||
do {
|
||||
try context.save()
|
||||
Logger.data.info("💾 Saved a new Node Info For: \(String(nodeInfo.num), privacy: .public)")
|
||||
if !deferSave {
|
||||
try context.save()
|
||||
Logger.data.info("💾 Saved a new Node Info For: \(String(nodeInfo.num), privacy: .public)")
|
||||
}
|
||||
return newNode
|
||||
} catch {
|
||||
context.rollback()
|
||||
|
|
@ -500,8 +502,10 @@ func nodeInfoPacket (nodeInfo: NodeInfo, channel: UInt32, context: NSManagedObje
|
|||
fetchedNode[0].myInfo = fetchedMyInfo[0]
|
||||
}
|
||||
do {
|
||||
try context.save()
|
||||
Logger.data.info("💾 [NodeInfo] saved for \(nodeInfo.num.toHex(), privacy: .public)")
|
||||
if !deferSave {
|
||||
try context.save()
|
||||
Logger.data.info("💾 [NodeInfo] saved for \(nodeInfo.num.toHex(), privacy: .public)")
|
||||
}
|
||||
return fetchedNode[0]
|
||||
} catch {
|
||||
context.rollback()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue