Status Update
Comments
da...@google.com <da...@google.com> #2
Branch: androidx-master-dev
commit b90079595f33f58fece04026a97faa0d243acdb1
Author: Yuichi Araki <yaraki@google.com>
Date: Wed Sep 18 16:55:49 2019
Change the way to detect mismatch between POJO and query
This fixes cursor mismatch warnings with expandProjection.
Bug: 140759491
Test: QueryMethodProcessorTest
Change-Id: I7659002e5e0d1ef60fc1af2a625c0c36da0664d8
M room/compiler/src/main/kotlin/androidx/room/processor/QueryMethodProcessor.kt
M room/compiler/src/main/kotlin/androidx/room/solver/TypeAdapterStore.kt
M room/compiler/src/main/kotlin/androidx/room/solver/query/result/PojoRowAdapter.kt
M room/compiler/src/test/kotlin/androidx/room/processor/QueryMethodProcessorTest.kt
M room/compiler/src/test/kotlin/androidx/room/testing/TestProcessor.kt
yb...@google.com <yb...@google.com> #3
yb...@google.com <yb...@google.com> #4
Branch: androidx-master-dev
commit bdde5a1a970ddc9007b28de4aa29d60ffa588f08
Author: Yigit Boyar <yboyar@google.com>
Date: Thu Apr 16 16:47:05 2020
Re-factor how errors are dismissed when query is re-written
This CL changes how we handle errors/warnings if query is
re-written.
There was a bug in expandProjection where we would report warnings
for things that Room already fixes automatically (
The solution to that problem (I7659002e5e0d1ef60fc1af2a625c0c36da0664d8)
solved it by deferring validating of columns until after re-write
decision is made. Unfortunately, this required changing PojoRowAdapter
to have a dummy mapping until it is validating, make it hard to use
as it does have a non-null mapping which is not useful.
This CL partially reverts that change and instead rely on the log
deferring logic we have in Context. This way, we don't need to break
the stability of PojoRowAdapter while still having the ability to
drop warnings that room fixes. This will also play nicer when we
have different query re-writing options that can use more information
about the query results.
Bug: 153387066
Bug: 140759491
Test: existing tests pass
Change-Id: I2ec967c763d33d7a3ff02c1a13c6953b460d1e5f
M room/compiler/src/main/kotlin/androidx/room/log/RLog.kt
M room/compiler/src/main/kotlin/androidx/room/processor/QueryMethodProcessor.kt
M room/compiler/src/main/kotlin/androidx/room/solver/TypeAdapterStore.kt
M room/compiler/src/main/kotlin/androidx/room/solver/query/result/PojoRowAdapter.kt
yb...@google.com <yb...@google.com> #5
current code actually tries to accomodate for a similar case in
Executor.acquireTransactionThread
by cancelling the job if that suspendCancellableCoroutine is cancelled yet in this case it actually completes successfully as cancellation only happens when it tries to hand it back in which case there is no place to cancel the job anymore.
yb...@google.com <yb...@google.com> #6
seems like the right fix is to use:
continuation.resume(coroutineContext[ContinuationInterceptor]!!) {
// on cancel block
controlJob.cancel()
}
to cover that case. unfortunately though it is experimental API.
Docs mention that this is when we need to close a resource, which is exactly our use case.
This function shall be used when resuming with a resource that must be closed by the code that had called the corresponding suspending function, e.g.:
yb...@google.com <yb...@google.com> #7
actually
continuation.resume(coroutineContext[ContinuationInterceptor]!!) {
// on cancel block
controlJob.cancel()
}
does not seem to work as I can still make it flake, very unlikely but possible
On the other hand, the initial solution of cancelling the job via the coroutine context's Job seems to work fine.
yb...@google.com <yb...@google.com> #8
ok that one fails because even if we get into execute, the following withContext may never start, again leaving the job lingering around.
I think it is best to tie that job to the context which is creating the transaction context as it should never live outside.
ap...@google.com <ap...@google.com> #9
Branch: androidx-master-dev
commit c89f069d9d7de77f8f0961f15f318494687cdac2
Author: Yigit Boyar <yboyar@google.com>
Date: Sun Jan 26 08:51:17 2020
Tie transaction job to the calling context
This CL fixes a bug in room suspend transactions where we would deadlock
the transactions if the calling coroutine gets cancelled before we can
even start the transaction. It would leave the control job in active
state with no other callback to cancel it (to unlock the runner).
With this change, we automatically cancel it if the calling context
has a job. Note that it is not added as a child job since doing so would
cancel the calling context when job is cancelled. We want that to be
just a one way cancelation.
Bug: 148181325
Test: SuspendingTransactionCancelationTest
Change-Id: I18a76128d325f099b9677af1bb5d35cedf43e3d5
A room/integration-tests/kotlintestapp/src/androidTest/java/androidx/room/integration/kotlintestapp/test/SuspendingTransactionCancellationTest.kt
M room/ktx/src/main/java/androidx/room/RoomDatabase.kt
an...@google.com <an...@google.com> #11
[Deleted User] <[Deleted User]> #12
zs...@google.com <zs...@google.com> #13
This deadlocks in tests as well:
@Test
fun bug() = runTest {
createTestDatabase().withTransaction {
println("hello world")
}
}
This will hang inside withTransaction
(more precisely, in acquireTransactionThread
), waiting for controlJob.join()
Description
Version used: 2.2.3
Devices/Android versions reproduced on: Pixel XL (API 26 - Emulator), Samsung Galaxy Tab A (API 28)
There seems to be an issue, with calling function from DAO, which is marked as @Transaction.
Issue emerges, while cancelling Job (Coroutines) which called the function.
Let's say, that we have simple function which:
1. Launches new coroutine
2. Inside this coroutine, we call function from DAO marked with @Transaction annotation
Then, if we would cancel this Job immediately after starting it, deadlock happens.
Every following function call, does not make place.
I've made sample project available here:
In there, you have two buttons. First one "Fetch user once" fetches user from the Database (using function called "getUser()").
Second button "Fetch user twice", calls this function twice.
As you can see in the sample code, we have mutual object, to which we assign latest Job.
In the beginning of every function call, we cancel previous Job and start new one.
Everything that is happening, is displayed in the TextView below buttons.
After pressing first button we can see that Job is loading data "Job 1 - Loading Data" for 3 seconds (there is a delay in DAO function) and then fetched data is displayed. In the logs we have:
D/MainActivity: Starting singular fetch
D/MainActivity: [main] Starting job 1
D/[main] Job 1: Getting user
D/UserDao: [arch_disk_io_2] getUserWithTransaction - start delay
D/UserDao: [arch_disk_io_2] getUserWithTransaction - after delay
D/[main] Job 1: Got user: User(uid=123, firstName=Adam)
If we later press the second button, TextView changes to "Job 3 - Loading data" (it's 3, because we called it twice) and nothing then changes. Data is not displayed (because it failed to fetch it), no error message is shown. In the logs we see:
D/MainActivity: Starting double fetch
D/MainActivity: [main] Starting job 2
D/[main] Job 2: Getting user
D/MainActivity: [main] Starting job 3
D/[main] Job 3: Getting user
E/[main] Job 2: Getting user cancelled
kotlinx.coroutines.JobCancellationException: StandaloneCoroutine was cancelled; job=StandaloneCoroutine{Cancelling}@86c7792
From now on, every call to this function is being frozen. For example next click on "Fetch user once" changes TextView message to "Job 4 - Loading data..." but nothing after that. Again in the logs:
D/MainActivity: Starting singular fetch
E/[main] Job 3: Getting user cancelled
kotlinx.coroutines.JobCancellationException: StandaloneCoroutine was cancelled; job=StandaloneCoroutine{Cancelling}@5cdea19
D/MainActivity: [main] Starting job 4
D/[main] Job 4: Getting user
As you can see in second and third case no logs from UsersDao are displayed. This means, that User's Dao function wasn't even called.
We can fix it now only by restarting the application.