MobileNativeFoundation / MobileNativeFoundation/Store
[BUG] ANR due to ConcurrentHashMap lock in `RealCache`
Nobody has claimed this yet.
- Dominant language
- Kotlin
- Stars
- 3.4k
- Forks
- 217
- Avg merge
- 18m
- Merged PRs (30d)
- 4
Description
See the following thread stack. I'm using a pretty vanilla setup for Room + Store and streaming in ViewModels (i.e. collecting on the main thread):
viewModelScope.launch {
store.stream(StoreRequest.cached(showId, refresh = false))
.collect { ... }
}
This might be a guidance issue, where we tell people to stream(...).flowOn(Dispatcher.Default)
Log:
"main" prio=5 tid=1 Runnable
| group="main" sCount=1 dsCount=0 flags=9 obj=0x717a02f8 self=0xb4000070b9eec380
| sysTid=27737 nice=0 cgrp=default sched=0/0 handle=0x71e08094f8
| state=R schedstat=( 45250255527 4245629451 61014 ) utm=4253 stm=271 core=4 HZ=100
| stack=0x7ff1d62000-0x7ff1d64000 stackSize=8192KB
| held mutexes= "mutator lock"(shared held)
at java.util.concurrent.ConcurrentHashMap.replaceNode (ConcurrentHashMap.java:1116)
at java.util.concurrent.ConcurrentHashMap.remove (ConcurrentHashMap.java:1107)
at com.dropbox.android.external.cache4.RealCache.evictEntries (RealCache.java:228)
at com.dropbox.android.external.cache4.RealCache.put (RealCache.java:151)
at com.dropbox.android.external.store4.impl.RealStore$stream$2.invokeSuspend (RealStore.java:116)
at com.dropbox.android.external.store4.impl.RealStore$stream$2.invoke (RealStore.java)
at kotlinx.coroutines.flow.FlowKt__TransformKt$onEach$$inlined$unsafeTransform$1$2.emit (FlowKt__TransformKt.java:134)
at kotlinx.coroutines.flow.internal.SafeCollectorKt$emitFun$1.invoke (SafeCollectorKt.java:15)
at kotlinx.coroutines.flow.internal.SafeCollectorKt$emitFun$1.invoke (SafeCollectorKt.java:1)
at kotlinx.coroutines.flow.internal.SafeCollector.emit (SafeCollector.java:73)
at kotlinx.coroutines.flow.internal.SafeCollector.emit (SafeCollector.java:55)
at kotlinx.coroutines.flow.internal.SafeCollectorKt$emitFun$1.invoke (SafeCollectorKt.java:15)
at kotlinx.coroutines.flow.internal.SafeCollectorKt$emitFun$1.invoke (SafeCollectorKt.java:1)
at kotlinx.coroutines.flow.internal.SafeCollector.emit (SafeCollector.java:73)
at kotlinx.coroutines.flow.internal.SafeCollector.emit (SafeCollector.java:55)
at com.dropbox.android.external.store4.impl.RealStore$diskNetworkCombined$$inlined$transform$1$1.emit (RealStore.java:152)
at kotlinx.coroutines.flow.FlowKt__ChannelsKt.emitAllImpl$FlowKt__ChannelsKt (FlowKt__ChannelsKt.java:58)
at kotlinx.coroutines.flow.FlowKt__ChannelsKt$emitAllImpl$1.invokeSuspend (FlowKt__ChannelsKt.java)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith (BaseContinuationImpl.java:33)
at kotlinx.coroutines.DispatchedTask.run (DispatchedTask.java:56)
at kotlinx.coroutines.EventLoop.processUnconfinedEvent (EventLoop.java:69)
at kotlinx.coroutines.CancellableContinuationImpl.parentCancelled$kotlinx_coroutines_core (CancellableContinuationImpl.java:184)
at kotlinx.coroutines.DispatchedTaskKt.resumeUnconfined (DispatchedTaskKt.java:184)
at kotlinx.coroutines.DispatchedTaskKt.dispatch (DispatchedTaskKt.java:108)
at kotlinx.coroutines.CancellableContinuationImpl.dispatchResume (CancellableContinuationImpl.java:308)
at kotlinx.coroutines.CancellableContinuationImpl.completeResume (CancellableContinuationImpl.java:395)
at kotlinx.coroutines.channels.AbstractChannel$ReceiveElement.completeResumeReceive (AbstractChannel.java:872)
at kotlinx.coroutines.channels.ArrayChannel.offerInternal (ArrayChannel.java:83)
at kotlinx.coroutines.channels.AbstractSendChannel.send (AbstractSendChannel.java:133)
at kotlinx.coroutines.channels.ChannelCoroutine.send$suspendImpl (ChannelCoroutine.java:1)
at kotlinx.coroutines.channels.ChannelCoroutine.send (ChannelCoroutine.java:1)
at kotlinx.coroutines.flow.internal.SendingCollector.emit (SendingCollector.java:19)
at kotlinx.coroutines.flow.internal.SafeCollectorKt$emitFun$1.invoke (SafeCollectorKt.java:15)
at kotlinx.coroutines.flow.internal.SafeCollectorKt$emitFun$1.invoke (SafeCollectorKt.java:1)
at kotlinx.coroutines.flow.internal.SafeCollector.emit (SafeCollector.java:73)
at kotlinx.coroutines.flow.internal.SafeCollector.emit (SafeCollector.java:55)
at com.dropbox.android.external.store4.impl.SourceOfTruthWithBarrier$reader$1$invokeSuspend$$inlined$flatMapLatest$1$lambda$1$1.emit (SourceOfTruthWithBarrier.java:153)
at kotlinx.coroutines.flow.internal.SafeCollectorKt$emitFun$1.invoke (SafeCollectorKt.java:15)
at kotlinx.coroutines.flow.internal.SafeCollectorKt$emitFun$1.invoke (SafeCollectorKt.java:1)
at kotlinx.coroutines.flow.internal.SafeCollector.emit (SafeCollector.java:73)
at kotlinx.coroutines.flow.internal.SafeCollector.emit (SafeCollector.java:55)
at androidx.room.CoroutinesRoom$Companion$createFlow$1$1$1.invokeSuspend (CoroutinesRoom.java:82)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith (BaseContinuationImpl.java:33)
at kotlinx.coroutines.DispatchedTask.run (DispatchedTask.java:56)
at android.os.Handler.handleCallback (Handler.java:938)
at android.os.Handler.dispatchMessage (Handler.java:99)
at android.os.Looper.loop (Looper.java:223)
at android.app.ActivityThread.main (ActivityThread.java:7656)
at java.lang.reflect.Method.invoke (Method.java)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:592)
at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:947)
Smartphone:
- Device: various
- OS: various
- Store Version: 4.0.0-alpha05 (trying alpha06 now)
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the stack entries for RealCache.evictEntries and RealCache.put, then trace RealStore.stream around the reported calls. Reproduce the shown viewModelScope and stream collection pattern, including the possible flowOn(Dispatcher.Default) guidance. Done means the ANR cause and an actionable code or guidance resolution are established.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- android, kotlin
- Domain
- mobile-dev, performance
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Needs clarification
- Newbie friendliness
- 25/100