Reduce transactions during getAndPossiblyMerge.

This commit is contained in:
Greyson Parrelli
2023-11-10 08:27:27 -08:00
parent e9bd35619d
commit b0733dcd51

View File

@@ -446,6 +446,14 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da
fun getAndPossiblyMerge(aci: ACI?, pni: PNI?, e164: String?, pniVerified: Boolean = false, changeSelf: Boolean = false): RecipientId {
require(aci != null || pni != null || e164 != null) { "Must provide an ACI, PNI, or E164!" }
// To avoid opening a transaction and doing extra reads, we start with a single read that checks if all of the fields already match a single recipient
val singleMatch: RecipientId? = getRecipientIdIfAllFieldsMatch(aci, pni, e164)
if (singleMatch != null) {
return singleMatch
}
Log.d(TAG, "[getAndPossiblyMerge] Requires a transaction.")
val db = writableDatabase
var transactionSuccessful = false
lateinit var result: ProcessPnpTupleResult
@@ -2618,6 +2626,40 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da
)
}
/**
* If all of the non-null fields match a single recipient, return it. Otherwise null.
*/
private fun getRecipientIdIfAllFieldsMatch(aci: ACI?, pni: PNI?, e164: String?): RecipientId? {
if (aci == null && pni == null && e164 == null) {
return null
}
val columns = listOf(
ACI_COLUMN to aci?.toString(),
PNI_COLUMN to pni?.toString(),
E164 to e164
).filter { it.second != null }
val query = columns
.map { "${it.first} = ?" }
.joinToString(separator = " AND ")
val args: Array<String> = columns.map { it.second!! }.toTypedArray()
val ids: List<Long> = readableDatabase
.select(ID)
.from(TABLE_NAME)
.where(query, args)
.run()
.readToList { it.requireLong(ID) }
return if (ids.size == 1) {
RecipientId.from(ids[0])
} else {
null
}
}
/**
* A session switchover event indicates a situation where we start communicating with a different session that we were before.
* If a switchover is "verified" (i.e. proven safe cryptographically by the sender), then this doesn't require a user-visible event.