mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-04-18 07:47:47 +01:00
Update delete column migration to use a single insert.
This commit is contained in:
@@ -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> {
|
||||
|
||||
Reference in New Issue
Block a user