Other measurments against deadlocks

This commit is contained in:
Jonas Lochmann 2020-07-06 02:00:00 +02:00
parent 838006f40e
commit ae8509c8b8
No known key found for this signature in database
GPG key ID: 8B8C9AEE10FA5B36
5 changed files with 28 additions and 15 deletions

View file

@ -21,6 +21,7 @@ import androidx.room.Database
import androidx.room.InvalidationTracker import androidx.room.InvalidationTracker
import androidx.room.Room import androidx.room.Room
import androidx.room.RoomDatabase import androidx.room.RoomDatabase
import io.timelimit.android.async.Threads
import io.timelimit.android.data.dao.DerivedDataDao import io.timelimit.android.data.dao.DerivedDataDao
import io.timelimit.android.data.invalidation.Observer import io.timelimit.android.data.invalidation.Observer
import io.timelimit.android.data.invalidation.Table import io.timelimit.android.data.invalidation.Table
@ -28,6 +29,7 @@ import io.timelimit.android.data.invalidation.TableUtil
import io.timelimit.android.data.model.* import io.timelimit.android.data.model.*
import java.lang.ref.WeakReference import java.lang.ref.WeakReference
import java.util.concurrent.CountDownLatch import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit
@Database(entities = [ @Database(entities = [
User::class, User::class,
@ -113,6 +115,7 @@ abstract class RoomDatabase: RoomDatabase(), io.timelimit.android.data.Database
DatabaseMigrations.MIGRATE_TO_V30, DatabaseMigrations.MIGRATE_TO_V30,
DatabaseMigrations.MIGRATE_TO_V31 DatabaseMigrations.MIGRATE_TO_V31
) )
.setQueryExecutor(Threads.database)
.build() .build()
} }
} }
@ -157,21 +160,21 @@ abstract class RoomDatabase: RoomDatabase(), io.timelimit.android.data.Database
val latch = CountDownLatch(1) val latch = CountDownLatch(1)
try { try {
queryExecutor.execute { latch.await() } queryExecutor.execute { latch.await(5, TimeUnit.SECONDS) }
// without requesting a async refresh, no sync refresh will happen // without requesting a async refresh, no sync refresh will happen
invalidationTracker.refreshVersionsAsync() invalidationTracker.refreshVersionsAsync()
invalidationTracker.refreshVersionsSync() invalidationTracker.refreshVersionsSync()
openHelper.readableDatabase.beginTransaction()
try {
synchronized(transactionCommitListeners) { transactionCommitListeners.toList() }.forEach { it() }
} finally {
openHelper.readableDatabase.endTransaction()
}
} finally { } finally {
latch.countDown() latch.countDown()
} }
openHelper.readableDatabase.beginTransaction()
try {
synchronized(transactionCommitListeners) { transactionCommitListeners.toList() }.forEach { it() }
} finally {
openHelper.readableDatabase.endTransaction()
}
} }
} }

View file

@ -1,5 +1,5 @@
/* /*
* TimeLimit Copyright <C> 2019 Jonas Lochmann * TimeLimit Copyright <C> 2019 - 2020 Jonas Lochmann
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -19,6 +19,7 @@ import android.content.Context
import android.util.Log import android.util.Log
import androidx.core.util.AtomicFile import androidx.core.util.AtomicFile
import io.timelimit.android.BuildConfig import io.timelimit.android.BuildConfig
import io.timelimit.android.async.Threads
import io.timelimit.android.coroutines.executeAndWait import io.timelimit.android.coroutines.executeAndWait
import io.timelimit.android.data.RoomDatabase import io.timelimit.android.data.RoomDatabase
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
@ -81,8 +82,9 @@ class DatabaseBackup(private val context: Context) {
try { try {
jsonFile.openRead().use { inputStream -> jsonFile.openRead().use { inputStream ->
Threads.database.executeAndWait {
DatabaseBackupLowlevel.restoreFromBackupJson(database, inputStream) DatabaseBackupLowlevel.restoreFromBackupJson(database, inputStream)
}
} }
if (BuildConfig.DEBUG) { if (BuildConfig.DEBUG) {

View file

@ -43,7 +43,9 @@ fun <K, V> DataCacheUserInterface<K, V>.openLive(key: K, executor: Executor): Li
override fun onInactive() { override fun onInactive() {
super.onInactive() super.onInactive()
cache.close(key, listener) executor.execute {
cache.close(key, listener)
}
} }
} }
} }

View file

@ -43,7 +43,9 @@ fun <V> SingleItemDataCacheUserInterface<V>.openLive(executor: Executor): LiveDa
override fun onInactive() { override fun onInactive() {
super.onInactive() super.onInactive()
cache.close(listener) executor.execute {
cache.close(listener)
}
} }
} }
} }

View file

@ -41,6 +41,8 @@ class SuspendAppsLogic(private val appLogic: AppLogic): Observer {
private val pendingSync = AtomicBoolean(true) private val pendingSync = AtomicBoolean(true)
private val executor = Executors.newSingleThreadExecutor() private val executor = Executors.newSingleThreadExecutor()
private var lastSuspendedApps: List<String>? = null private var lastSuspendedApps: List<String>? = null
private val userAndDeviceRelatedDataLive = appLogic.database.derivedDataDao().getUserAndDeviceRelatedDataLive()
private var didLoadUserAndDeviceRelatedData = false
private val backgroundRunnable = Runnable { private val backgroundRunnable = Runnable {
while (pendingSync.getAndSet(false)) { while (pendingSync.getAndSet(false)) {
@ -67,7 +69,7 @@ class SuspendAppsLogic(private val appLogic: AppLogic): Observer {
appLogic.database.registerWeakObserver(arrayOf(Table.App), WeakReference(this)) appLogic.database.registerWeakObserver(arrayOf(Table.App), WeakReference(this))
appLogic.platformIntegration.getBatteryStatusLive().observeForever { batteryStatus = it; triggerUpdate() } appLogic.platformIntegration.getBatteryStatusLive().observeForever { batteryStatus = it; triggerUpdate() }
appLogic.realTimeLogic.registerTimeModificationListener { triggerUpdate() } appLogic.realTimeLogic.registerTimeModificationListener { triggerUpdate() }
appLogic.database.derivedDataDao().getUserAndDeviceRelatedDataLive().observeForever { triggerUpdate() } userAndDeviceRelatedDataLive.observeForever { didLoadUserAndDeviceRelatedData = true; triggerUpdate() }
} }
override fun onInvalidated(tables: Set<Table>) { override fun onInvalidated(tables: Set<Table>) {
@ -75,7 +77,9 @@ class SuspendAppsLogic(private val appLogic: AppLogic): Observer {
} }
private fun updateBlockingSync() { private fun updateBlockingSync() {
val userAndDeviceRelatedData = appLogic.database.derivedDataDao().getUserAndDeviceRelatedDataSync() if (!didLoadUserAndDeviceRelatedData) return
val userAndDeviceRelatedData = userAndDeviceRelatedDataLive.value
val isRestrictedUser = userAndDeviceRelatedData?.userRelatedData?.user?.type == UserType.Child val isRestrictedUser = userAndDeviceRelatedData?.userRelatedData?.user?.type == UserType.Child
val enableBlockingAtSystemLevel = userAndDeviceRelatedData?.deviceRelatedData?.isExperimentalFlagSetSync(ExperimentalFlags.SYSTEM_LEVEL_BLOCKING) ?: false val enableBlockingAtSystemLevel = userAndDeviceRelatedData?.deviceRelatedData?.isExperimentalFlagSetSync(ExperimentalFlags.SYSTEM_LEVEL_BLOCKING) ?: false