mirror of
https://github.com/signalapp/Signal-Android.git
synced 2025-12-20 19:18:37 +00:00
@@ -5,8 +5,7 @@
|
|||||||
|
|
||||||
package org.thoughtcrime.securesms.backup.v2
|
package org.thoughtcrime.securesms.backup.v2
|
||||||
|
|
||||||
import org.signal.core.util.ThreadUtil
|
import androidx.annotation.VisibleForTesting
|
||||||
import org.signal.core.util.concurrent.SignalExecutors
|
|
||||||
import org.thoughtcrime.securesms.dependencies.AppDependencies
|
import org.thoughtcrime.securesms.dependencies.AppDependencies
|
||||||
import org.thoughtcrime.securesms.util.ThrottledDebouncer
|
import org.thoughtcrime.securesms.util.ThrottledDebouncer
|
||||||
import java.util.concurrent.ExecutionException
|
import java.util.concurrent.ExecutionException
|
||||||
@@ -19,7 +18,10 @@ import kotlin.time.Duration.Companion.seconds
|
|||||||
*/
|
*/
|
||||||
object ArchiveDatabaseExecutor {
|
object ArchiveDatabaseExecutor {
|
||||||
|
|
||||||
val executor = Executors.newSingleThreadExecutor(SignalExecutors.NumberedThreadFactory("archive-db", ThreadUtil.PRIORITY_IMPORTANT_BACKGROUND_THREAD))
|
@VisibleForTesting
|
||||||
|
const val THREAD_NAME = "archive-db"
|
||||||
|
|
||||||
|
private val executor = Executors.newSingleThreadExecutor { Thread(it, THREAD_NAME) }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* By default, downloading/uploading an attachment wants to notify a bunch of database observation listeners. This slams the observer so hard that other
|
* By default, downloading/uploading an attachment wants to notify a bunch of database observation listeners. This slams the observer so hard that other
|
||||||
@@ -39,6 +41,10 @@ object ArchiveDatabaseExecutor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun <T> runBlocking(block: () -> T): T {
|
fun <T> runBlocking(block: () -> T): T {
|
||||||
|
if (Thread.currentThread().name.equals(THREAD_NAME)) {
|
||||||
|
return block()
|
||||||
|
}
|
||||||
|
|
||||||
return try {
|
return try {
|
||||||
executor.submit(block).get()
|
executor.submit(block).get()
|
||||||
} catch (e: ExecutionException) {
|
} catch (e: ExecutionException) {
|
||||||
|
|||||||
@@ -360,11 +360,9 @@ class UploadAttachmentToArchiveJob private constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun setArchiveTransferStateWithDelayedNotification(attachmentId: AttachmentId, transferState: AttachmentTable.ArchiveTransferState) {
|
private fun setArchiveTransferStateWithDelayedNotification(attachmentId: AttachmentId, transferState: AttachmentTable.ArchiveTransferState) {
|
||||||
ArchiveDatabaseExecutor.runBlocking {
|
|
||||||
SignalDatabase.attachments.setArchiveTransferState(attachmentId, transferState, notify = false)
|
SignalDatabase.attachments.setArchiveTransferState(attachmentId, transferState, notify = false)
|
||||||
ArchiveDatabaseExecutor.throttledNotifyAttachmentObservers()
|
ArchiveDatabaseExecutor.throttledNotifyAttachmentObservers()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
class Factory : Job.Factory<UploadAttachmentToArchiveJob> {
|
class Factory : Job.Factory<UploadAttachmentToArchiveJob> {
|
||||||
override fun create(parameters: Parameters, serializedData: ByteArray?): UploadAttachmentToArchiveJob {
|
override fun create(parameters: Parameters, serializedData: ByteArray?): UploadAttachmentToArchiveJob {
|
||||||
|
|||||||
@@ -0,0 +1,66 @@
|
|||||||
|
package org.thoughtcrime.securesms.backup.v2
|
||||||
|
|
||||||
|
import android.app.Application
|
||||||
|
import assertk.assertThat
|
||||||
|
import assertk.assertions.isEqualTo
|
||||||
|
import assertk.assertions.isTrue
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
import org.robolectric.RobolectricTestRunner
|
||||||
|
import org.robolectric.annotation.Config
|
||||||
|
import java.util.concurrent.CountDownLatch
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean
|
||||||
|
import java.util.concurrent.atomic.AtomicReference
|
||||||
|
|
||||||
|
@RunWith(RobolectricTestRunner::class)
|
||||||
|
@Config(manifest = Config.NONE, application = Application::class)
|
||||||
|
class ArchiveDatabaseExecutorTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `runBlocking returns the result of the block`() {
|
||||||
|
val result = ArchiveDatabaseExecutor.runBlocking {
|
||||||
|
42
|
||||||
|
}
|
||||||
|
|
||||||
|
assertThat(result).isEqualTo(42)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `nested runBlocking calls do not deadlock`() {
|
||||||
|
val completed = AtomicBoolean(false)
|
||||||
|
val result = AtomicReference<String>()
|
||||||
|
val latch = CountDownLatch(1)
|
||||||
|
|
||||||
|
Thread {
|
||||||
|
try {
|
||||||
|
val r = ArchiveDatabaseExecutor.runBlocking {
|
||||||
|
ArchiveDatabaseExecutor.runBlocking {
|
||||||
|
ArchiveDatabaseExecutor.runBlocking {
|
||||||
|
"nested-result"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result.set(r)
|
||||||
|
completed.set(true)
|
||||||
|
} finally {
|
||||||
|
latch.countDown()
|
||||||
|
}
|
||||||
|
}.start()
|
||||||
|
|
||||||
|
val finishedInTime = latch.await(5, TimeUnit.SECONDS)
|
||||||
|
|
||||||
|
assertThat(finishedInTime).isTrue()
|
||||||
|
assertThat(completed.get()).isTrue()
|
||||||
|
assertThat(result.get()).isEqualTo("nested-result")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `runBlocking executes on archive-db thread`() {
|
||||||
|
val threadName = ArchiveDatabaseExecutor.runBlocking {
|
||||||
|
Thread.currentThread().name
|
||||||
|
}
|
||||||
|
|
||||||
|
assertThat(threadName).isEqualTo(ArchiveDatabaseExecutor.THREAD_NAME)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user