diff --git a/app/src/main/java/androidx/room/RoomTrackingLiveData.kt b/app/src/main/java/androidx/room/RoomTrackingLiveData.kt index 916133262c..32317b296a 100644 --- a/app/src/main/java/androidx/room/RoomTrackingLiveData.kt +++ b/app/src/main/java/androidx/room/RoomTrackingLiveData.kt @@ -23,6 +23,7 @@ import java.lang.RuntimeException import java.util.concurrent.Callable import java.util.concurrent.Executor import java.util.concurrent.atomic.AtomicBoolean +import java.util.concurrent.atomic.AtomicInteger /** * A LiveData implementation that closely works with [InvalidationTracker] to implement @@ -54,58 +55,52 @@ internal class RoomTrackingLiveData ( val invalid = AtomicBoolean(true) val computing = AtomicBoolean(false) val registeredObserver = AtomicBoolean(false) - val queued = eu.faircode.email.ObjectHolder(0) - val lock = Object() + val queued = AtomicInteger(0); val refreshRunnable = Runnable { - synchronized(lock) { - queued.value-- - if (queued.value < 0) { - eu.faircode.email.Log.e("$computeFunction queued=" + queued.value) - queued.value = 0 - } - } - if (registeredObserver.compareAndSet(false, true)) { database.invalidationTracker.addWeakObserver(observer) } - var value: T? = null - var computed = false - synchronized(computeFunction) { - var retry = 0 - while (!computed) { - try { - value = computeFunction.call() - computed = true - } catch (e: Throwable) { - if (++retry > 5) { - eu.faircode.email.Log.e(e) - break - } - eu.faircode.email.Log.w(e) + val v = queued.decrementAndGet(); + if (v < 0) { + queued.set(0) + eu.faircode.email.Log.e("$computeFunction queued=$v") + } else if (v > 0) + eu.faircode.email.Log.persist(eu.faircode.email.EntityLog.Type.Debug1, "$computeFunction queued=$v") + + if (v <= 0) { + var value: T? = null + var computed = false + synchronized(computeFunction) { + var retry = 0 + while (!computed) { try { - Thread.sleep(2000L) - } catch (ignored: InterruptedException) { + value = computeFunction.call() + computed = true + } catch (e: Throwable) { + if (++retry > 5) { + eu.faircode.email.Log.e(e) + break + } + eu.faircode.email.Log.w(e) + try { + Thread.sleep(2000L) + } catch (ignored: InterruptedException) { + } } } } - } - if (computed) { - postValue(value) + if (computed) { + postValue(value) + } } } val invalidationRunnable = Runnable { val isActive = hasActiveObservers() if (isActive) { - synchronized(lock) { - if (queued.value > 0) { - eu.faircode.email.Log.persist(eu.faircode.email.EntityLog.Type.Debug1, "$computeFunction queued=" + queued.value) - } else { - queued.value++ - queryExecutor.execute(refreshRunnable) - } - } + queued.incrementAndGet() + queryExecutor.execute(refreshRunnable) } } @@ -113,10 +108,8 @@ internal class RoomTrackingLiveData ( override fun onActive() { super.onActive() container.onActive(this as LiveData) - synchronized(lock) { - queued.value++ - queryExecutor.execute(refreshRunnable) - } + queued.incrementAndGet(); + queryExecutor.execute(refreshRunnable) } @Suppress("UNCHECKED_CAST") diff --git a/patches/roomkt.patch b/patches/roomkt.patch index b2a4ad565d..735ee6ba95 100644 --- a/patches/roomkt.patch +++ b/patches/roomkt.patch @@ -21,15 +21,22 @@ index 38067b702f..76cf95815c 100644 } if (invalidatedTableIds.isNotEmpty()) { diff --git a/app/src/main/java/androidx/room/RoomTrackingLiveData.kt b/app/src/main/java/androidx/room/RoomTrackingLiveData.kt -index 171b57d16e..85c14c1a93 100644 +index 171b57d16e..32317b296a 100644 --- a/app/src/main/java/androidx/room/RoomTrackingLiveData.kt +++ b/app/src/main/java/androidx/room/RoomTrackingLiveData.kt -@@ -54,62 +54,70 @@ internal class RoomTrackingLiveData ( +@@ -23,6 +23,7 @@ import java.lang.RuntimeException + import java.util.concurrent.Callable + import java.util.concurrent.Executor + import java.util.concurrent.atomic.AtomicBoolean ++import java.util.concurrent.atomic.AtomicInteger + + /** + * A LiveData implementation that closely works with [InvalidationTracker] to implement +@@ -54,62 +55,62 @@ internal class RoomTrackingLiveData ( val invalid = AtomicBoolean(true) val computing = AtomicBoolean(false) val registeredObserver = AtomicBoolean(false) -+ val queued = eu.faircode.email.ObjectHolder(0) -+ val lock = Object() ++ val queued = AtomicInteger(0); val refreshRunnable = Runnable { - if (registeredObserver.compareAndSet(false, true)) { - database.invalidationTracker.addWeakObserver(observer) @@ -70,41 +77,42 @@ index 171b57d16e..85c14c1a93 100644 - // We've left invalid in set state. The check below recovers. - } while (computed && invalid.get()) - } -+ synchronized(lock) { -+ queued.value-- -+ if (queued.value < 0) { -+ eu.faircode.email.Log.e("$computeFunction queued=" + queued.value) -+ queued.value = 0 -+ } -+ } -+ + if (registeredObserver.compareAndSet(false, true)) { + database.invalidationTracker.addWeakObserver(observer) + } + -+ var value: T? = null -+ var computed = false -+ synchronized(computeFunction) { -+ var retry = 0 -+ while (!computed) { -+ try { -+ value = computeFunction.call() -+ computed = true -+ } catch (e: Throwable) { -+ if (++retry > 5) { -+ eu.faircode.email.Log.e(e) -+ break -+ } -+ eu.faircode.email.Log.w(e) ++ val v = queued.decrementAndGet(); ++ if (v < 0) { ++ queued.set(0) ++ eu.faircode.email.Log.e("$computeFunction queued=$v") ++ } else if (v > 0) ++ eu.faircode.email.Log.persist(eu.faircode.email.EntityLog.Type.Debug1, "$computeFunction queued=$v") ++ ++ if (v <= 0) { ++ var value: T? = null ++ var computed = false ++ synchronized(computeFunction) { ++ var retry = 0 ++ while (!computed) { + try { -+ Thread.sleep(2000L) -+ } catch (ignored: InterruptedException) { ++ value = computeFunction.call() ++ computed = true ++ } catch (e: Throwable) { ++ if (++retry > 5) { ++ eu.faircode.email.Log.e(e) ++ break ++ } ++ eu.faircode.email.Log.w(e) ++ try { ++ Thread.sleep(2000L) ++ } catch (ignored: InterruptedException) { ++ } + } + } + } -+ } -+ if (computed) { -+ postValue(value) ++ if (computed) { ++ postValue(value) ++ } + } + } @@ -118,14 +126,8 @@ index 171b57d16e..85c14c1a93 100644 - } + val isActive = hasActiveObservers() + if (isActive) { -+ synchronized(lock) { -+ if (queued.value > 0) { -+ eu.faircode.email.Log.persist(eu.faircode.email.EntityLog.Type.Debug, "$computeFunction queued=" + queued.value) -+ } else { -+ queued.value++ -+ queryExecutor.execute(refreshRunnable) -+ } -+ } ++ queued.incrementAndGet() ++ queryExecutor.execute(refreshRunnable) + } + } @@ -137,10 +139,8 @@ index 171b57d16e..85c14c1a93 100644 - } + super.onActive() + container.onActive(this as LiveData) -+ synchronized(lock) { -+ queued.value++ -+ queryExecutor.execute(refreshRunnable) -+ } ++ queued.incrementAndGet(); ++ queryExecutor.execute(refreshRunnable) + } @Suppress("UNCHECKED_CAST")