mirror of
https://gitlab.com/ultrasonic/ultrasonic.git
synced 2026-10-22 23:42:14 +03:00
Own metadata databases by server ID
This commit is contained in:
1 parent
0a3d5b1c02
commit
dd95c554b7
3 files changed
+82
-37
No files matched your search
@@ -7,7 +7,6 @@
|
||||
|
||||
package org.moire.ultrasonic.data
|
||||
|
||||
import androidx.room.Room
|
||||
import kotlinx.coroutines.CompletableDeferred
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
@@ -40,8 +39,7 @@ import timber.log.Timber
|
||||
class ActiveServerProvider(private val repository: ServerSettingDao) :
|
||||
CoroutineScope by CoroutinePatterns.loggingScope(Dispatchers.IO) {
|
||||
|
||||
private var cachedDatabase: MetaDatabase? = null
|
||||
private var cachedServerId: Int? = null
|
||||
private val metadataDatabases = MetaDatabaseRegistry()
|
||||
|
||||
private val _accessState = MutableStateFlow(
|
||||
LibraryAccessState(Settings.activeServer, Settings.explicitOffline)
|
||||
@@ -308,45 +306,18 @@ class ActiveServerProvider(private val repository: ServerSettingDao) :
|
||||
* this rather than the effective, offline database.
|
||||
*/
|
||||
@Synchronized
|
||||
fun getSelectedMetaDatabase(): MetaDatabase {
|
||||
val selectedServer = getSelectedServerId()
|
||||
fun getSelectedMetaDatabase(): MetaDatabase = getMetaDatabaseForServer(getSelectedServerId())
|
||||
|
||||
if (selectedServer == cachedServerId && cachedDatabase != null) {
|
||||
return cachedDatabase!!
|
||||
}
|
||||
/** Metadata storage owned by a server, independent of the current UI selection. */
|
||||
@Synchronized
|
||||
fun getMetaDatabaseForServer(serverId: Int): MetaDatabase =
|
||||
metadataDatabases.forServer(serverId)
|
||||
|
||||
if (selectedServer < 1) {
|
||||
return offlineMetaDatabase
|
||||
}
|
||||
|
||||
Timber.i("Switching to new database, id:$selectedServer")
|
||||
cachedServerId = selectedServer
|
||||
cachedDatabase = initDatabase(selectedServer)
|
||||
|
||||
return cachedDatabase!!
|
||||
}
|
||||
|
||||
val offlineMetaDatabase: MetaDatabase by lazy {
|
||||
initDatabase(0)
|
||||
}
|
||||
|
||||
private fun initDatabase(serverId: Int): MetaDatabase = Room.databaseBuilder(
|
||||
UApp.applicationContext(),
|
||||
MetaDatabase::class.java,
|
||||
METADATA_DB + serverId
|
||||
)
|
||||
.addMigrations(META_MIGRATION_2_3, META_MIGRATION_3_4)
|
||||
.fallbackToDestructiveMigrationOnDowngrade(true)
|
||||
.build()
|
||||
val offlineMetaDatabase: MetaDatabase get() = metadataDatabases.forServer(0)
|
||||
|
||||
@Synchronized
|
||||
fun deleteMetaDatabase(id: Int) {
|
||||
if (cachedServerId == id) {
|
||||
cachedDatabase?.close()
|
||||
cachedDatabase = null
|
||||
cachedServerId = null
|
||||
}
|
||||
UApp.applicationContext().deleteDatabase(METADATA_DB + id)
|
||||
metadataDatabases.delete(id)
|
||||
Timber.i("Deleted metadataBase, id:$id")
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
package org.moire.ultrasonic.data
|
||||
|
||||
import androidx.room.Room
|
||||
import org.moire.ultrasonic.app.UApp
|
||||
import timber.log.Timber
|
||||
|
||||
/** Owns one Room handle per server for the lifetime of the application process. */
|
||||
internal class MetaDatabaseRegistry(
|
||||
private val open: (Int) -> MetaDatabase = { serverId ->
|
||||
Room.databaseBuilder(
|
||||
UApp.applicationContext(),
|
||||
MetaDatabase::class.java,
|
||||
ActiveServerProvider.METADATA_DB + serverId
|
||||
)
|
||||
.addMigrations(META_MIGRATION_2_3, META_MIGRATION_3_4)
|
||||
.fallbackToDestructiveMigrationOnDowngrade(true)
|
||||
.build()
|
||||
},
|
||||
private val deleteFile: (Int) -> Unit = { serverId ->
|
||||
UApp.applicationContext().deleteDatabase(ActiveServerProvider.METADATA_DB + serverId)
|
||||
}
|
||||
) {
|
||||
private val databases = mutableMapOf<Int, MetaDatabase>()
|
||||
|
||||
@Synchronized
|
||||
fun forServer(serverId: Int): MetaDatabase {
|
||||
val databaseId = serverId.coerceAtLeast(0)
|
||||
return databases.getOrPut(databaseId) {
|
||||
Timber.i("Opening metadata database, id:$databaseId")
|
||||
open(databaseId)
|
||||
}
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
fun delete(serverId: Int) {
|
||||
databases.remove(serverId)?.close()
|
||||
deleteFile(serverId)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package org.moire.ultrasonic.data
|
||||
|
||||
import org.amshove.kluent.shouldBeEqualTo
|
||||
import org.junit.Test
|
||||
import org.mockito.kotlin.mock
|
||||
import org.mockito.kotlin.verify
|
||||
|
||||
class MetaDatabaseRegistryTest {
|
||||
@Test
|
||||
fun `server switch reuses handles and deletion closes only its server`() {
|
||||
val first: MetaDatabase = mock()
|
||||
val second: MetaDatabase = mock()
|
||||
val opened = mutableListOf<Int>()
|
||||
val deleted = mutableListOf<Int>()
|
||||
val registry = MetaDatabaseRegistry(
|
||||
open = { id ->
|
||||
opened += id
|
||||
if (id == 1) first else second
|
||||
},
|
||||
deleteFile = { deleted += it }
|
||||
)
|
||||
|
||||
registry.forServer(1) shouldBeEqualTo first
|
||||
registry.forServer(2) shouldBeEqualTo second
|
||||
registry.forServer(1) shouldBeEqualTo first
|
||||
opened shouldBeEqualTo listOf(1, 2)
|
||||
|
||||
registry.delete(1)
|
||||
|
||||
verify(first).close()
|
||||
deleted shouldBeEqualTo listOf(1)
|
||||
registry.forServer(2) shouldBeEqualTo second
|
||||
opened shouldBeEqualTo listOf(1, 2)
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user