Help with favorites sync db locking

This commit is contained in:
Jobobby04 2021-06-10 17:20:29 -04:00
parent 963b85f756
commit 9e80f47e9f
4 changed files with 48 additions and 28 deletions

View File

@ -16,7 +16,7 @@ import eu.kanade.tachiyomi.source.online.all.EHentai
import eu.kanade.tachiyomi.util.chapter.syncChaptersWithSource
import exh.log.xLogStack
import exh.source.getMainSource
import exh.util.executeOnIO
import exh.util.maybeRunBlocking
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
import uy.kohesive.injekt.injectLazy
@ -53,7 +53,8 @@ class GalleryAdder {
url: String,
fav: Boolean = false,
forceSource: UrlImportableSource? = null,
throttleFunc: suspend () -> Unit = {}
throttleFunc: suspend () -> Unit = {},
protectTrans: Boolean = false
): GalleryAddEvent {
logger.d(context.getString(R.string.gallery_adder_importing_manga, url, fav.toString(), forceSource))
try {
@ -118,7 +119,7 @@ class GalleryAdder {
} ?: return GalleryAddEvent.Fail.UnknownType(url, context)
// Use manga in DB if possible, otherwise, make a new manga
val manga = db.getManga(cleanedMangaUrl, source.id).executeOnIO()
val manga = db.getManga(cleanedMangaUrl, source.id).executeAsBlocking()
?: Manga.create(source.id).apply {
this.url = cleanedMangaUrl
title = realMangaUrl
@ -146,14 +147,16 @@ class GalleryAdder {
// Fetch and copy chapters
try {
val chapterList = if (source is EHentai) {
source.getChapterList(manga.toMangaInfo(), throttleFunc)
} else {
source.getChapterList(manga.toMangaInfo())
}.map { it.toSChapter() }
maybeRunBlocking(protectTrans) {
val chapterList = if (source is EHentai) {
source.getChapterList(manga.toMangaInfo(), throttleFunc)
} else {
source.getChapterList(manga.toMangaInfo())
}.map { it.toSChapter() }
if (chapterList.isNotEmpty()) {
syncChaptersWithSource(db, chapterList, manga, source)
if (chapterList.isNotEmpty()) {
syncChaptersWithSource(db, chapterList, manga, source)
}
}
} catch (e: Exception) {
logger.w(context.getString(R.string.gallery_adder_chapter_fetch_error, manga.title), e)
@ -161,7 +164,7 @@ class GalleryAdder {
}
return if (cleanedChapterUrl != null) {
val chapter = db.getChapter(cleanedChapterUrl, manga.id!!).executeOnIO()
val chapter = db.getChapter(cleanedChapterUrl, manga.id!!).executeAsBlocking()
if (chapter != null) {
GalleryAddEvent.Success(url, manga, context, chapter)
} else {

View File

@ -14,6 +14,7 @@ import eu.kanade.tachiyomi.network.await
import eu.kanade.tachiyomi.source.SourceManager
import eu.kanade.tachiyomi.source.online.all.EHentai
import eu.kanade.tachiyomi.util.lang.launchUI
import eu.kanade.tachiyomi.util.lang.withIOContext
import eu.kanade.tachiyomi.util.system.powerManager
import eu.kanade.tachiyomi.util.system.toast
import exh.GalleryAddEvent
@ -24,7 +25,6 @@ import exh.log.xLog
import exh.source.EH_SOURCE_ID
import exh.source.EXH_SOURCE_ID
import exh.source.isEhBasedManga
import exh.util.executeOnIO
import exh.util.ignore
import exh.util.trans
import exh.util.wifiManager
@ -85,13 +85,13 @@ class FavoritesSyncHelper(val context: Context) {
// Validate library state
status.value = FavoritesSyncStatus.Processing(context.getString(R.string.favorites_sync_verifying_library), context = context)
val libraryManga = db.getLibraryMangas().executeOnIO()
val libraryManga = db.getLibraryMangas().executeAsBlocking()
val seenManga = HashSet<Long>(libraryManga.size)
libraryManga.forEach {
if (!it.isEhBasedManga()) return@forEach
if (it.id in seenManga) {
val inCategories = db.getCategoriesForManga(it).executeOnIO()
val inCategories = db.getCategoriesForManga(it).executeAsBlocking()
status.value = FavoritesSyncStatus.BadLibraryState.MangaInMultipleCategories(it, inCategories, context)
logger.w(context.getString(R.string.favorites_sync_manga_multiple_categories_error, it.id))
@ -194,8 +194,8 @@ class FavoritesSyncHelper(val context: Context) {
}
}
private suspend fun applyRemoteCategories(categories: List<String>) {
val localCategories = db.getCategories().executeOnIO()
private fun applyRemoteCategories(categories: List<String>) {
val localCategories = db.getCategories().executeAsBlocking()
val newLocalCategories = localCategories.toMutableList()
@ -233,7 +233,7 @@ class FavoritesSyncHelper(val context: Context) {
// Only insert categories if changed
if (changed) {
db.insertCategories(newLocalCategories).executeOnIO()
db.insertCategories(newLocalCategories).executeAsBlocking()
}
}
@ -267,7 +267,7 @@ class FavoritesSyncHelper(val context: Context) {
for (i in 1..retryCount) {
try {
val resp = exh.client.newCall(request).await()
val resp = withIOContext { exh.client.newCall(request).await() }
if (resp.isSuccessful) {
success = true
@ -340,7 +340,7 @@ class FavoritesSyncHelper(val context: Context) {
db.getManga(url, EXH_SOURCE_ID),
db.getManga(url, EH_SOURCE_ID)
).forEach {
val manga = it.executeOnIO()
val manga = it.executeAsBlocking()
if (manga?.favorite == true) {
manga.favorite = false
@ -357,7 +357,7 @@ class FavoritesSyncHelper(val context: Context) {
}
val insertedMangaCategories = mutableListOf<Pair<MangaCategory, Manga>>()
val categories = db.getCategories().executeOnIO()
val categories = db.getCategories().executeAsBlocking()
// Apply additions
throttleManager.resetThrottle()
@ -376,7 +376,8 @@ class FavoritesSyncHelper(val context: Context) {
"${exh.baseUrl}${it.getUrl()}",
true,
exh,
throttleManager::throttle
throttleManager::throttle,
true
)
if (result is GalleryAddEvent.Fail) {

View File

@ -5,7 +5,6 @@ import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.source.online.all.EHentai
import exh.metadata.metadata.EHentaiSearchMetadata
import exh.source.isEhBasedManga
import exh.util.executeOnIO
import io.realm.Realm
import io.realm.RealmConfiguration
import uy.kohesive.injekt.injectLazy
@ -20,13 +19,13 @@ class LocalFavoritesStorage {
fun getRealm(): Realm = Realm.getInstance(realmConfig)
suspend fun getChangedDbEntries(realm: Realm) =
fun getChangedDbEntries(realm: Realm) =
getChangedEntries(
realm,
parseToFavoriteEntries(
loadDbCategories(
db.getFavoriteMangas()
.executeOnIO()
.executeAsBlocking()
.asSequence()
)
)
@ -45,11 +44,11 @@ class LocalFavoritesStorage {
)
)
suspend fun snapshotEntries(realm: Realm) {
fun snapshotEntries(realm: Realm) {
val dbMangas = parseToFavoriteEntries(
loadDbCategories(
db.getFavoriteMangas()
.executeOnIO()
.executeAsBlocking()
.asSequence()
)
)
@ -97,8 +96,8 @@ class LocalFavoritesStorage {
it.category == entry.category
}
private suspend fun loadDbCategories(manga: Sequence<Manga>): Sequence<Pair<Int, Manga>> {
val dbCategories = db.getCategories().executeOnIO()
private fun loadDbCategories(manga: Sequence<Manga>): Sequence<Pair<Int, Manga>> {
val dbCategories = db.getCategories().executeAsBlocking()
return manga.filter(this::validateDbManga).mapNotNull {
val category = db.getCategoriesForManga(it).executeAsBlocking()

View File

@ -3,8 +3,25 @@ package exh.util
import kotlinx.coroutines.ensureActive
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.runBlocking
import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.InvocationKind
import kotlin.contracts.contract
import kotlin.coroutines.coroutineContext
fun <T> Flow<T>.cancellable() = onEach {
coroutineContext.ensureActive()
}
@Suppress("BlockingMethodInNonBlockingContext")
@OptIn(ExperimentalContracts::class)
suspend inline fun <T> maybeRunBlocking(runBlocking: Boolean, crossinline block: suspend () -> T): T {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return if (runBlocking) {
runBlocking { block() }
} else {
block()
}
}