From 613a07eb2cc7d0c51b7f487017a9e8e2db767a2e Mon Sep 17 00:00:00 2001 From: Greyson Parrelli Date: Mon, 22 Jun 2026 14:53:58 +0000 Subject: [PATCH] Optimize single name collision check. --- .../securesms/database/NameCollisionTables.kt | 28 ++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/NameCollisionTables.kt b/app/src/main/java/org/thoughtcrime/securesms/database/NameCollisionTables.kt index 9c7f3d1098..208ea94cf4 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/NameCollisionTables.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/NameCollisionTables.kt @@ -220,7 +220,7 @@ class NameCollisionTables( .run() } - pruneCollisions() + pruneCollision(collisionId) } } @@ -473,6 +473,32 @@ class NameCollisionTables( ) } + /** + * Removes the given collision if it has fewer than two members. + * + * Unlike [pruneCollisions], this is scoped to a single collision so it can be used on hot paths + * (e.g. opening a conversation) without scanning the entire [NameCollisionTable] while holding the + * write lock. Callers that may have modified the membership of more than one collision should + * continue to use [pruneCollisions]. + */ + private fun pruneCollision(collisionId: Long) { + check(writableDatabase.inTransaction()) + + writableDatabase.execSQL( + """ + DELETE FROM ${NameCollisionTable.TABLE_NAME} + WHERE $ID = ? AND $ID NOT IN ( + SELECT ${NameCollisionMembershipTable.COLLISION_ID} + FROM ${NameCollisionMembershipTable.TABLE_NAME} + WHERE ${NameCollisionMembershipTable.COLLISION_ID} = ? + GROUP BY ${NameCollisionMembershipTable.COLLISION_ID} + HAVING COUNT(*) >= 2 + ) + """.trimIndent(), + arrayOf(collisionId, collisionId) + ) + } + private fun getDuplicatedGroupRecipients(groupId: V2, toCheck: Set): List { if (toCheck.isEmpty()) { return emptyList()