Update delete column migration to use a single insert.

This commit is contained in:
Greyson Parrelli
2026-03-06 14:56:15 -05:00
parent 43e7d65af5
commit 0605cc0a9c

View File

@@ -9,13 +9,13 @@ import org.signal.core.util.requireNonNullString
import org.thoughtcrime.securesms.database.SQLiteDatabase
/**
* Adds column to messages to track who has deleted a given message. Because of an
* OOM crash, we rebuild the table manually in batches instead of using the drop column syntax.
* Adds column to messages to track who has deleted a given message. We rebuild the table
* manually instead of using ALTER TABLE to drop the column, which previously caused OOM crashes.
*/
@Suppress("ClassName")
object V302_AddDeletedByColumn : SignalDatabaseMigration {
private val TAG = Log.tag(V302_AddDeletedByColumn::class.java)
private val TAG = Log.tag(V302_AddDeletedByColumn::class)
override fun migrate(context: Application, db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
if (SqlUtil.columnExists(db, "message", "deleted_by")) {
@@ -33,12 +33,6 @@ object V302_AddDeletedByColumn : SignalDatabaseMigration {
}
stopwatch.split("drop-dependents")
db.execSQL("ALTER TABLE message ADD COLUMN deleted_by INTEGER DEFAULT NULL REFERENCES recipient (_id) ON DELETE CASCADE")
stopwatch.split("add-column")
db.execSQL("UPDATE message SET deleted_by = from_recipient_id WHERE remote_deleted > 0")
stopwatch.split("update-data")
db.execSQL(
"""
CREATE TABLE message_tmp (
@@ -106,41 +100,6 @@ object V302_AddDeletedByColumn : SignalDatabaseMigration {
)
stopwatch.split("create-table")
copyMessages(db)
stopwatch.split("copy-data")
db.execSQL("DROP TABLE message")
stopwatch.split("drop-old-table")
db.execSQL("ALTER TABLE message_tmp RENAME TO message")
stopwatch.split("rename-table")
dependentItems.forEach { item ->
val sql = item.createStatement
Log.d(TAG, "Executing: $sql")
db.execSQL(sql)
}
stopwatch.split("recreate-dependents")
db.execSQL("CREATE INDEX IF NOT EXISTS message_deleted_by_index ON message (deleted_by)")
stopwatch.split("create-index")
val foreignKeyViolations: List<SqlUtil.ForeignKeyViolation> = SqlUtil.getForeignKeyViolations(db, "message")
if (foreignKeyViolations.isNotEmpty()) {
Log.w(TAG, "Foreign key violations!\n${foreignKeyViolations.joinToString(separator = "\n")}")
throw IllegalStateException("Foreign key violations!")
}
stopwatch.split("fk-check")
stopwatch.stop(TAG)
}
private fun copyMessages(db: SQLiteDatabase) {
val batchSize = 50_000L
val maxId = SqlUtil.getNextAutoIncrementId(db, "message")
for (i in 1..maxId step batchSize) {
db.execSQL(
"""
INSERT INTO message_tmp
@@ -203,15 +162,37 @@ object V302_AddDeletedByColumn : SignalDatabaseMigration {
pinned_until,
pinning_message_id,
pinned_at,
deleted_by
CASE WHEN remote_deleted > 0 THEN from_recipient_id ELSE NULL END AS deleted_by
FROM
message
WHERE
_id >= $i AND
_id < ${i + batchSize}
"""
)
stopwatch.split("copy-data")
db.execSQL("DROP TABLE message")
stopwatch.split("drop-old-table")
db.execSQL("ALTER TABLE message_tmp RENAME TO message")
stopwatch.split("rename-table")
dependentItems.forEach { item ->
val sql = item.createStatement
Log.d(TAG, "Executing: $sql")
db.execSQL(sql)
}
stopwatch.split("recreate-dependents")
db.execSQL("CREATE INDEX IF NOT EXISTS message_deleted_by_index ON message (deleted_by)")
stopwatch.split("create-index")
val foreignKeyViolations: List<SqlUtil.ForeignKeyViolation> = SqlUtil.getForeignKeyViolations(db, "message")
if (foreignKeyViolations.isNotEmpty()) {
Log.w(TAG, "Foreign key violations!\n${foreignKeyViolations.joinToString(separator = "\n")}")
throw IllegalStateException("Foreign key violations!")
}
stopwatch.split("fk-check")
stopwatch.stop(TAG)
}
private fun getAllDependentItems(db: SQLiteDatabase, tableName: String): List<SqlItem> {