Improve receipt perf by caching the pending PNI signature table.
This commit is contained in:
parent
ebef4b079c
commit
b7ec913cb9
1 changed files with 54 additions and 25 deletions
|
@ -8,7 +8,10 @@ import org.signal.core.util.logging.Log
|
|||
import org.signal.core.util.update
|
||||
import org.signal.core.util.withinTransaction
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId
|
||||
import org.thoughtcrime.securesms.util.LRUCache
|
||||
import org.whispersystems.signalservice.api.messages.SendMessageResult
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock
|
||||
import kotlin.concurrent.withLock
|
||||
|
||||
/**
|
||||
* Contains records of messages that have been sent with PniSignatures on them.
|
||||
|
@ -41,45 +44,71 @@ class PendingPniSignatureMessageTable(context: Context, databaseHelper: SignalDa
|
|||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Caches whether or not there are any pending PNI signature messages for a given recipient.
|
||||
* - If there are, there will be an entry with 'true' for that recipient.
|
||||
* - If there aren't, there will be an entry with 'false'.
|
||||
* - If the entry is null, we do not know, and you should check the database.
|
||||
*
|
||||
* This cache exists because this table is hit very frequently via delivery receipt handling.
|
||||
*/
|
||||
private val pendingPniSignaturesCache: MutableMap<RecipientId, Boolean?> = LRUCache(1000)
|
||||
private val pendingPniSignaturesCacheLock = ReentrantReadWriteLock()
|
||||
|
||||
fun insertIfNecessary(recipientId: RecipientId, sentTimestamp: Long, result: SendMessageResult) {
|
||||
if (!result.isSuccess) {
|
||||
if (!result.isSuccess || result.success.devices.isEmpty()) {
|
||||
return
|
||||
}
|
||||
|
||||
writableDatabase.withinTransaction { db ->
|
||||
for (deviceId in result.success.devices) {
|
||||
val values = contentValuesOf(
|
||||
RECIPIENT_ID to recipientId.serialize(),
|
||||
SENT_TIMESTAMP to sentTimestamp,
|
||||
DEVICE_ID to deviceId
|
||||
)
|
||||
pendingPniSignaturesCacheLock.writeLock().withLock {
|
||||
writableDatabase.withinTransaction { db ->
|
||||
for (deviceId in result.success.devices) {
|
||||
val values = contentValuesOf(
|
||||
RECIPIENT_ID to recipientId.serialize(),
|
||||
SENT_TIMESTAMP to sentTimestamp,
|
||||
DEVICE_ID to deviceId
|
||||
)
|
||||
|
||||
db.insertWithOnConflict(TABLE_NAME, null, values, SQLiteDatabase.CONFLICT_IGNORE)
|
||||
db.insertWithOnConflict(TABLE_NAME, null, values, SQLiteDatabase.CONFLICT_IGNORE)
|
||||
}
|
||||
}
|
||||
|
||||
pendingPniSignaturesCache[recipientId] = true
|
||||
}
|
||||
}
|
||||
|
||||
fun acknowledgeReceipts(recipientId: RecipientId, sentTimestamps: Collection<Long>, deviceId: Int) {
|
||||
writableDatabase.withinTransaction { db ->
|
||||
val count = db
|
||||
.delete(TABLE_NAME)
|
||||
.where("$RECIPIENT_ID = ? AND $SENT_TIMESTAMP IN (?) AND $DEVICE_ID = ?", recipientId, sentTimestamps.joinToString(separator = ","), deviceId)
|
||||
.run()
|
||||
|
||||
if (count <= 0) {
|
||||
return@withinTransaction
|
||||
pendingPniSignaturesCacheLock.readLock().withLock {
|
||||
if (pendingPniSignaturesCache[recipientId] == false) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
val stillPending: Boolean = db.exists(TABLE_NAME).where("$RECIPIENT_ID = ? AND $SENT_TIMESTAMP = ?", recipientId, sentTimestamps).run()
|
||||
|
||||
if (!stillPending) {
|
||||
Log.i(TAG, "All devices for ($recipientId, $sentTimestamps) have acked the PNI signature message. Clearing flag and removing any other pending receipts.")
|
||||
SignalDatabase.recipients.clearNeedsPniSignature(recipientId)
|
||||
|
||||
db
|
||||
pendingPniSignaturesCacheLock.writeLock().withLock {
|
||||
writableDatabase.withinTransaction { db ->
|
||||
val count = db
|
||||
.delete(TABLE_NAME)
|
||||
.where("$RECIPIENT_ID = ?", recipientId)
|
||||
.where("$RECIPIENT_ID = ? AND $SENT_TIMESTAMP IN (?) AND $DEVICE_ID = ?", recipientId, sentTimestamps.joinToString(separator = ","), deviceId)
|
||||
.run()
|
||||
|
||||
if (count <= 0) {
|
||||
pendingPniSignaturesCache[recipientId] = false
|
||||
return@withinTransaction
|
||||
}
|
||||
|
||||
val stillPending: Boolean = db.exists(TABLE_NAME).where("$RECIPIENT_ID = ? AND $SENT_TIMESTAMP = ?", recipientId, sentTimestamps).run()
|
||||
|
||||
if (!stillPending) {
|
||||
Log.i(TAG, "All devices for ($recipientId, $sentTimestamps) have acked the PNI signature message. Clearing flag and removing any other pending receipts.")
|
||||
SignalDatabase.recipients.clearNeedsPniSignature(recipientId)
|
||||
|
||||
db
|
||||
.delete(TABLE_NAME)
|
||||
.where("$RECIPIENT_ID = ?", recipientId)
|
||||
.run()
|
||||
}
|
||||
|
||||
pendingPniSignaturesCache[recipientId] = stillPending
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue