Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Opt/multi database #5124

Open
wants to merge 59 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
db31301
Migration database
SeniorZhai Nov 26, 2024
da2db30
Support db backup
SeniorZhai Nov 26, 2024
7614283
Update
SeniorZhai Nov 27, 2024
472cbab
Merge branch 'master' into opt/multi_database
SeniorZhai Nov 27, 2024
948d441
Refactor: optimize dependency injection and ViewModel architecture
SeniorZhai Nov 27, 2024
162b795
Job inject
SeniorZhai Nov 27, 2024
0abe2f3
Update dependency injection and transient field management
SeniorZhai Nov 27, 2024
707b45f
Injector
SeniorZhai Nov 28, 2024
43505d5
Merge commit 'df0b32e68b2ef3f8852c4b60c7d5b3cf8dd8d07d' into opt/mult…
SeniorZhai Nov 28, 2024
15cdc70
Check db status
SeniorZhai Nov 28, 2024
c83d4ce
Merge commit '020dda310f17f201fe14dd38b5d1196dbf528891' into opt/mult…
SeniorZhai Nov 29, 2024
461fdcb
Fix move target
SeniorZhai Nov 29, 2024
9e72817
Fix db migration
SeniorZhai Nov 29, 2024
51ef7ed
Remove transaction on DAO extension
SeniorZhai Nov 29, 2024
b5701f5
Move old database files at login
SeniorZhai Nov 29, 2024
1aabc24
Refactor ChatWebSocket to use DatabaseProvider directly
SeniorZhai Nov 29, 2024
e1218e5
More inject
SeniorZhai Nov 29, 2024
8562f32
Fix init db
SeniorZhai Nov 29, 2024
cfff174
Inject web socket
SeniorZhai Nov 29, 2024
a09ba34
Merge remote-tracking branch 'origin/master' into opt/multi_database
SeniorZhai Dec 2, 2024
b8803cb
Inject signal
SeniorZhai Dec 2, 2024
29544ec
Inject Hedwig
SeniorZhai Dec 2, 2024
fd9a2b0
Fix job inject
SeniorZhai Dec 3, 2024
f460dd6
Update backup
SeniorZhai Dec 3, 2024
257d384
Fix error data
SeniorZhai Dec 3, 2024
32c6017
Merge remote-tracking branch 'origin/master' into opt/multi_database
SeniorZhai Dec 3, 2024
92ffe5f
Update
SeniorZhai Dec 3, 2024
7b7a9a7
Update save user
SeniorZhai Dec 3, 2024
17f92c5
Merge branch 'opt/deactivation' into opt/multi_database
SeniorZhai Dec 4, 2024
be49f08
Remove test code
SeniorZhai Dec 4, 2024
673fbd6
Merge remote-tracking branch 'origin/master' into opt/multi_database
SeniorZhai Dec 9, 2024
43dcafb
Merge branch 'master' into opt/multi_database
SeniorZhai Dec 10, 2024
edc5161
Merge branch 'master' into opt/multi_database
SeniorZhai Dec 12, 2024
ed07d68
Merge commit '33e7a20b092ea3081108a3c5ee1eb91b512d0a3a' into opt/mult…
SeniorZhai Dec 12, 2024
2cd571d
Update database init
SeniorZhai Dec 12, 2024
28be4e6
Merge remote-tracking branch 'origin/master' into opt/multi_database
SeniorZhai Dec 12, 2024
5bda84d
Fix database init
SeniorZhai Dec 12, 2024
25a7ed3
Check state
SeniorZhai Dec 13, 2024
98d50a6
Force init
SeniorZhai Dec 14, 2024
efb7867
Merge remote-tracking branch 'origin/master' into opt/multi_database
SeniorZhai Dec 14, 2024
fb74f19
Search swap token
SeniorZhai Dec 16, 2024
dd84ad9
Filter result
SeniorZhai Dec 6, 2024
9d64ca8
Support chain filter
SeniorZhai Dec 17, 2024
76b5167
Fix select callback
SeniorZhai Dec 17, 2024
2efda26
Fix search return
SeniorZhai Dec 17, 2024
11b0cc9
Fix swap amount
SeniorZhai Dec 17, 2024
844f92a
Merge remote-tracking branch 'origin/master' into opt/multi_database
SeniorZhai Dec 17, 2024
0c47cc6
Swap base on quote result
Tougee Dec 17, 2024
fecf510
Fix to amount
Tougee Dec 17, 2024
34a4326
Fix fragment crash
Tougee Dec 17, 2024
0fd7d6e
Fix calculate rate
Tougee Dec 17, 2024
275a571
Merge branch 'opt/swap_search' into opt/multi_database
SeniorZhai Dec 17, 2024
0212f96
Update map and filter
SeniorZhai Dec 17, 2024
c3a2da6
Remove duplicates
SeniorZhai Dec 17, 2024
ef59423
Merge branch 'opt/swap_search' into opt/multi_database
SeniorZhai Dec 17, 2024
d16844f
Merge remote-tracking branch 'origin/master' into opt/multi_database
SeniorZhai Dec 18, 2024
50f980c
Update get database
SeniorZhai Dec 18, 2024
75a7196
Update
SeniorZhai Dec 23, 2024
b466a5a
Merge remote-tracking branch 'origin/master' into opt/multi_database
SeniorZhai Dec 23, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 7 additions & 21 deletions app/src/main/java/one/mixin/android/MixinApplication.kt
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import com.mapbox.maps.loader.MapboxMapsInitializer
import dagger.hilt.EntryPoint
import dagger.hilt.InstallIn
import dagger.hilt.android.EntryPointAccessors
import dagger.hilt.android.internal.managers.ApplicationComponentManager
import dagger.hilt.components.SingletonComponent
import io.reactivex.plugins.RxJavaPlugins
import io.sentry.SentryLevel
Expand All @@ -50,6 +51,7 @@ import one.mixin.android.crypto.MixinSignalProtocolLogger
import one.mixin.android.crypto.PrivacyPreference.clearPrivacyPreferences
import one.mixin.android.crypto.removeValueFromEncryptedPreferences
import one.mixin.android.crypto.db.SignalDatabase
import one.mixin.android.db.DatabaseProvider
import one.mixin.android.db.MixinDatabase
import one.mixin.android.di.AppModule.API_UA
import one.mixin.android.di.ApplicationScope
Expand Down Expand Up @@ -94,6 +96,7 @@ import java.util.concurrent.atomic.AtomicBoolean
import javax.inject.Inject
import kotlin.system.exitProcess

@SuppressLint("UnsafeOptInUsageError")
open class MixinApplication :
Application(),
Application.ActivityLifecycleCallbacks,
Expand All @@ -118,11 +121,9 @@ open class MixinApplication :
fun getHiltWorkerFactory(): HiltWorkerFactory
}

@InstallIn(SingletonComponent::class)
@EntryPoint
interface AppEntryPoint {
fun inject(app: MixinApplication)
}

@Inject
lateinit var databaseProvider: DatabaseProvider

private fun getWorkerFactory() = EntryPointAccessors.fromApplication(this, HiltWorkerFactoryEntryPoint::class.java).getHiltWorkerFactory()

Expand Down Expand Up @@ -317,26 +318,11 @@ open class MixinApplication :
applicationScope.launch {
clearData(sessionId)
withContext(Dispatchers.Main) {
val entryPoint =
EntryPointAccessors.fromApplication(
this@MixinApplication,
AppEntryPoint::class.java,
)
entryPoint.inject(this@MixinApplication)
LandingActivity.show(this@MixinApplication)
}
}
}
}

fun reject() {
MixinDatabase.destroy()
val entryPoint =
EntryPointAccessors.fromApplication(
this@MixinApplication,
AppEntryPoint::class.java,
)
entryPoint.inject(this@MixinApplication)
databaseProvider.closeAllDatabases()
}

private fun clearData(sessionId: String?) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import one.mixin.android.crypto.vo.RatchetSenderKey
import one.mixin.android.crypto.vo.SenderKey
import one.mixin.android.crypto.vo.Session
import one.mixin.android.crypto.vo.SignedPreKey
import one.mixin.android.db.MixinDatabase

@Database(
entities = [
Expand Down Expand Up @@ -67,4 +68,9 @@ abstract class SignalDatabase : RoomDatabase() {
object : RoomDatabase.Callback() {
}
}

override fun close() {
INSTANCE = null
super.close()
}
}
1 change: 0 additions & 1 deletion app/src/main/java/one/mixin/android/db/CircleDao.kt
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ interface CircleDao : BaseDao<Circle> {
}
}


@Query(
"""
SELECT c.* FROM circle_conversations cc
Expand Down
28 changes: 14 additions & 14 deletions app/src/main/java/one/mixin/android/db/DaoExtension.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package one.mixin.android.db

import androidx.room.Transaction
import kotlinx.coroutines.withContext
import one.mixin.android.db.flow.MessageFlow
import one.mixin.android.db.pending.PendingDatabase
Expand Down Expand Up @@ -31,26 +32,25 @@ fun JobDao.insertNoReplace(job: Job) {
}
}

@Transaction
suspend fun OutputDao.insertUnspentOutputs(outputs: List<Output>) =
withContext(SINGLE_DB_THREAD) {
runInTransaction {
val signed = findSignedOutput(outputs.map { it.outputId })
if (signed.isEmpty()) {
insertList(outputs)
} else {
Timber.e("Insert filter ${signed.joinToString(", ") }")
// Exclude signed data
val unsignedData = outputs.filterNot { signed.contains(it.outputId) }
insertList(unsignedData)
}
val signed = findSignedOutput(outputs.map { it.outputId })
if (signed.isEmpty()) {
insertList(outputs)
} else {
Timber.e("Insert filter ${signed.joinToString(", ")}")
// Exclude signed data
val unsignedData = outputs.filterNot { signed.contains(it.outputId) }
insertList(unsignedData)
}
}

// Delete SQL
fun MixinDatabase.deleteMessageById(messageId: String) {
runInTransaction {
pinMessageDao().deleteByMessageId(messageId)
mentionMessageDao().deleteMessage(messageId)
messageMentionDao().deleteMessage(messageId)
messageDao().deleteMessageById(messageId)
remoteMessageStatusDao().deleteByMessageId(messageId)
expiredMessageDao().deleteByMessageId(messageId)
Expand All @@ -63,7 +63,7 @@ fun MixinDatabase.deleteMessageById(
) {
runInTransaction {
pinMessageDao().deleteByMessageId(messageId)
mentionMessageDao().deleteMessage(messageId)
messageMentionDao().deleteMessage(messageId)
messageDao().deleteMessageById(messageId)
conversationExtDao().decrement(conversationId)
remoteMessageStatusDao().deleteByMessageId(messageId)
Expand All @@ -75,7 +75,7 @@ fun MixinDatabase.deleteMessageById(
fun MixinDatabase.deleteMessageByIds(messageIds: List<String>) {
runInTransaction {
pinMessageDao().deleteByIds(messageIds)
mentionMessageDao().deleteMessage(messageIds)
messageMentionDao().deleteMessage(messageIds)
messageDao().deleteMessageById(messageIds)
remoteMessageStatusDao().deleteByMessageIds(messageIds)
expiredMessageDao().deleteByMessageId(messageIds)
Expand Down Expand Up @@ -143,4 +143,4 @@ fun MixinDatabase.insertMessage(message: Message) {
messageDao().insert(message)
conversationExtDao().increment(message.conversationId)
conversationDao().updateLastMessageId(message.messageId, message.createdAt, message.conversationId)
}
}
80 changes: 80 additions & 0 deletions app/src/main/java/one/mixin/android/db/DatabaseProvider.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package one.mixin.android.db

import android.content.Context
import one.mixin.android.crypto.db.SignalDatabase
import one.mixin.android.fts.FtsDatabase
import one.mixin.android.db.pending.PendingDatabase
import one.mixin.android.db.pending.PendingDatabaseImp
import one.mixin.android.session.Session
import javax.inject.Inject

class DatabaseProvider @Inject constructor(
private val context: Context,
) {
private var mixinDatabase: MixinDatabase? = null
private var ftsDatabase: FtsDatabase? = null
private var pendingDatabase: PendingDatabaseImp? = null
private var identityNumber: String? = null

@Synchronized
fun getMixinDatabase(): MixinDatabase {
if (mixinDatabase == null) {
val db = MixinDatabase.getDatabase(context)
mixinDatabase = db
}
return mixinDatabase ?: throw IllegalStateException("MixinDatabase is not initialized")
}

@Synchronized
fun getFtsDatabase(): FtsDatabase {
if (ftsDatabase == null) {
val db = FtsDatabase.getDatabase(context)
ftsDatabase = db
}
return ftsDatabase ?: throw IllegalStateException("FtsDatabase is not initialized")
}

@Synchronized
fun getPendingDatabase(needCreate: Boolean = false): PendingDatabase {
if (pendingDatabase == null) {
val db = getMixinDatabase()
pendingDatabase = PendingDatabaseImp.getDatabase(context, db.floodMessageDao(), db.jobDao())
}
return pendingDatabase ?: throw IllegalStateException("PendingDatabase is not initialized")
}

@Synchronized
fun initAllDatabases() {
val identityNumber = requireNotNull(Session.getAccount()?.identityNumber)
if (identityNumber == this.identityNumber && isInit()) return

this.identityNumber = identityNumber

mixinDatabase?.close()
val db = MixinDatabase.getDatabase(context)
mixinDatabase = db

ftsDatabase?.close()
ftsDatabase = FtsDatabase.getDatabase(context)

pendingDatabase?.close()
pendingDatabase = PendingDatabaseImp.getDatabase(context, db.floodMessageDao(), db.jobDao())
}

@Synchronized
fun closeAllDatabases() {
mixinDatabase?.close()
mixinDatabase = null

ftsDatabase?.close()
ftsDatabase = null

pendingDatabase?.close()
pendingDatabase = null

identityNumber = null
}

@Synchronized
fun isInit() = mixinDatabase != null && ftsDatabase != null && pendingDatabase != null
}
7 changes: 7 additions & 0 deletions app/src/main/java/one/mixin/android/db/DepositDao.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package one.mixin.android.db

import androidx.room.Dao
import androidx.room.Query
import androidx.room.Transaction
import one.mixin.android.vo.safe.DepositEntry
import one.mixin.android.vo.safe.DestinationTag

Expand All @@ -15,4 +16,10 @@ interface DepositDao : BaseDao<DepositEntry> {

@Query("DELETE FROM deposit_entries WHERE chain_id=:chainId")
fun deleteByChainId(chainId: String)

@Transaction
fun deleteAndInsert(chainId: String, list: List<DepositEntry>) {
deleteByChainId(chainId)
insertList(list)
}
}
1 change: 1 addition & 0 deletions app/src/main/java/one/mixin/android/db/MarketCapRankDao.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package one.mixin.android.db
import androidx.room.Dao
import androidx.room.Query
import androidx.room.Transaction
import one.mixin.android.vo.market.Market
import one.mixin.android.vo.market.MarketCapRank

@Dao
Expand Down
39 changes: 21 additions & 18 deletions app/src/main/java/one/mixin/android/db/MixinDatabase.kt
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ import one.mixin.android.db.converter.WithdrawalMemoPossibilityConverter
import one.mixin.android.ui.wallet.alert.vo.Alert
import one.mixin.android.util.GsonHelper
import one.mixin.android.util.SINGLE_DB_EXECUTOR
import one.mixin.android.util.database.dbDir
import one.mixin.android.util.debug.getContent
import one.mixin.android.util.reportException
import one.mixin.android.vo.Address
Expand Down Expand Up @@ -127,6 +128,7 @@ import one.mixin.android.vo.safe.RawTransaction
import one.mixin.android.vo.safe.SafeSnapshot
import one.mixin.android.vo.safe.Token
import one.mixin.android.vo.safe.TokensExtra
import java.io.File
import java.util.concurrent.Executors
import kotlin.math.max
import kotlin.math.min
Expand Down Expand Up @@ -235,7 +237,7 @@ abstract class MixinDatabase : RoomDatabase() {

abstract fun favoriteAppDao(): FavoriteAppDao

abstract fun mentionMessageDao(): MessageMentionDao
abstract fun messageMentionDao(): MessageMentionDao

abstract fun circleDao(): CircleDao

Expand Down Expand Up @@ -277,23 +279,28 @@ abstract class MixinDatabase : RoomDatabase() {

abstract fun marketCapRankDao(): MarketCapRankDao

override fun close() {
INSTANCE = null
super.close()
}

companion object {
private var INSTANCE: MixinDatabase? = null

private val lock = Any()
private var supportSQLiteDatabase: SupportSQLiteDatabase? = null
private var NAME: String? = null

fun destroy() {
INSTANCE = null
fun getCurrentDbName(): String? {
return NAME
}

@Suppress("UNUSED_ANONYMOUS_PARAMETER")
@SuppressLint("RestrictedApi")
fun getDatabase(context: Context): MixinDatabase {
synchronized(lock) {
if (INSTANCE == null) {
val dir = dbDir(context)
NAME = dir.name
val builder =
Room.databaseBuilder(context, MixinDatabase::class.java, DB_NAME)
Room.databaseBuilder(context, MixinDatabase::class.java, File(dir, DB_NAME).absolutePath)
.openHelperFactory(
MixinOpenHelperFactory(
FrameworkSQLiteOpenHelperFactory(),
Expand Down Expand Up @@ -384,7 +391,6 @@ abstract class MixinDatabase : RoomDatabase() {
INSTANCE = builder.build()
}
return INSTANCE as MixinDatabase
}
}

fun query(query: String): String? {
Expand All @@ -411,7 +417,12 @@ abstract class MixinDatabase : RoomDatabase() {
}

fun checkPoint() {
supportSQLiteDatabase?.query("PRAGMA wal_checkpoint(FULL)")?.close()
supportSQLiteDatabase?.let { db ->
db.beginTransaction()
db.query("PRAGMA wal_checkpoint(FULL)")?.close()
db.setTransactionSuccessful()
db.endTransaction()
}
}

fun getWritableDatabase(): SupportSQLiteDatabase? {
Expand All @@ -431,12 +442,4 @@ abstract class MixinDatabase : RoomDatabase() {
}
}
}
}

fun runInTransaction(block: () -> Unit) {
MixinDatabase.getDatabase(MixinApplication.appContext).runInTransaction(block)
}

suspend fun withTransaction(block: suspend () -> Unit) {
MixinDatabase.getDatabase(MixinApplication.appContext).withTransaction(block)
}
}
1 change: 1 addition & 0 deletions app/src/main/java/one/mixin/android/db/StickerAlbumDao.kt
Original file line number Diff line number Diff line change
Expand Up @@ -67,4 +67,5 @@ interface StickerAlbumDao : BaseDao<StickerAlbum> {

@Query("SELECT max(ordered_at) FROM sticker_albums")
suspend fun findMaxOrder(): Int?

}
1 change: 0 additions & 1 deletion app/src/main/java/one/mixin/android/db/StickerDao.kt
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ interface StickerDao : BaseDao<Sticker> {
insert(s)
}


@Query("SELECT * FROM stickers WHERE last_use_at > 0 ORDER BY last_use_at DESC LIMIT 20")
fun recentUsedStickers(): LiveData<List<Sticker>>

Expand Down
Loading
Loading