Make sure pending metadata is reset and is thread safe

Summary: We have gotton concurrent modification crashes from this

Reviewed By: lblasa

Differential Revision: D42343224

fbshipit-source-id: 9cf4046da63d40cbe6632c3ae24d95abd21081ba
This commit is contained in:
Luke De Feo
2023-01-25 04:47:11 -08:00
committed by Facebook GitHub Bot
parent 18b6ce6f24
commit 412d10b280
3 changed files with 25 additions and 21 deletions

View File

@@ -59,7 +59,7 @@ class UIDebuggerFlipperPlugin(
MetadataUpdateEvent.name, MetadataUpdateEvent.name,
Json.encodeToString( Json.encodeToString(
MetadataUpdateEvent.serializer(), MetadataUpdateEvent.serializer(),
MetadataUpdateEvent(MetadataRegister.getPendingMetadata()))) MetadataUpdateEvent(MetadataRegister.extractPendingMetadata())))
context.treeObserverManager.start() context.treeObserverManager.start()
} }

View File

@@ -23,9 +23,11 @@ object MetadataRegister {
const val TYPE_LAYOUT = "layout" const val TYPE_LAYOUT = "layout"
const val TYPE_DOCUMENTATION = "documentation" const val TYPE_DOCUMENTATION = "documentation"
private val lock = "lock"
private var generator: MetadataId = 0 private var generator: MetadataId = 0
private val register: MutableMap<String, Metadata> = mutableMapOf() private val register: MutableMap<String, Metadata> = mutableMapOf()
private val pending: MutableSet<String> = mutableSetOf() private val pendingKeys: MutableSet<String> = mutableSetOf()
private fun key(namespace: String, name: String): String = "${namespace}_$name" private fun key(namespace: String, name: String): String = "${namespace}_$name"
@@ -41,38 +43,40 @@ object MetadataRegister {
return m.id return m.id
} }
synchronized(lock) {
val identifier = ++generator val identifier = ++generator
val metadata = Metadata(identifier, type, namespace, name, mutable, possibleValues) val metadata = Metadata(identifier, type, namespace, name, mutable, possibleValues)
register[key] = metadata register[key] = metadata
pending.add(key) pendingKeys.add(key)
return identifier return identifier
} }
}
fun get(namespace: String, name: String): Metadata? { fun get(namespace: String, name: String): Metadata? {
val key = key(namespace, name) val key = key(namespace, name)
return register[key] return register[key]
} }
fun getMetadata(): Map<MetadataId, Metadata> { /** gets all pending metadata to be sent and resets the pending list */
val metadata: MutableMap<MetadataId, Metadata> = mutableMapOf() fun extractPendingMetadata(): Map<MetadataId, Metadata> {
register.forEach { entry -> metadata[entry.value.id] = entry.value } synchronized(lock) {
return metadata
}
fun getPendingMetadata(): Map<MetadataId, Metadata> {
val pendingMetadata: MutableMap<MetadataId, Metadata> = mutableMapOf() val pendingMetadata: MutableMap<MetadataId, Metadata> = mutableMapOf()
pending.forEach { key ->
pendingKeys.forEach { key ->
register[key]?.let { metadata -> pendingMetadata[metadata.id] = metadata } register[key]?.let { metadata -> pendingMetadata[metadata.id] = metadata }
} }
pendingKeys.clear()
return pendingMetadata return pendingMetadata
} }
}
fun reset() { fun reset() {
pending.clear() synchronized(lock) {
register.forEach { entry -> pending.add(entry.key) } pendingKeys.clear()
register.forEach { entry -> pendingKeys.add(entry.key) }
}
} }
} }

View File

@@ -90,7 +90,7 @@ class TreeObserverManager(val context: Context) {
} }
private fun sendMetadata() { private fun sendMetadata() {
val metadata = MetadataRegister.getPendingMetadata() val metadata = MetadataRegister.extractPendingMetadata()
if (metadata.size > 0) { if (metadata.size > 0) {
context.connectionRef.connection?.send( context.connectionRef.connection?.send(
MetadataUpdateEvent.name, MetadataUpdateEvent.name,