Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use getOrDefault instead of getValue in TransactionManager #1389

Closed
wants to merge 3 commits into from

Conversation

nomisRev
Copy link

Attempts to fix #1387.

I was unsure where to put the test since the CoroutineTest file didn't have a Database available.
Shall I put the test inside the H2Tests file?

@nomisRev nomisRev changed the title Use getOrDefault instead of getValue in currentThreadManager Use getOrDefault instead of getValue in TransactionManager Nov 24, 2021
@@ -76,12 +76,12 @@ interface TransactionManager {
fun closeAndUnregister(database: Database) {
val manager = registeredDatabases[database]
manager?.let {
registeredDatabases.remove(database)
databases.remove(database)
currentDefaultDatabase.compareAndSet(database, null)
if (currentThreadManager.get() == it) {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Tapac I tried your fix on master but it didn't fix the issue.

The issue is shown in the test H2Tests. When you call closeAndRegister from a different Thread the ThreadLocal is empty, and will thus try to initialize itself. Resulting in registeredDatabases[database] begin called which throw NoSuchElementException since we remove the database from the registeredDatabases map on line 79.

To fix this we could move the removal of database to after the if check but that would redundantly initialize the threadLocal. There are a couple of solutions for that, but they probably introduce similar overhead as just running the initializer and immediately removing it.

withDb(TestDB.H2) { testDB ->
runBlocking {
val db = requireNotNull(testDB.db) { "testDB.db cannot be null" }
TransactionManager.registerManager(
Copy link
Author

@nomisRev nomisRev Nov 27, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not 100% sure anymore why this introduced the issue.
I'd need to re-debug the flow, but it was related to registerManager adding a 2nd entry for Database into private val databases = ConcurrentLinkedDeque<Database>().

So is that second instance leaking in the ConcurrentLinkedDeque if you only call closeAnddUnregister once? 🤔

@nomisRev
Copy link
Author

Closed by fixed: 621dc5b

@nomisRev nomisRev closed this Nov 29, 2021
@nomisRev nomisRev deleted the fix-1387 branch November 29, 2021 09:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Bug when calling TransactionManager.closeAndUnregister from a different Thread.
1 participant