Fix concurrent manga downloading #154
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
package org.koitharu.kotatsu.utils
|
||||
|
||||
import kotlinx.coroutines.CancellableContinuation
|
||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
import java.util.*
|
||||
import kotlin.coroutines.resume
|
||||
|
||||
class CompositeMutex<T : Any> : Set<T> {
|
||||
|
||||
private val data = HashMap<T, MutableList<CancellableContinuation<Unit>>>()
|
||||
private val mutex = Mutex()
|
||||
|
||||
override val size: Int
|
||||
get() = data.size
|
||||
|
||||
override fun contains(element: T): Boolean {
|
||||
return data.containsKey(element)
|
||||
}
|
||||
|
||||
override fun containsAll(elements: Collection<T>): Boolean {
|
||||
return elements.all { x -> data.containsKey(x) }
|
||||
}
|
||||
|
||||
override fun isEmpty(): Boolean {
|
||||
return data.isEmpty()
|
||||
}
|
||||
|
||||
override fun iterator(): Iterator<T> {
|
||||
return data.keys.iterator()
|
||||
}
|
||||
|
||||
suspend fun lock(element: T) {
|
||||
waitForRemoval(element)
|
||||
mutex.withLock {
|
||||
val lastValue = data.put(element, LinkedList<CancellableContinuation<Unit>>())
|
||||
check(lastValue == null) {
|
||||
"CompositeMutex is double-locked for $element"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun unlock(element: T) {
|
||||
val continuations = mutex.withLock {
|
||||
checkNotNull(data.remove(element)) {
|
||||
"CompositeMutex is not locked for $element"
|
||||
}
|
||||
}
|
||||
continuations.forEach { c ->
|
||||
if (c.isActive) {
|
||||
c.resume(Unit)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun waitForRemoval(element: T) {
|
||||
val list = data[element] ?: return
|
||||
suspendCancellableCoroutine<Unit> { continuation ->
|
||||
list.add(continuation)
|
||||
continuation.invokeOnCancellation {
|
||||
list.remove(continuation)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package org.koitharu.kotatsu.utils.progress
|
||||
|
||||
import android.os.SystemClock
|
||||
import java.util.concurrent.TimeUnit
|
||||
import kotlin.math.roundToInt
|
||||
import kotlin.math.roundToLong
|
||||
|
||||
@@ -11,6 +12,7 @@ class TimeLeftEstimator {
|
||||
|
||||
private var times = ArrayList<Int>()
|
||||
private var lastTick: Tick? = null
|
||||
private val tooLargeTime = TimeUnit.DAYS.toMillis(1)
|
||||
|
||||
fun tick(value: Int, total: Int) {
|
||||
if (total < 0) {
|
||||
@@ -36,7 +38,8 @@ class TimeLeftEstimator {
|
||||
}
|
||||
val timePerTick = times.average()
|
||||
val ticksLeft = progress.total - progress.value
|
||||
return (ticksLeft * timePerTick).roundToLong()
|
||||
val eta = (ticksLeft * timePerTick).roundToLong()
|
||||
return if (eta < tooLargeTime) eta else NO_TIME
|
||||
}
|
||||
|
||||
private class Tick(
|
||||
|
||||
Reference in New Issue
Block a user