Refactor: Add new indexes to the history table

Adds two new indexes to the `history2` table:
*   `history_by_time` on the `time` column.
*   `history_by_key_and_time` on the `pkKey` and `time` columns.

This change also bumps the database version from 10 to 11 and includes the corresponding migration.
This commit is contained in:
greenart7c3
2025-10-22 10:14:12 -03:00
parent 9b57a0ea09
commit cc1f4ca5de
5 changed files with 533 additions and 4 deletions
@@ -2,7 +2,7 @@
"formatVersion": 1,
"database": {
"version": 10,
"identityHash": "bd08ac27efa990e98825cdcc6e8e167d",
"identityHash": "431c73ad09acac77a9c7d0edb1372e8b",
"entities": [
{
"tableName": "application",
@@ -443,13 +443,32 @@
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `history_by_id2` ON `${TABLE_NAME}` (`id`)"
},
{
"name": "history_by_time",
"unique": false,
"columnNames": [
"time"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `history_by_time` ON `${TABLE_NAME}` (`time`)"
},
{
"name": "history_by_key_and_time",
"unique": false,
"columnNames": [
"pkKey",
"time"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `history_by_key_and_time` ON `${TABLE_NAME}` (`pkKey`, `time`)"
}
]
}
],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'bd08ac27efa990e98825cdcc6e8e167d')"
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '431c73ad09acac77a9c7d0edb1372e8b')"
]
}
}
@@ -0,0 +1,474 @@
{
"formatVersion": 1,
"database": {
"version": 11,
"identityHash": "431c73ad09acac77a9c7d0edb1372e8b",
"entities": [
{
"tableName": "application",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`key` TEXT NOT NULL, `name` TEXT NOT NULL, `relays` TEXT NOT NULL, `url` TEXT NOT NULL, `icon` TEXT NOT NULL, `description` TEXT NOT NULL, `pubKey` TEXT NOT NULL, `isConnected` INTEGER NOT NULL, `secret` TEXT NOT NULL, `useSecret` INTEGER NOT NULL, `signPolicy` INTEGER NOT NULL, `closeApplication` INTEGER NOT NULL, `deleteAfter` INTEGER NOT NULL, PRIMARY KEY(`key`))",
"fields": [
{
"fieldPath": "key",
"columnName": "key",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "name",
"columnName": "name",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "relays",
"columnName": "relays",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "url",
"columnName": "url",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "icon",
"columnName": "icon",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "description",
"columnName": "description",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "pubKey",
"columnName": "pubKey",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "isConnected",
"columnName": "isConnected",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "secret",
"columnName": "secret",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "useSecret",
"columnName": "useSecret",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "signPolicy",
"columnName": "signPolicy",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "closeApplication",
"columnName": "closeApplication",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "deleteAfter",
"columnName": "deleteAfter",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"key"
]
},
"indices": [
{
"name": "index_key",
"unique": true,
"columnNames": [
"key"
],
"orders": [],
"createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_key` ON `${TABLE_NAME}` (`key`)"
},
{
"name": "index_name",
"unique": false,
"columnNames": [
"name"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `index_name` ON `${TABLE_NAME}` (`name`)"
}
]
},
{
"tableName": "applicationPermission",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER, `pkKey` TEXT NOT NULL, `type` TEXT NOT NULL, `kind` INTEGER, `acceptable` INTEGER NOT NULL, `rememberType` INTEGER NOT NULL, `acceptUntil` INTEGER NOT NULL, `rejectUntil` INTEGER NOT NULL, PRIMARY KEY(`id`), FOREIGN KEY(`pkKey`) REFERENCES `application`(`key`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER"
},
{
"fieldPath": "pkKey",
"columnName": "pkKey",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "type",
"columnName": "type",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "kind",
"columnName": "kind",
"affinity": "INTEGER"
},
{
"fieldPath": "acceptable",
"columnName": "acceptable",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "rememberType",
"columnName": "rememberType",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "acceptUntil",
"columnName": "acceptUntil",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "rejectUntil",
"columnName": "rejectUntil",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"id"
]
},
"indices": [
{
"name": "permissions_by_pk_key",
"unique": false,
"columnNames": [
"pkKey"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `permissions_by_pk_key` ON `${TABLE_NAME}` (`pkKey`)"
},
{
"name": "permissions_unique",
"unique": true,
"columnNames": [
"pkKey",
"type",
"kind"
],
"orders": [],
"createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `permissions_unique` ON `${TABLE_NAME}` (`pkKey`, `type`, `kind`)"
}
],
"foreignKeys": [
{
"table": "application",
"onDelete": "CASCADE",
"onUpdate": "NO ACTION",
"columns": [
"pkKey"
],
"referencedColumns": [
"key"
]
}
]
},
{
"tableName": "notification",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `eventId` TEXT NOT NULL, `time` INTEGER NOT NULL)",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "eventId",
"columnName": "eventId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "time",
"columnName": "time",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": true,
"columnNames": [
"id"
]
},
"indices": [
{
"name": "index_notification_eventId",
"unique": false,
"columnNames": [
"eventId"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `index_notification_eventId` ON `${TABLE_NAME}` (`eventId`)"
},
{
"name": "index_notification_time",
"unique": false,
"columnNames": [
"time"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `index_notification_time` ON `${TABLE_NAME}` (`time`)"
}
]
},
{
"tableName": "history",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `pkKey` TEXT NOT NULL, `type` TEXT NOT NULL, `kind` INTEGER, `time` INTEGER NOT NULL, `accepted` INTEGER NOT NULL, FOREIGN KEY(`pkKey`) REFERENCES `application`(`key`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "pkKey",
"columnName": "pkKey",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "type",
"columnName": "type",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "kind",
"columnName": "kind",
"affinity": "INTEGER"
},
{
"fieldPath": "time",
"columnName": "time",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "accepted",
"columnName": "accepted",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": true,
"columnNames": [
"id"
]
},
"indices": [
{
"name": "history_by_pk_key",
"unique": false,
"columnNames": [
"pkKey"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `history_by_pk_key` ON `${TABLE_NAME}` (`pkKey`)"
},
{
"name": "history_by_id",
"unique": false,
"columnNames": [
"id"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `history_by_id` ON `${TABLE_NAME}` (`id`)"
}
],
"foreignKeys": [
{
"table": "application",
"onDelete": "CASCADE",
"onUpdate": "NO ACTION",
"columns": [
"pkKey"
],
"referencedColumns": [
"key"
]
}
]
},
{
"tableName": "amber_log",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `url` TEXT NOT NULL, `type` TEXT NOT NULL, `message` TEXT NOT NULL, `time` INTEGER NOT NULL)",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "url",
"columnName": "url",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "type",
"columnName": "type",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "message",
"columnName": "message",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "time",
"columnName": "time",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": true,
"columnNames": [
"id"
]
}
},
{
"tableName": "history2",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `pkKey` TEXT NOT NULL, `type` TEXT NOT NULL, `kind` INTEGER, `time` INTEGER NOT NULL, `accepted` INTEGER NOT NULL)",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "pkKey",
"columnName": "pkKey",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "type",
"columnName": "type",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "kind",
"columnName": "kind",
"affinity": "INTEGER"
},
{
"fieldPath": "time",
"columnName": "time",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "accepted",
"columnName": "accepted",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": true,
"columnNames": [
"id"
]
},
"indices": [
{
"name": "history_by_pk_key2",
"unique": false,
"columnNames": [
"pkKey"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `history_by_pk_key2` ON `${TABLE_NAME}` (`pkKey`)"
},
{
"name": "history_by_id2",
"unique": false,
"columnNames": [
"id"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `history_by_id2` ON `${TABLE_NAME}` (`id`)"
},
{
"name": "history_by_time",
"unique": false,
"columnNames": [
"time"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `history_by_time` ON `${TABLE_NAME}` (`time`)"
},
{
"name": "history_by_key_and_time",
"unique": false,
"columnNames": [
"pkKey",
"time"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `history_by_key_and_time` ON `${TABLE_NAME}` (`pkKey`, `time`)"
}
]
}
],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '431c73ad09acac77a9c7d0edb1372e8b')"
]
}
}
@@ -191,6 +191,8 @@ class Amber : Application(), LifecycleObserver {
override fun onCreate() {
super.onCreate()
isStartingAppState.value = true
isStartingApp.value = true
Thread.setDefaultUncaughtExceptionHandler(UnexpectedCrashSaver(crashReportCache, applicationIOScope))
@@ -256,12 +258,29 @@ class Amber : Application(), LifecycleObserver {
LocalPreferences.reloadApp()
fixRejectedPermissions()
fixAcceptedPermissions()
isStartingApp.value = false
checkForNewRelaysAndUpdateAllFilters(true)
if (settings.killSwitch.value) {
client.disconnect()
}
// LocalPreferences.allSavedAccounts(this@Amber).forEach {
// List<Int>(100000, init = { 1 }).forEachIndexed { index, it2 ->
// launch(Dispatchers.IO) {
// getDatabase(it.npub).applicationDao().addHistory(
// HistoryEntity2(
// id = 0,
// pkKey = "com.vitorpamplona.amethyst",
// type = "SIGN_EVENT",
// kind = 1,
// time = TimeUtils.now() + index,
// accepted = true,
// )
// )
// }
// }
// }
launch(Dispatchers.Main) {
ProcessLifecycleOwner.get().lifecycle.addObserver(object : DefaultLifecycleObserver {
override fun onStart(owner: LifecycleOwner) {
@@ -287,6 +306,7 @@ class Amber : Application(), LifecycleObserver {
}
})
}
isStartingApp.value = false
} catch (e: Exception) {
Log.e(TAG, "Failed to run migrations", e)
isStartingApp.value = false
@@ -93,6 +93,13 @@ val MIGRATION_9_10 = object : Migration(9, 10) {
}
}
val MIGRATION_10_11 = object : Migration(10, 11) {
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL("CREATE INDEX IF NOT EXISTS `history_by_time` ON `history2` (`time`)")
db.execSQL("CREATE INDEX IF NOT EXISTS `history_by_key_and_time` ON `history2` (`pkKey`, `time`)")
}
}
@Database(
entities = [
ApplicationEntity::class,
@@ -102,7 +109,7 @@ val MIGRATION_9_10 = object : Migration(9, 10) {
LogEntity::class,
HistoryEntity2::class,
],
version = 10,
version = 11,
)
@TypeConverters(Converters::class)
abstract class AppDatabase : RoomDatabase() {
@@ -134,6 +141,7 @@ abstract class AppDatabase : RoomDatabase() {
.addMigrations(MIGRATION_7_8)
.addMigrations(MIGRATION_8_9)
.addMigrations(MIGRATION_9_10)
.addMigrations(MIGRATION_10_11)
.build()
instance.openHelper.writableDatabase.execSQL("VACUUM")
@@ -47,6 +47,14 @@ data class HistoryEntity(
value = ["id"],
name = "history_by_id2",
),
Index(
value = ["time"],
name = "history_by_time",
),
Index(
value = ["pkKey", "time"],
name = "history_by_key_and_time",
),
],
)
data class HistoryEntity2(