Skip to content

feat: enable WAL connection pool for parallel reads#5372

Merged
jamesarich merged 2 commits into
mainfrom
feat/wal-connection-pool
May 21, 2026
Merged

feat: enable WAL connection pool for parallel reads#5372
jamesarich merged 2 commits into
mainfrom
feat/wal-connection-pool

Conversation

@jamesarich

@jamesarich jamesarich commented May 6, 2026

Copy link
Copy Markdown
Collaborator

Enables Room 3 new APIs in the database configuration layer.

Changes

  1. Connection pool — Configure setMultipleConnectionPool(maxNumOfReaders = 4, maxNumOfWriters = 1) in configureCommon() for WAL-mode parallel reads
  2. No-Context builders — Drop redundant Context param from Android's databaseBuilder and inMemoryDatabaseBuilder (Room 3.0.0-alpha03 overloads; we already pass absolute paths)

Impact

  • Improved read performance under concurrent access (message list + search + sync can run in parallel)
  • Aligns Android builders with JVM/iOS implementations (all now use context-free overloads)
  • No schema change required
  • WAL mode was already enabled by default in Room

@github-actions github-actions Bot added the enhancement New feature or request label May 6, 2026
@jamesarich jamesarich requested a review from Copilot May 6, 2026 20:01

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR enables Room 3’s multi-connection pool on the shared RoomDatabase.Builder configuration to allow parallel reads while writes are in progress (WAL-mode), improving responsiveness under concurrent database access (e.g., message list + search + sync).

Changes:

  • Enable setMultipleConnectionPool(maxNumOfReaders = 4, maxNumOfWriters = 1) in the project’s common Room builder configuration.
  • Keep existing destructive-migration fallback and query coroutine context configuration intact.

Room 3.0.0-alpha04 adds setMultipleConnectionPool(). Enable it with
4 readers / 1 writer to allow concurrent read operations (paging,
multiple Flow collectors) without contention.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@jamesarich jamesarich force-pushed the feat/wal-connection-pool branch from dddba07 to 402a85d Compare May 21, 2026 00:24
Room 3.0.0-alpha03 introduced databaseBuilder and inMemoryDatabaseBuilder
overloads that no longer require an Android Context parameter. Since we
already pass absolute paths, Context was redundant for Room's internal use.

This aligns the Android builders with the JVM/iOS implementations that
already use the context-free overloads.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@jamesarich jamesarich force-pushed the feat/wal-connection-pool branch from 402a85d to fb0046a Compare May 21, 2026 00:37
@jamesarich jamesarich merged commit e67ebb7 into main May 21, 2026
16 of 17 checks passed
@jamesarich jamesarich deleted the feat/wal-connection-pool branch May 21, 2026 00:42
@codecov

codecov Bot commented May 21, 2026

Copy link
Copy Markdown

❌ 1 Tests Failed:

Tests completed Failed Passed Skipped
2446 1 2445 0
View the top 1 failed test(s) by shortest run time
org.meshtastic.core.database.DatabaseManagerWithDbRetryTest::withDb retries against current database when previous pool closes during switch
Stack Traces | 22.1s run time
java.lang.AssertionError: expected:<42424242> but was:<null>
	at org.junit.Assert.fail(Assert.java:89)
	at org.junit.Assert.failNotEquals(Assert.java:835)
	at org.junit.Assert.assertEquals(Assert.java:120)
	at kotlin.test.junit.JUnitAsserter.assertEquals(JUnitSupport.kt:32)
	at kotlin.test.AssertionsKt__AssertionsKt.assertEquals(Assertions.kt:63)
	at kotlin.test.AssertionsKt.assertEquals(Unknown Source)
	at kotlin.test.AssertionsKt__AssertionsKt.assertEquals$default(Assertions.kt:62)
	at kotlin.test.AssertionsKt.assertEquals$default(Unknown Source)
	at org.meshtastic.core.database.DatabaseManagerWithDbRetryTest$withDb retries against current database when previous pool closes during switch$1.invokeSuspend(DatabaseManagerWithDbRetryTest.kt:99)
	at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:34)
	at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:100)
	at kotlinx.coroutines.test.TestDispatcher.processEvent$kotlinx_coroutines_test(TestDispatcher.kt:24)
	at kotlinx.coroutines.test.TestCoroutineScheduler.tryRunNextTaskUnless$kotlinx_coroutines_test(TestCoroutineScheduler.kt:98)
	at kotlinx.coroutines.test.TestBuildersKt__TestBuildersKt$runTest$2$1$workRunner$1.invokeSuspend(TestBuilders.kt:326)
	at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:34)
	at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:100)
	at kotlinx.coroutines.EventLoopImplBase.processNextEvent(EventLoop.common.kt:256)
	at kotlinx.coroutines.BlockingCoroutine.joinBlocking(Builders.kt:54)
	at kotlinx.coroutines.BuildersKt__BuildersKt.runBlockingImpl(Builders.kt:30)
	at kotlinx.coroutines.BuildersKt.runBlockingImpl(Unknown Source)
	at kotlinx.coroutines.BuildersKt__Builders_concurrentKt.runBlockingK(Builders.concurrent.kt:172)
	at kotlinx.coroutines.BuildersKt.runBlockingK(Unknown Source)
	at kotlinx.coroutines.BuildersKt__Builders_concurrentKt.runBlockingK$default(Builders.concurrent.kt:157)
	at kotlinx.coroutines.BuildersKt.runBlockingK$default(Unknown Source)
	at kotlinx.coroutines.test.TestBuildersJvmKt.createTestResult(TestBuildersJvm.kt:10)
	at kotlinx.coroutines.test.TestBuildersKt__TestBuildersKt.runTest-8Mi8wO0(TestBuilders.kt:309)
	at kotlinx.coroutines.test.TestBuildersKt.runTest-8Mi8wO0(TestBuilders.kt:1)
	at kotlinx.coroutines.test.TestBuildersKt__TestBuildersKt.runTest-8Mi8wO0(TestBuilders.kt:167)
	at kotlinx.coroutines.test.TestBuildersKt.runTest-8Mi8wO0(TestBuilders.kt:1)
	at kotlinx.coroutines.test.TestBuildersKt__TestBuildersKt.runTest-8Mi8wO0$default(TestBuilders.kt:159)
	at kotlinx.coroutines.test.TestBuildersKt.runTest-8Mi8wO0$default(TestBuilders.kt:1)
	at org.meshtastic.core.database.DatabaseManagerWithDbRetryTest.withDb retries against current database when previous pool closes during switch(DatabaseManagerWithDbRetryTest.kt:69)
	at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
	at java.base/java.lang.reflect.Method.invoke(Method.java:580)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
	at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
	at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
	at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
	at org.robolectric.RobolectricTestRunner$HelperTestRunner$1.evaluate(RobolectricTestRunner.java:524)
	at org.robolectric.internal.SandboxTestRunner.executeInSandbox(SandboxTestRunner.java:494)
	at org.robolectric.internal.SandboxTestRunner.access$900(SandboxTestRunner.java:67)
	at org.robolectric.internal.SandboxTestRunner$7.evaluate(SandboxTestRunner.java:442)
	at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
	at org.robolectric.internal.SandboxTestRunner.access$600(SandboxTestRunner.java:67)
	at org.robolectric.internal.SandboxTestRunner$6.evaluate(SandboxTestRunner.java:333)
	at org.robolectric.internal.SandboxTestRunner$3.evaluate(SandboxTestRunner.java:233)
	at org.robolectric.internal.SandboxTestRunner$5.lambda$evaluate$0(SandboxTestRunner.java:317)
	at org.robolectric.internal.bytecode.Sandbox.lambda$runOnMainThread$0(Sandbox.java:101)
	at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)
	at java.base/java.lang.Thread.run(Thread.java:1583)

To view more test analytics, go to the Test Analytics Dashboard
📋 Got 3 mins? Take this short survey to help us improve Test Analytics.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants