Skip to content

Commit

Permalink
Improved performance when deleting and importing events
Browse files Browse the repository at this point in the history
  • Loading branch information
greenart7c3 committed Dec 11, 2024
1 parent 933decc commit 31c208b
Show file tree
Hide file tree
Showing 10 changed files with 375 additions and 62 deletions.
15 changes: 13 additions & 2 deletions app/schemas/com.greenart7c3.citrine.database.AppDatabase/1.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"formatVersion": 1,
"database": {
"version": 1,
"identityHash": "3b07bf4ea94274460773626c1fe0957e",
"identityHash": "bf90c485bbfb3751761eb581ab24cf07",
"entities": [
{
"tableName": "EventEntity",
Expand Down Expand Up @@ -73,6 +73,17 @@
"ASC"
],
"createSql": "CREATE INDEX IF NOT EXISTS `most_common_search_is_pubkey_kind` ON `${TABLE_NAME}` (`pubkey` ASC, `kind` ASC)"
},
{
"name": "most_common_search_is_kind",
"unique": false,
"columnNames": [
"kind"
],
"orders": [
"ASC"
],
"createSql": "CREATE INDEX IF NOT EXISTS `most_common_search_is_kind` ON `${TABLE_NAME}` (`kind` ASC)"
}
],
"foreignKeys": []
Expand Down Expand Up @@ -175,7 +186,7 @@
"views": [],
"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, '3b07bf4ea94274460773626c1fe0957e')"
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'bf90c485bbfb3751761eb581ab24cf07')"
]
}
}
192 changes: 192 additions & 0 deletions app/schemas/com.greenart7c3.citrine.database.AppDatabase/2.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
{
"formatVersion": 1,
"database": {
"version": 2,
"identityHash": "bf90c485bbfb3751761eb581ab24cf07",
"entities": [
{
"tableName": "EventEntity",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `pubkey` TEXT NOT NULL, `createdAt` INTEGER NOT NULL, `kind` INTEGER NOT NULL, `content` TEXT NOT NULL, `sig` TEXT NOT NULL, PRIMARY KEY(`id`))",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "pubkey",
"columnName": "pubkey",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "createdAt",
"columnName": "createdAt",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "kind",
"columnName": "kind",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "content",
"columnName": "content",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "sig",
"columnName": "sig",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"id"
]
},
"indices": [
{
"name": "id_is_hash",
"unique": true,
"columnNames": [
"id"
],
"orders": [],
"createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `id_is_hash` ON `${TABLE_NAME}` (`id`)"
},
{
"name": "most_common_search_is_pubkey_kind",
"unique": false,
"columnNames": [
"pubkey",
"kind"
],
"orders": [
"ASC",
"ASC"
],
"createSql": "CREATE INDEX IF NOT EXISTS `most_common_search_is_pubkey_kind` ON `${TABLE_NAME}` (`pubkey` ASC, `kind` ASC)"
},
{
"name": "most_common_search_is_kind",
"unique": false,
"columnNames": [
"kind"
],
"orders": [
"ASC"
],
"createSql": "CREATE INDEX IF NOT EXISTS `most_common_search_is_kind` ON `${TABLE_NAME}` (`kind` ASC)"
}
],
"foreignKeys": []
},
{
"tableName": "TagEntity",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`pk` INTEGER PRIMARY KEY AUTOINCREMENT, `pkEvent` TEXT, `position` INTEGER NOT NULL, `col0Name` TEXT, `col1Value` TEXT, `col2Differentiator` TEXT, `col3Amount` TEXT, `col4Plus` TEXT NOT NULL, FOREIGN KEY(`pkEvent`) REFERENCES `EventEntity`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "pk",
"columnName": "pk",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "pkEvent",
"columnName": "pkEvent",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "position",
"columnName": "position",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "col0Name",
"columnName": "col0Name",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "col1Value",
"columnName": "col1Value",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "col2Differentiator",
"columnName": "col2Differentiator",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "col3Amount",
"columnName": "col3Amount",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "col4Plus",
"columnName": "col4Plus",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": true,
"columnNames": [
"pk"
]
},
"indices": [
{
"name": "tags_by_pk_event",
"unique": false,
"columnNames": [
"pkEvent"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `tags_by_pk_event` ON `${TABLE_NAME}` (`pkEvent`)"
},
{
"name": "tags_by_tags_on_person_or_events",
"unique": false,
"columnNames": [
"col0Name",
"col1Value"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `tags_by_tags_on_person_or_events` ON `${TABLE_NAME}` (`col0Name`, `col1Value`)"
}
],
"foreignKeys": [
{
"table": "EventEntity",
"onDelete": "CASCADE",
"onUpdate": "NO ACTION",
"columns": [
"pkEvent"
],
"referencedColumns": [
"id"
]
}
]
}
],
"views": [],
"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, 'bf90c485bbfb3751761eb581ab24cf07')"
]
}
}
58 changes: 58 additions & 0 deletions app/src/main/java/com/greenart7c3/citrine/Citrine.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,27 @@ package com.greenart7c3.citrine
import android.app.Application
import android.content.ContentResolver
import android.util.Log
import com.greenart7c3.citrine.database.AppDatabase
import com.greenart7c3.citrine.server.OlderThan
import com.greenart7c3.citrine.server.Settings
import com.greenart7c3.citrine.service.LocalPreferences
import com.vitorpamplona.ammolite.relays.Relay
import com.vitorpamplona.quartz.events.Event
import com.vitorpamplona.quartz.events.EventInterface
import com.vitorpamplona.quartz.utils.TimeUtils
import kotlin.coroutines.cancellation.CancellationException
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.cancelChildren
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch

class Citrine : Application() {
val applicationScope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
var isImportingEvents = false
var job: Job? = null

override fun onCreate() {
super.onCreate()
Expand All @@ -23,6 +34,53 @@ class Citrine : Application() {

fun contentResolverFn(): ContentResolver = contentResolver

fun cancelJob() {
job?.cancelChildren(null)
job?.cancel(null)
}

suspend fun eventsToDelete(database: AppDatabase) {
if (isImportingEvents) return

job?.cancel()
job = applicationScope.launch(Dispatchers.IO) {
try {
if (Settings.deleteEphemeralEvents && isActive) {
Log.d(Citrine.TAG, "Deleting ephemeral events")
database.eventDao().deleteEphemeralEvents()
}

if (Settings.deleteExpiredEvents && isActive) {
Log.d(Citrine.TAG, "Deleting expired events")
database.eventDao().deleteEventsWithExpirations(TimeUtils.now())
}

if (Settings.deleteEventsOlderThan != OlderThan.NEVER && isActive) {
val until = when (Settings.deleteEventsOlderThan) {
OlderThan.DAY -> TimeUtils.oneDayAgo()
OlderThan.WEEK -> TimeUtils.oneWeekAgo()
OlderThan.MONTH -> TimeUtils.now() - TimeUtils.ONE_MONTH
OlderThan.YEAR -> TimeUtils.now() - TimeUtils.ONE_YEAR
else -> 0
}
if (until > 0) {
Log.d(Citrine.TAG, "Deleting old events (older than ${Settings.deleteEventsOlderThan})")
if (Settings.neverDeleteFrom.isNotEmpty()) {
val pubKeys = Settings.neverDeleteFrom.joinToString(separator = ",") { "'$it'" }
database.eventDao().deleteAll(until, pubKeys)
} else {
database.eventDao().deleteAll(until)
}
}
}
} catch (e: Exception) {
if (e is CancellationException) throw e
Log.e(Citrine.TAG, "Error deleting events", e)
}
}
job?.join()
}

companion object {
const val TAG = "Citrine"

Expand Down
15 changes: 13 additions & 2 deletions app/src/main/java/com/greenart7c3/citrine/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -307,9 +307,20 @@ class MainActivity : ComponentActivity() {
TextButton(
onClick = {
deleteAllDialog = false
coroutineScope.launch(Dispatchers.IO) {
Citrine.getInstance().applicationScope.launch(Dispatchers.IO) {
homeViewModel.setLoading(true)
database.eventDao().deleteAll()
Citrine.getInstance().job?.join()
Citrine.getInstance().isImportingEvents = true
homeViewModel.setProgress("Calculating database size")
val ids = database.eventDao().getAllIds()
val size = ids.size
val batchSize = 500
ids.chunked(batchSize).forEachIndexed { index, chunk ->
homeViewModel.setProgress("Deleting ${index * batchSize}/$size")
database.eventDao().delete(chunk)
}

Citrine.getInstance().isImportingEvents = false
homeViewModel.setLoading(false)
}
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,14 @@ import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
import androidx.room.TypeConverters
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
import com.greenart7c3.citrine.BuildConfig
import com.greenart7c3.citrine.Citrine

@Database(
entities = [EventEntity::class, TagEntity::class],
version = 1,
version = 2,
)
@TypeConverters(Converters::class)
abstract class AppDatabase : RoomDatabase() {
Expand All @@ -29,6 +31,7 @@ abstract class AppDatabase : RoomDatabase() {
"citrine_database",
)
// .setQueryCallback(AppDatabaseCallback(), Executors.newSingleThreadExecutor())
.addMigrations(MIGRATION_1_2)
.build()

database = instance
Expand All @@ -38,6 +41,12 @@ abstract class AppDatabase : RoomDatabase() {
}
}

val MIGRATION_1_2 = object : Migration(1, 2) {
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL("CREATE INDEX IF NOT EXISTS `most_common_search_is_kind` ON `EventEntity` (`kind` ASC)")
}
}

class AppDatabaseCallback : RoomDatabase.QueryCallback {
override fun onQuery(sqlQuery: String, bindArgs: List<Any?>) {
if (BuildConfig.DEBUG) {
Expand Down
Loading

0 comments on commit 31c208b

Please sign in to comment.