From dc6aa11bc726088c5588cd67a24d32bdfc0d14bc Mon Sep 17 00:00:00 2001 From: Jobobby04 Date: Tue, 26 Jan 2021 23:36:03 -0500 Subject: [PATCH] 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 --- .../tachiyomi/data/track/mdlist/MdList.kt | 2 +- .../ui/library/LibraryCategoryAdapter.kt | 9 ++- .../ui/setting/SettingsEhController.kt | 2 +- app/src/main/java/exh/debug/DebugFunctions.kt | 14 ++--- .../main/java/exh/eh/EHentaiUpdateWorker.kt | 20 +++--- .../metadata/metadata/base/FlatMetadata.kt | 63 +++++-------------- .../exh/ui/metadata/MetadataViewPresenter.kt | 4 +- .../main/java/exh/util/DatabaseExtensions.kt | 5 +- 8 files changed, 45 insertions(+), 74 deletions(-) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/mdlist/MdList.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/mdlist/MdList.kt index 9c8f8d7f6..e1507b067 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/mdlist/MdList.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/mdlist/MdList.kt @@ -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() ?: throw Exception("Invalid manga metadata") val followStatus = FollowStatus.fromInt(track.status) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryCategoryAdapter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryCategoryAdapter.kt index 1e3215c49..1118f7748 100755 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryCategoryAdapter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryCategoryAdapter.kt @@ -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, manga: LibraryManga, checkGenre: Boolean = true, searchTags: List? = null, searchTitles: List? = 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 -> diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsEhController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsEhController.kt index 61f8a98f7..71bdd407a 100755 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsEhController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsEhController.kt @@ -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() }.toList() diff --git a/app/src/main/java/exh/debug/DebugFunctions.kt b/app/src/main/java/exh/debug/DebugFunctions.kt index b1f512a90..bc240a14c 100644 --- a/app/src/main/java/exh/debug/DebugFunctions.kt +++ b/app/src/main/java/exh/debug/DebugFunctions.kt @@ -60,7 +60,7 @@ object DebugFunctions { }.toList() allManga.forEach { manga -> - val meta = db.getFlatMetadataForManga(manga.id!!).executeOnIO()?.raise() ?: return@forEach + val meta = db.getFlatMetadataForManga(manga.id!!).executeAsBlocking()?.raise() ?: 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() ?: return@forEach + val meta = db.getFlatMetadataForManga(manga.id!!).executeAsBlocking()?.raise() ?: 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() ?: return@forEach + val meta = db.getFlatMetadataForManga(manga.id!!).executeAsBlocking()?.raise() ?: 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() diff --git a/app/src/main/java/exh/eh/EHentaiUpdateWorker.kt b/app/src/main/java/exh/eh/EHentaiUpdateWorker.kt index b258d7dec..a8d8ac115 100644 --- a/app/src/main/java/exh/eh/EHentaiUpdateWorker.kt +++ b/app/src/main/java/exh/eh/EHentaiUpdateWorker.kt @@ -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() @@ -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() + val meta = db.getFlatMetadataForManga(manga.id!!).executeAsBlocking()?.raise() 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 { diff --git a/app/src/main/java/exh/metadata/metadata/base/FlatMetadata.kt b/app/src/main/java/exh/metadata/metadata/base/FlatMetadata.kt index 249e2a3fb..fd1dc2861 100644 --- a/app/src/main/java/exh/metadata/metadata/base/FlatMetadata.kt +++ b/app/src/main/java/exh/metadata/metadata/base/FlatMetadata.kt @@ -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 : PreparedOperation { - /** - * Creates a [Flow] that emits the result of of Operation - * - * Example: - * override fun asFlow(): Flow = flow { emit(operation()) } - * - */ - fun asFlow(): Flow - - /** - * Executes operation asynchronously in the I/O thread pool. - */ - suspend fun executeOnIO(): T -} - -fun DatabaseHelper.getFlatMetadataForManga(mangaId: Long): PreparedSuspendOperation = - preparedOperationFromSuspend { - val meta = getSearchMetadataForManga(mangaId).executeOnIO() +fun DatabaseHelper.getFlatMetadataForManga(mangaId: Long): PreparedOperation { + // 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 preparedOperationFromSuspend(operation: suspend () -> T): PreparedSuspendOperation { - return object : PreparedSuspendOperation { + return preparedOperationFromSingle(single) +} + +private fun preparedOperationFromSingle(single: Single): PreparedOperation { + return object : PreparedOperation { /** * Creates [rx.Observable] that emits result of Operation. * @@ -74,7 +57,7 @@ private fun 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 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 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 preparedOperationFromSuspend(operation: suspend () -> T): Prepar * * @return single result of operation. */ - override fun asRxSingle(): Single = runAsObservable(operation).toSingle() - - /** - * Creates a [Flow] that emits the result of of Operation - * - * Example: - * override fun asFlow(): Flow = flow { emit(operation()) } - * - */ - override fun asFlow(): Flow = flow { emit(operation()) } - - /** - * Executes operation asynchronously in the I/O thread pool. - */ - override suspend fun executeOnIO(): T = withIOContext { operation() } + override fun asRxSingle() = single } } diff --git a/app/src/main/java/exh/ui/metadata/MetadataViewPresenter.kt b/app/src/main/java/exh/ui/metadata/MetadataViewPresenter.kt index 4338c651a..fcedf2c61 100644 --- a/app/src/main/java/exh/ui/metadata/MetadataViewPresenter.kt +++ b/app/src/main/java/exh/ui/metadata/MetadataViewPresenter.kt @@ -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 { - return db.getFlatMetadataForManga(manga.id!!).asFlow() + return db.getFlatMetadataForManga(manga.id!!).asRxObservable().asFlow() } } diff --git a/app/src/main/java/exh/util/DatabaseExtensions.kt b/app/src/main/java/exh/util/DatabaseExtensions.kt index f3d94c1a2..ba11915d9 100644 --- a/app/src/main/java/exh/util/DatabaseExtensions.kt +++ b/app/src/main/java/exh/util/DatabaseExtensions.kt @@ -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 PreparedPutObject.executeOnIO(): PutResult = withContext(Disp suspend fun PreparedPutCollectionOfObjects.executeOnIO(): PutResults = withContext(Dispatchers.IO) { executeAsBlocking() } -suspend fun PreparedGetCursor.executeOnIO(): Cursor = withContext(Dispatchers.IO) { executeAsBlocking() } +suspend fun PreparedOperation.executeOnIO(): T? = withContext(Dispatchers.IO) { executeAsBlocking() }