From 976c9dd064f723130ec5d74424fff059ee7a5e3f Mon Sep 17 00:00:00 2001 From: Harsh Shandilya Date: Tue, 11 Mar 2025 17:32:56 +0530 Subject: [PATCH] feat: separate db reads and writes to separate dispatchers --- .../android/viewmodel/CommentsRepository.kt | 10 ++++++---- .../android/viewmodel/ReadPostsRepository.kt | 10 ++++++---- .../android/viewmodel/SavedPostsRepository.kt | 14 ++++++++------ .../claw/core/coroutines/DispatcherProvider.kt | 7 +++++-- .../core/injection/CoroutineDispatcherModule.kt | 17 +++++++++++++---- 5 files changed, 38 insertions(+), 20 deletions(-) diff --git a/android/src/main/kotlin/dev/msfjarvis/claw/android/viewmodel/CommentsRepository.kt b/android/src/main/kotlin/dev/msfjarvis/claw/android/viewmodel/CommentsRepository.kt index 091911af..6959beea 100644 --- a/android/src/main/kotlin/dev/msfjarvis/claw/android/viewmodel/CommentsRepository.kt +++ b/android/src/main/kotlin/dev/msfjarvis/claw/android/viewmodel/CommentsRepository.kt @@ -6,7 +6,8 @@ */ package dev.msfjarvis.claw.android.viewmodel -import dev.msfjarvis.claw.core.injection.DatabaseDispatcher +import dev.msfjarvis.claw.core.injection.DatabaseReadDispatcher +import dev.msfjarvis.claw.core.injection.DatabaseWriteDispatcher import dev.msfjarvis.claw.database.local.PostComments import dev.msfjarvis.claw.database.local.PostCommentsQueries import dev.msfjarvis.claw.model.Comment @@ -18,14 +19,15 @@ class CommentsRepository @Inject constructor( private val postCommentsQueries: PostCommentsQueries, - @DatabaseDispatcher private val dbDispatcher: CoroutineDispatcher, + @DatabaseReadDispatcher private val readDispatcher: CoroutineDispatcher, + @DatabaseWriteDispatcher private val writeDispatcher: CoroutineDispatcher, ) { suspend fun getSeenComments(postId: String) = - withContext(dbDispatcher) { postCommentsQueries.getCommentIds(postId).executeAsOneOrNull() } + withContext(readDispatcher) { postCommentsQueries.getCommentIds(postId).executeAsOneOrNull() } suspend fun markSeenComments(postId: String, comments: List) { - withContext(dbDispatcher) { + withContext(writeDispatcher) { postCommentsQueries.rememberComments(PostComments(postId, comments.map { it.shortId })) } } diff --git a/android/src/main/kotlin/dev/msfjarvis/claw/android/viewmodel/ReadPostsRepository.kt b/android/src/main/kotlin/dev/msfjarvis/claw/android/viewmodel/ReadPostsRepository.kt index 9dcf0554..d824a0fd 100644 --- a/android/src/main/kotlin/dev/msfjarvis/claw/android/viewmodel/ReadPostsRepository.kt +++ b/android/src/main/kotlin/dev/msfjarvis/claw/android/viewmodel/ReadPostsRepository.kt @@ -8,7 +8,8 @@ package dev.msfjarvis.claw.android.viewmodel import app.cash.sqldelight.coroutines.asFlow import app.cash.sqldelight.coroutines.mapToList -import dev.msfjarvis.claw.core.injection.DatabaseDispatcher +import dev.msfjarvis.claw.core.injection.DatabaseReadDispatcher +import dev.msfjarvis.claw.core.injection.DatabaseWriteDispatcher import dev.msfjarvis.claw.database.local.ReadPostsQueries import javax.inject.Inject import kotlinx.coroutines.CoroutineDispatcher @@ -18,11 +19,12 @@ class ReadPostsRepository @Inject constructor( private val readPostsQueries: ReadPostsQueries, - @DatabaseDispatcher private val dbDispatcher: CoroutineDispatcher, + @DatabaseReadDispatcher private val readDispatcher: CoroutineDispatcher, + @DatabaseWriteDispatcher private val writeDispatcher: CoroutineDispatcher, ) { - val readPosts = readPostsQueries.selectAllPosts().asFlow().mapToList(dbDispatcher) + val readPosts = readPostsQueries.selectAllPosts().asFlow().mapToList(readDispatcher) suspend fun markRead(postId: String) { - withContext(dbDispatcher) { readPostsQueries.markRead(postId) } + withContext(writeDispatcher) { readPostsQueries.markRead(postId) } } } diff --git a/android/src/main/kotlin/dev/msfjarvis/claw/android/viewmodel/SavedPostsRepository.kt b/android/src/main/kotlin/dev/msfjarvis/claw/android/viewmodel/SavedPostsRepository.kt index fd50ee10..63f6a9f0 100644 --- a/android/src/main/kotlin/dev/msfjarvis/claw/android/viewmodel/SavedPostsRepository.kt +++ b/android/src/main/kotlin/dev/msfjarvis/claw/android/viewmodel/SavedPostsRepository.kt @@ -8,7 +8,8 @@ package dev.msfjarvis.claw.android.viewmodel import app.cash.sqldelight.coroutines.asFlow import app.cash.sqldelight.coroutines.mapToList -import dev.msfjarvis.claw.core.injection.DatabaseDispatcher +import dev.msfjarvis.claw.core.injection.DatabaseReadDispatcher +import dev.msfjarvis.claw.core.injection.DatabaseWriteDispatcher import dev.msfjarvis.claw.database.local.SavedPost import dev.msfjarvis.claw.database.local.SavedPostQueries import dev.msfjarvis.claw.model.UIPost @@ -23,23 +24,24 @@ class SavedPostsRepository @Inject constructor( private val savedPostQueries: SavedPostQueries, - @DatabaseDispatcher private val dbDispatcher: CoroutineDispatcher, + @DatabaseReadDispatcher private val readDispatcher: CoroutineDispatcher, + @DatabaseWriteDispatcher private val writeDispatcher: CoroutineDispatcher, ) { - val savedPosts = savedPostQueries.selectAllPosts().asFlow().mapToList(dbDispatcher) + val savedPosts = savedPostQueries.selectAllPosts().asFlow().mapToList(readDispatcher) suspend fun toggleSave(post: UIPost) { if (savedPosts.firstOrNull().orEmpty().any { it.shortId == post.shortId }) { Napier.d(tag = TAG) { "Removing post: ${post.shortId}" } - withContext(dbDispatcher) { savedPostQueries.deletePost(post.shortId) } + withContext(writeDispatcher) { savedPostQueries.deletePost(post.shortId) } } else { Napier.d(tag = TAG) { "Saving post: ${post.shortId}" } - withContext(dbDispatcher) { savedPostQueries.insertOrReplacePost(post.toSavedPost()) } + withContext(writeDispatcher) { savedPostQueries.insertOrReplacePost(post.toSavedPost()) } } } suspend fun savePosts(posts: List) { Napier.d(tag = TAG) { "Saving posts: ${posts.joinToString(",") { it.shortId }}" } - withContext(dbDispatcher) { + withContext(writeDispatcher) { savedPostQueries.transaction { posts.forEach { post -> savedPostQueries.insertOrReplacePost(post) } } diff --git a/core/src/main/kotlin/dev/msfjarvis/claw/core/coroutines/DispatcherProvider.kt b/core/src/main/kotlin/dev/msfjarvis/claw/core/coroutines/DispatcherProvider.kt index 66550c58..3e2c43a6 100644 --- a/core/src/main/kotlin/dev/msfjarvis/claw/core/coroutines/DispatcherProvider.kt +++ b/core/src/main/kotlin/dev/msfjarvis/claw/core/coroutines/DispatcherProvider.kt @@ -21,8 +21,11 @@ interface DispatcherProvider { fun io(): CoroutineDispatcher = Dispatchers.IO - fun database(): CoroutineDispatcher = - Dispatchers.IO.limitedParallelism(1, name = "DatabaseDispatcher") + fun databaseRead(): CoroutineDispatcher = + Dispatchers.IO.limitedParallelism(4, name = "DatabaseRead") + + fun databaseWrite(): CoroutineDispatcher = + Dispatchers.IO.limitedParallelism(1, name = "DatabaseWrite") } /** Concrete type for [DispatcherProvider] with all the defaults from the class. */ diff --git a/core/src/main/kotlin/dev/msfjarvis/claw/core/injection/CoroutineDispatcherModule.kt b/core/src/main/kotlin/dev/msfjarvis/claw/core/injection/CoroutineDispatcherModule.kt index ca2ab0c6..8bf91dd2 100644 --- a/core/src/main/kotlin/dev/msfjarvis/claw/core/injection/CoroutineDispatcherModule.kt +++ b/core/src/main/kotlin/dev/msfjarvis/claw/core/injection/CoroutineDispatcherModule.kt @@ -16,7 +16,9 @@ import dev.msfjarvis.claw.core.coroutines.DispatcherProvider import javax.inject.Qualifier import kotlinx.coroutines.CoroutineDispatcher -@Qualifier @Retention(AnnotationRetention.RUNTIME) annotation class DatabaseDispatcher +@Qualifier @Retention(AnnotationRetention.RUNTIME) annotation class DatabaseReadDispatcher + +@Qualifier @Retention(AnnotationRetention.RUNTIME) annotation class DatabaseWriteDispatcher @Qualifier @Retention(AnnotationRetention.RUNTIME) annotation class MainDispatcher @@ -36,9 +38,16 @@ interface CoroutineDispatcherModule { return dispatcherProvider.io() } - @[Provides DatabaseDispatcher] - fun provideDatabaseDispatcher(dispatcherProvider: DispatcherProvider): CoroutineDispatcher { - return dispatcherProvider.database() + @[Provides DatabaseReadDispatcher] + fun provideDatabaseReadDispatcher(dispatcherProvider: DispatcherProvider): CoroutineDispatcher { + return dispatcherProvider.databaseRead() + } + + @[Provides DatabaseWriteDispatcher] + fun provideDatabaseWriteDispatcher( + dispatcherProvider: DispatcherProvider + ): CoroutineDispatcher { + return dispatcherProvider.databaseWrite() } @[Provides MainDispatcher]