mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-02-15 07:28:30 +00:00
Improve backup import resilience for duplicate messages.
This commit is contained in:
committed by
jeffrey-signal
parent
19afd5c0e6
commit
8d931391db
@@ -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(
|
||||
|
||||
@@ -403,13 +403,13 @@ object SqlUtil {
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun buildBulkInsert(tableName: String, columns: Array<String>, contentValues: List<ContentValues>): List<Query> {
|
||||
fun buildBulkInsert(tableName: String, columns: Array<String>, contentValues: List<ContentValues>, onConflict: String? = null): List<Query> {
|
||||
return buildBulkInsert(tableName, columns, contentValues, MAX_QUERY_ARGS)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@VisibleForTesting
|
||||
fun buildBulkInsert(tableName: String, columns: Array<String>, contentValues: List<ContentValues>, maxQueryArgs: Int): List<Query> {
|
||||
fun buildBulkInsert(tableName: String, columns: Array<String>, contentValues: List<ContentValues>, maxQueryArgs: Int, onConflict: String? = null): List<Query> {
|
||||
val batchSize = maxQueryArgs / columns.size
|
||||
|
||||
return contentValues
|
||||
|
||||
@@ -238,7 +238,7 @@ public final class SqlUtilTest {
|
||||
|
||||
contentValues.add(cv1);
|
||||
|
||||
List<SqlUtil.Query> output = SqlUtil.buildBulkInsert("mytable", new String[] { "a", "b"}, contentValues);
|
||||
List<SqlUtil.Query> output = SqlUtil.buildBulkInsert("mytable", new String[] { "a", "b"}, contentValues, null);
|
||||
|
||||
assertEquals(1, output.size());
|
||||
assertEquals("INSERT INTO mytable (a, b) VALUES (?, ?)", output.get(0).getWhere());
|
||||
@@ -256,7 +256,7 @@ public final class SqlUtilTest {
|
||||
|
||||
contentValues.add(cv1);
|
||||
|
||||
List<SqlUtil.Query> output = SqlUtil.buildBulkInsert("mytable", new String[] { "a", "b", "c"}, contentValues);
|
||||
List<SqlUtil.Query> output = SqlUtil.buildBulkInsert("mytable", new String[] { "a", "b", "c"}, contentValues, null);
|
||||
|
||||
assertEquals(1, output.size());
|
||||
assertEquals("INSERT INTO mytable (a, b, c) VALUES (?, ?, null)", output.get(0).getWhere());
|
||||
@@ -278,7 +278,7 @@ public final class SqlUtilTest {
|
||||
contentValues.add(cv1);
|
||||
contentValues.add(cv2);
|
||||
|
||||
List<SqlUtil.Query> output = SqlUtil.buildBulkInsert("mytable", new String[] { "a", "b"}, contentValues);
|
||||
List<SqlUtil.Query> output = SqlUtil.buildBulkInsert("mytable", new String[] { "a", "b"}, contentValues, null);
|
||||
|
||||
assertEquals(1, output.size());
|
||||
assertEquals("INSERT INTO mytable (a, b) VALUES (?, ?), (?, ?)", output.get(0).getWhere());
|
||||
@@ -305,7 +305,7 @@ public final class SqlUtilTest {
|
||||
contentValues.add(cv2);
|
||||
contentValues.add(cv3);
|
||||
|
||||
List<SqlUtil.Query> output = SqlUtil.buildBulkInsert("mytable", new String[] { "a", "b"}, contentValues, 4);
|
||||
List<SqlUtil.Query> output = SqlUtil.buildBulkInsert("mytable", new String[] { "a", "b"}, contentValues, 4, null);
|
||||
|
||||
assertEquals(2, output.size());
|
||||
|
||||
|
||||
Reference in New Issue
Block a user