Improve backup import resilience for duplicate messages.

This commit is contained in:
Greyson Parrelli
2025-10-27 12:24:59 -04:00
committed by jeffrey-signal
parent 19afd5c0e6
commit 8d931391db
3 changed files with 30 additions and 13 deletions

View File

@@ -84,6 +84,7 @@ import org.whispersystems.signalservice.api.push.ServiceId
import org.whispersystems.signalservice.api.util.UuidUtil
import org.whispersystems.signalservice.internal.push.DataMessage
import java.math.BigInteger
import java.sql.SQLException
import java.util.Optional
import java.util.UUID
import org.thoughtcrime.securesms.backup.v2.proto.GiftBadge as BackupGiftBadge
@@ -226,12 +227,17 @@ class ChatItemArchiveImporter(
}
var messageInsertIndex = 0
SqlUtil.buildBulkInsert(MessageTable.TABLE_NAME, MESSAGE_COLUMNS, buffer.messages.map { it.contentValues }).forEach { query ->
db.rawQuery("${query.where} RETURNING ${MessageTable.ID}", query.whereArgs).forEach { cursor ->
val finalMessageId = cursor.requireLong(MessageTable.ID)
val relatedInsert = buffer.messages[messageInsertIndex++]
relatedInsert.followUp?.invoke(finalMessageId)
try {
SqlUtil.buildBulkInsert(MessageTable.TABLE_NAME, MESSAGE_COLUMNS, buffer.messages.map { it.contentValues }, onConflict = "IGNORE").forEach { query ->
db.rawQuery("${query.where} RETURNING ${MessageTable.ID}", query.whereArgs).forEach { cursor ->
val finalMessageId = cursor.requireLong(MessageTable.ID)
val relatedInsert = buffer.messages[messageInsertIndex++]
relatedInsert.followUp?.invoke(finalMessageId)
}
}
} catch (e: SQLException) {
Log.w(TAG, "Failed to bulk-insert message! Trying one at at time.", e)
performIndividualMessageInserts(buffer.messages)
}
SqlUtil.buildBulkInsert(ReactionTable.TABLE_NAME, REACTION_COLUMNS, buffer.reactions).forEach {
@@ -249,6 +255,18 @@ class ChatItemArchiveImporter(
return true
}
private fun performIndividualMessageInserts(messageInserts: List<MessageInsert>) {
for (message in messageInserts) {
val values = message.contentValues
try {
db.insert(MessageTable.TABLE_NAME, SQLiteDatabase.CONFLICT_IGNORE, values)
message.followUp?.invoke(messageId - 1)
} catch (e: SQLException) {
Log.w(TAG, "Failed to insert message with timestamp ${message.contentValues.get(MessageTable.DATE_SENT)}. Must skip.", e)
}
}
}
private fun ChatItem.toMessageInsert(fromRecipientId: RecipientId, chatRecipientId: RecipientId, threadId: Long): MessageInsert {
val contentValues = this.toMessageContentValues(fromRecipientId, chatRecipientId, threadId)
@@ -1260,8 +1278,7 @@ class ChatItemArchiveImporter(
private class MessageInsert(
val contentValues: ContentValues,
val followUp: ((Long) -> Unit)?,
val edits: List<MessageInsert>? = null
val followUp: ((Long) -> Unit)?
)
private class Buffer(