Improve receipt processing via faster thread updates.

This commit is contained in:
Greyson Parrelli 2023-11-10 11:11:42 -08:00
parent b0733dcd51
commit a81e5c4e6b
2 changed files with 71 additions and 9 deletions

View file

@ -1678,17 +1678,39 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
.run()
}
fun getIncomingMeaningfulMessageCountSince(threadId: Long, afterTime: Long): Int {
val meaningfulMessagesQuery = buildMeaningfulMessagesQuery(threadId)
val where = "${meaningfulMessagesQuery.where} AND $DATE_RECEIVED >= ? AND NOT ($outgoingTypeClause)"
val whereArgs = appendArg(meaningfulMessagesQuery.whereArgs, afterTime.toString())
/**
* Returns the receipt status of the most recent meaningful message in the thread if it matches the provided message ID.
* If the ID doesn't match or otherwise can't be found, it will return null.
*
* This is a very specific method for use with [ThreadTable.updateReceiptStatus] to improve the perfomance of
* processing receipts.
*/
fun getReceiptStatusIfItsTheMostRecentMeaningfulMessage(messageId: Long, threadId: Long): MessageReceiptStatus? {
val query = buildMeaningfulMessagesQuery(threadId)
return readableDatabase
.select("COUNT(*)")
.select(ID, DELIVERY_RECEIPT_COUNT, READ_RECEIPT_COUNT, VIEWED_RECEIPT_COUNT, TYPE)
.from(TABLE_NAME)
.where(where, whereArgs)
.where(query.where, query.whereArgs)
.orderBy("$DATE_RECEIVED DESC")
.limit(1)
.run()
.readToSingleInt()
.use { cursor ->
if (cursor.moveToFirst()) {
if (cursor.requireLong(ID) != messageId) {
return null
}
return MessageReceiptStatus(
deliveryCount = cursor.requireInt(DELIVERY_RECEIPT_COUNT),
readCount = cursor.requireInt(READ_RECEIPT_COUNT),
viewedCount = cursor.requireInt(VIEWED_RECEIPT_COUNT),
type = cursor.requireLong(TYPE)
)
} else {
null
}
}
}
private fun buildMeaningfulMessagesQuery(threadId: Long): SqlUtil.Query {
@ -4129,7 +4151,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
messageUpdates = incrementReceiptCountInternal(targetTimestamp, receiptAuthor, receiptSentTimestamp, receiptType, messageQualifier)
for (messageUpdate in messageUpdates) {
threads.update(messageUpdate.threadId, false)
threads.updateReceiptStatus(messageUpdate.messageId.id, messageUpdate.threadId)
}
}
@ -4161,7 +4183,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
for (update in messageUpdates) {
if (update.shouldUpdateSnippet) {
threads.updateSilently(update.threadId, false)
threads.updateReceiptStatus(update.messageId.id, update.threadId)
}
}
}
@ -4722,6 +4744,17 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
VIEWED(VIEWED_RECEIPT_COUNT, GroupReceiptTable.STATUS_VIEWED)
}
data class MessageReceiptStatus(
val readCount: Int,
val deliveryCount: Int,
val viewedCount: Int,
val type: Long
)
enum class MessageStatus {
PENDING, SENT, DELIVERED, READ, VIEWED, FAILED
}
data class SyncMessageId(
val recipientId: RecipientId,
val timetamp: Long

View file

@ -1402,6 +1402,35 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa
)
}
/**
* Updates the thread with the receipt status of the message provided, but only if that message is the most recent meaningful message.
* The idea here is that if it _is_ the most meaningful message, we can set the new status. If it's not, there's no need to update
* the thread at all.
*/
fun updateReceiptStatus(messageId: Long, threadId: Long) {
val status = messages.getReceiptStatusIfItsTheMostRecentMeaningfulMessage(messageId, threadId)
if (status != null) {
Log.d(TAG, "Updating receipt status for thread $threadId")
writableDatabase
.update(TABLE_NAME)
.values(
DELIVERY_RECEIPT_COUNT to status.deliveryCount,
READ_RECEIPT_COUNT to status.readCount,
STATUS to when {
MessageTypes.isFailedMessageType(status.type) -> MessageTable.Status.STATUS_FAILED
MessageTypes.isSentType(status.type) -> MessageTable.Status.STATUS_COMPLETE
MessageTypes.isPendingMessageType(status.type) -> MessageTable.Status.STATUS_PENDING
else -> MessageTable.Status.STATUS_NONE
}
)
.where("$ID = ?", threadId)
.run()
} else {
Log.d(TAG, "Receipt was for an old message, not updating thread.")
}
}
private fun update(threadId: Long, unarchive: Boolean, allowDeletion: Boolean, notifyListeners: Boolean): Boolean {
if (threadId == -1L) {
Log.d(TAG, "Skipping update for threadId -1")