Revert "Run more db queries inside the IO pool, convert some RxJava references to Coroutines"

This reverts commit 18f02a85ac3b21b5ce91b81a6a6b97c7585d7088.

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsEhController.kt
This commit is contained in:
Jobobby04 2021-01-26 23:36:03 -05:00
parent 628eedf15a
commit dc6aa11bc7
8 changed files with 45 additions and 74 deletions

View File

@ -51,7 +51,7 @@ class MdList(private val context: Context, id: Int) : TrackService(id) {
override suspend fun update(track: Track): Track {
val mdex = mdex ?: throw Exception("Mangadex not enabled")
val mangaMetadata = db.getFlatMetadataForManga(track.manga_id).executeOnIO()
val mangaMetadata = db.getFlatMetadataForManga(track.manga_id).executeAsBlocking()
?.raise<MangaDexSearchMetadata>()
?: throw Exception("Invalid manga metadata")
val followStatus = FollowStatus.fromInt(track.status)

View File

@ -20,7 +20,6 @@ import exh.search.SearchEngine
import exh.search.Text
import exh.source.isMetadataSource
import exh.util.cancellable
import exh.util.executeOnIO
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
@ -116,7 +115,7 @@ class LibraryCategoryAdapter(view: LibraryCategoryView, val controller: LibraryC
// Prepare filter object
val parsedQuery = searchEngine.parseQuery(savedSearchText)
val mangaWithMetaIdsQuery = db.getIdsOfFavoriteMangaWithMetadata().executeOnIO()
val mangaWithMetaIdsQuery = db.getIdsOfFavoriteMangaWithMetadata().executeAsBlocking()
val mangaWithMetaIds = LongArray(mangaWithMetaIdsQuery.count)
if (mangaWithMetaIds.isNotEmpty()) {
val mangaIdCol = mangaWithMetaIdsQuery.getColumnIndex(MangaTable.COL_ID)
@ -139,8 +138,8 @@ class LibraryCategoryAdapter(view: LibraryCategoryView, val controller: LibraryC
// No meta? Filter using title
filterManga(parsedQuery, item.manga)
} else {
val tags = db.getSearchTagsForManga(mangaId).executeOnIO()
val titles = db.getSearchTitlesForManga(mangaId).executeOnIO()
val tags = db.getSearchTagsForManga(mangaId).executeAsBlocking()
val titles = db.getSearchTitlesForManga(mangaId).executeAsBlocking()
filterManga(parsedQuery, item.manga, false, tags, titles)
}
} else {
@ -168,7 +167,7 @@ class LibraryCategoryAdapter(view: LibraryCategoryView, val controller: LibraryC
private suspend fun filterManga(queries: List<QueryComponent>, manga: LibraryManga, checkGenre: Boolean = true, searchTags: List<SearchTag>? = null, searchTitles: List<SearchTitle>? = null): Boolean {
val mappedQueries = queries.groupBy { it.excluded }
val tracks = if (hasLoggedServices) db.getTracks(manga).executeOnIO() else null
val tracks = if (hasLoggedServices) db.getTracks(manga).executeAsBlocking().toList() else null
val source = sourceManager.get(manga.source)
val genre = if (checkGenre) manga.getGenres().orEmpty() else emptyList()
val hasNormalQuery = mappedQueries[false]?.all { queryComponent ->

View File

@ -643,7 +643,7 @@ class SettingsEhController : SettingsController() {
val allMeta = db.getFavoriteMangaWithMetadata().executeAsBlocking()
.filter(Manga::isEhBasedManga)
.mapNotNull {
db.getFlatMetadataForManga(it.id!!).executeOnIO()
db.getFlatMetadataForManga(it.id!!).executeAsBlocking()
?.raise<EHentaiSearchMetadata>()
}.toList()

View File

@ -60,7 +60,7 @@ object DebugFunctions {
}.toList()
allManga.forEach { manga ->
val meta = db.getFlatMetadataForManga(manga.id!!).executeOnIO()?.raise<EHentaiSearchMetadata>() ?: return@forEach
val meta = db.getFlatMetadataForManga(manga.id!!).executeAsBlocking()?.raise<EHentaiSearchMetadata>() ?: return@forEach
// remove age flag
meta.aged = false
db.insertFlatMetadataAsync(meta.flatten()).await()
@ -94,7 +94,7 @@ object DebugFunctions {
)?.getMangaDetails(manga.toMangaInfo())?.let { networkManga ->
manga.copyFrom(networkManga.toSManga())
manga.initialized = true
db.insertManga(manga).executeOnIO()
db.insertManga(manga).executeAsBlocking()
}
}
}
@ -111,7 +111,7 @@ object DebugFunctions {
}.toList()
allManga.forEach { manga ->
val meta = db.getFlatMetadataForManga(manga.id!!).executeOnIO()?.raise<EHentaiSearchMetadata>() ?: return@forEach
val meta = db.getFlatMetadataForManga(manga.id!!).executeAsBlocking()?.raise<EHentaiSearchMetadata>() ?: return@forEach
galleries += "Aged: ${meta.aged}\t Title: ${manga.title}"
}
}
@ -121,7 +121,7 @@ object DebugFunctions {
fun countAgedFlagInEXHManga(): Int {
var agedAmount = 0
runBlocking {
val metadataManga = db.getFavoriteMangaWithMetadata().executeOnIO()
val metadataManga = db.getFavoriteMangaWithMetadata().executeAsBlocking()
val allManga = metadataManga.asFlow().cancellable().mapNotNull { manga ->
if (manga.isEhBasedManga()) manga
@ -129,7 +129,7 @@ object DebugFunctions {
}.toList()
allManga.forEach { manga ->
val meta = db.getFlatMetadataForManga(manga.id!!).executeOnIO()?.raise<EHentaiSearchMetadata>() ?: return@forEach
val meta = db.getFlatMetadataForManga(manga.id!!).executeAsBlocking()?.raise<EHentaiSearchMetadata>() ?: return@forEach
if (meta.aged) {
// remove age flag
agedAmount++
@ -200,7 +200,7 @@ object DebugFunctions {
EHentaiUpdateWorker.scheduleBackground(app)
}
fun listScheduledJobs() = app.jobScheduler.allPendingJobs.joinToString(",\n") { j ->
fun listScheduledJobs() = app.jobScheduler.allPendingJobs.map { j ->
"""
{
info: ${j.id},
@ -209,7 +209,7 @@ object DebugFunctions {
intervalMillis: ${j.intervalMillis},
}
""".trimIndent()
}
}.joinToString(",\n")
fun cancelAllScheduledJobs() = app.jobScheduler.cancelAll()

View File

@ -7,7 +7,6 @@ import android.app.job.JobService
import android.content.ComponentName
import android.content.Context
import android.os.Build
import com.elvishew.xlog.Logger
import com.elvishew.xlog.XLog
import eu.kanade.tachiyomi.data.database.DatabaseHelper
import eu.kanade.tachiyomi.data.database.models.Chapter
@ -45,18 +44,20 @@ import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
import uy.kohesive.injekt.injectLazy
import java.util.ArrayList
import kotlin.coroutines.CoroutineContext
import kotlin.time.ExperimentalTime
import kotlin.time.days
import kotlin.time.hours
class EHentaiUpdateWorker : JobService() {
private val scope = CoroutineScope(Dispatchers.Default + Job())
class EHentaiUpdateWorker : JobService(), CoroutineScope {
override val coroutineContext: CoroutineContext
get() = Dispatchers.Default + Job()
private val db: DatabaseHelper by injectLazy()
private val prefs: PreferencesHelper by injectLazy()
private val sourceManager: SourceManager by injectLazy()
private val updateHelper: EHentaiUpdateHelper by injectLazy()
private val logger: Logger = XLog.tag("EHUpdater").build()
private val logger = XLog.tag("EHUpdater")
private val updateNotifier by lazy { LibraryUpdateNotifier(this) }
@ -84,7 +85,7 @@ class EHentaiUpdateWorker : JobService() {
* to end the job entirely. Regardless of the value returned, your job must stop executing.
*/
override fun onStopJob(params: JobParameters?): Boolean {
runBlocking { scope.coroutineContext[Job]?.cancelAndJoin() }
runBlocking { this@EHentaiUpdateWorker.coroutineContext[Job]?.cancelAndJoin() }
return false
}
@ -120,7 +121,7 @@ class EHentaiUpdateWorker : JobService() {
* extras configured with [ This object serves to identify this specific running job instance when calling][JobInfo.Builder.setExtras]
*/
override fun onStartJob(params: JobParameters): Boolean {
scope.launch {
launch {
startUpdating()
logger.d("Update job completed!")
jobFinished(params, false)
@ -143,7 +144,7 @@ class EHentaiUpdateWorker : JobService() {
return@mapNotNull null
}
val meta = db.getFlatMetadataForManga(manga.id!!).executeOnIO()
val meta = db.getFlatMetadataForManga(manga.id!!).executeAsBlocking()
?: return@mapNotNull null
val raisedMeta = meta.raise<EHentaiSearchMetadata>()
@ -272,7 +273,7 @@ class EHentaiUpdateWorker : JobService() {
return new to db.getChapters(manga).executeOnIO()
} catch (t: Throwable) {
if (t is EHentai.GalleryNotFoundException) {
val meta = db.getFlatMetadataForManga(manga.id!!).executeOnIO()?.raise<EHentaiSearchMetadata>()
val meta = db.getFlatMetadataForManga(manga.id!!).executeAsBlocking()?.raise<EHentaiSearchMetadata>()
if (meta != null) {
// Age dead galleries
logger.d("Aged %s - notfound", manga.id)
@ -343,7 +344,8 @@ class EHentaiUpdateWorker : JobService() {
}
fun launchBackgroundTest(context: Context): String {
return if (context.jobScheduler.schedule(context.testBackgroundJobInfo()) == JobScheduler.RESULT_FAILURE) {
val jobScheduler = context.jobScheduler
return if (jobScheduler.schedule(context.testBackgroundJobInfo()) == JobScheduler.RESULT_FAILURE) {
logger.e("Failed to schedule background test job!")
"Failed"
} else {

View File

@ -2,8 +2,6 @@ package exh.metadata.metadata.base
import com.pushtorefresh.storio.operations.PreparedOperation
import eu.kanade.tachiyomi.data.database.DatabaseHelper
import eu.kanade.tachiyomi.util.lang.runAsObservable
import eu.kanade.tachiyomi.util.lang.withIOContext
import exh.metadata.sql.models.SearchMetadata
import exh.metadata.sql.models.SearchTag
import exh.metadata.sql.models.SearchTitle
@ -11,9 +9,6 @@ import exh.util.executeOnIO
import kotlinx.coroutines.Deferred
import kotlinx.coroutines.async
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.runBlocking
import kotlinx.serialization.InternalSerializationApi
import kotlinx.serialization.Serializable
import kotlinx.serialization.serializer
@ -37,35 +32,23 @@ data class FlatMetadata(
}
}
interface PreparedSuspendOperation<T> : PreparedOperation<T> {
/**
* Creates a [Flow] that emits the result of of Operation
*
* Example:
* override fun asFlow(): Flow<T> = flow { emit(operation()) }
*
*/
fun asFlow(): Flow<T>
/**
* Executes operation asynchronously in the I/O thread pool.
*/
suspend fun executeOnIO(): T
}
fun DatabaseHelper.getFlatMetadataForManga(mangaId: Long): PreparedSuspendOperation<FlatMetadata?> =
preparedOperationFromSuspend {
val meta = getSearchMetadataForManga(mangaId).executeOnIO()
fun DatabaseHelper.getFlatMetadataForManga(mangaId: Long): PreparedOperation<FlatMetadata?> {
// We have to use fromCallable because StorIO messes up the thread scheduling if we use their rx functions
val single = Single.fromCallable {
val meta = getSearchMetadataForManga(mangaId).executeAsBlocking()
if (meta != null) {
val tags = getSearchTagsForManga(mangaId).executeOnIO()
val titles = getSearchTitlesForManga(mangaId).executeOnIO()
val tags = getSearchTagsForManga(mangaId).executeAsBlocking()
val titles = getSearchTitlesForManga(mangaId).executeAsBlocking()
FlatMetadata(meta, tags, titles)
} else null
}
private fun <T> preparedOperationFromSuspend(operation: suspend () -> T): PreparedSuspendOperation<T> {
return object : PreparedSuspendOperation<T> {
return preparedOperationFromSingle(single)
}
private fun <T> preparedOperationFromSingle(single: Single<T>): PreparedOperation<T> {
return object : PreparedOperation<T> {
/**
* Creates [rx.Observable] that emits result of Operation.
*
@ -74,7 +57,7 @@ private fun <T> preparedOperationFromSuspend(operation: suspend () -> T): Prepar
*
* @return observable result of operation with only one [rx.Observer.onNext] call.
*/
override fun createObservable() = runAsObservable(operation)
override fun createObservable() = single.toObservable()
/**
* Executes operation synchronously in current thread.
@ -83,11 +66,11 @@ private fun <T> preparedOperationFromSuspend(operation: suspend () -> T): Prepar
* Notice: Blocking I/O operation should not be executed on the Main Thread,
* it can cause ANR (Activity Not Responding dialog), block the UI and drop animations frames.
* So please, execute blocking I/O operation only from background thread.
* See [androidx.annotation.WorkerThread].
* See [WorkerThread].
*
* @return nullable result of operation.
*/
override fun executeAsBlocking() = runBlocking { operation() }
override fun executeAsBlocking() = single.toBlocking().value()
/**
* Creates [rx.Observable] that emits result of Operation.
@ -97,7 +80,7 @@ private fun <T> preparedOperationFromSuspend(operation: suspend () -> T): Prepar
*
* @return observable result of operation with only one [rx.Observer.onNext] call.
*/
override fun asRxObservable() = runAsObservable(operation)
override fun asRxObservable() = single.toObservable()
/**
* Creates [rx.Single] that emits result of Operation lazily when somebody subscribes to it.
@ -106,21 +89,7 @@ private fun <T> preparedOperationFromSuspend(operation: suspend () -> T): Prepar
*
* @return single result of operation.
*/
override fun asRxSingle(): Single<T> = runAsObservable(operation).toSingle()
/**
* Creates a [Flow] that emits the result of of Operation
*
* Example:
* override fun asFlow(): Flow<T> = flow { emit(operation()) }
*
*/
override fun asFlow(): Flow<T> = flow { emit(operation()) }
/**
* Executes operation asynchronously in the I/O thread pool.
*/
override suspend fun executeOnIO(): T = withIOContext { operation() }
override fun asRxSingle() = single
}
}

View File

@ -6,6 +6,7 @@ import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.source.Source
import eu.kanade.tachiyomi.source.online.MetadataSource
import eu.kanade.tachiyomi.util.lang.asFlow
import exh.metadata.metadata.base.FlatMetadata
import exh.metadata.metadata.base.RaisedSearchMetadata
import exh.metadata.metadata.base.getFlatMetadataForManga
@ -15,6 +16,7 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.plus
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
@ -48,6 +50,6 @@ class MetadataViewPresenter(
}
private fun getMangaMetaObservable(): Flow<FlatMetadata?> {
return db.getFlatMetadataForManga(manga.id!!).asFlow()
return db.getFlatMetadataForManga(manga.id!!).asRxObservable().asFlow()
}
}

View File

@ -1,7 +1,6 @@
package exh.util
import android.database.Cursor
import com.pushtorefresh.storio.sqlite.operations.get.PreparedGetCursor
import com.pushtorefresh.storio.operations.PreparedOperation
import com.pushtorefresh.storio.sqlite.operations.get.PreparedGetListOfObjects
import com.pushtorefresh.storio.sqlite.operations.get.PreparedGetObject
import com.pushtorefresh.storio.sqlite.operations.put.PreparedPutCollectionOfObjects
@ -19,4 +18,4 @@ suspend fun <T> PreparedPutObject<T>.executeOnIO(): PutResult = withContext(Disp
suspend fun <T> PreparedPutCollectionOfObjects<T>.executeOnIO(): PutResults<T> = withContext(Dispatchers.IO) { executeAsBlocking() }
suspend fun PreparedGetCursor.executeOnIO(): Cursor = withContext(Dispatchers.IO) { executeAsBlocking() }
suspend fun <T> PreparedOperation<T>.executeOnIO(): T? = withContext(Dispatchers.IO) { executeAsBlocking() }