Skip to content

Commit

Permalink
Synchronize registrations in ChartEntryModelProducer
Browse files Browse the repository at this point in the history
Co-authored-by: Patrick Michalik <[email protected]>
  • Loading branch information
Gowsky and patrickmichalik committed Nov 26, 2024
1 parent 4b19817 commit 720d6a5
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 20 deletions.
2 changes: 2 additions & 0 deletions .idea/detekt-config.yml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,21 @@ import com.patrykandpatrick.vico.core.chart.values.ChartValuesProvider
import com.patrykandpatrick.vico.core.entry.diff.ExtraStore
import com.patrykandpatrick.vico.core.entry.diff.MutableExtraStore
import com.patrykandpatrick.vico.core.extension.copy
import java.util.concurrent.ConcurrentHashMap
import kotlinx.coroutines.CompletableDeferred
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Deferred
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.currentCoroutineContext
import kotlinx.coroutines.ensureActive
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock

/**
* A [ChartModelProducer] implementation that generates [ChartEntryModel] instances.
Expand All @@ -51,8 +55,9 @@ public class ChartEntryModelProducer(
private var cachedInternalModel: InternalModel? = null
private val mutex = Mutex()
private val coroutineScope = CoroutineScope(dispatcher)
private val updateReceivers: HashMap<Any, UpdateReceiver> = HashMap()
private val updateReceivers = ConcurrentHashMap<Any, UpdateReceiver>()
private val extraStore = MutableExtraStore()
private val registrationLock = Mutex()

public constructor(
vararg entryCollections: List<ChartEntry>,
Expand Down Expand Up @@ -95,15 +100,16 @@ public class ChartEntryModelProducer(
updateExtras: (MutableExtraStore) -> Unit = {},
): Deferred<Unit> {
mutex.lock()
series = entries.copy()
updateExtras(extraStore)
cachedInternalModel = null
registrationLock.lock()
val completableDeferred = CompletableDeferred<Unit>()
val deferredUpdates = updateReceivers.values.map { updateReceiver ->
coroutineScope.async { updateReceiver.handleUpdate() }
}
coroutineScope.launch {
deferredUpdates.awaitAll()
series = entries.copy()
updateExtras(extraStore)
cachedInternalModel = null
coroutineScope {
updateReceivers.values.forEach { updateReceiver -> launch { updateReceiver.handleUpdate() } }
registrationLock.unlock()
}
mutex.unlock()
completableDeferred.complete(Unit)
}
Expand Down Expand Up @@ -200,8 +206,12 @@ public class ChartEntryModelProducer(
getOldModel,
updateChartValues,
).run {
updateReceivers[key] = this
handleUpdate()
runBlocking {
registrationLock.withLock {
updateReceivers[key] = this@run
handleUpdate()
}
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,17 +32,21 @@ import com.patrykandpatrick.vico.core.entry.yRange
import com.patrykandpatrick.vico.core.extension.copy
import com.patrykandpatrick.vico.core.extension.gcdWith
import com.patrykandpatrick.vico.core.extension.setAll
import java.util.concurrent.ConcurrentHashMap
import kotlinx.coroutines.CompletableDeferred
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.currentCoroutineContext
import kotlinx.coroutines.Deferred
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll
import kotlinx.coroutines.currentCoroutineContext
import kotlinx.coroutines.ensureActive
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock

/**
* A [ChartModelProducer] implementation that generates [ComposedChartEntryModel] instances.
Expand All @@ -57,8 +61,9 @@ public class ComposedChartEntryModelProducer private constructor(dispatcher: Cor
private var cachedInternalComposedModel: InternalComposedModel? = null
private val mutex = Mutex()
private val coroutineScope = CoroutineScope(dispatcher)
private val updateReceivers = mutableMapOf<Any, UpdateReceiver>()
private val updateReceivers = ConcurrentHashMap<Any, UpdateReceiver>()
private val extraStore = MutableExtraStore()
private val registrationLock = Mutex()

private fun setDataSets(dataSets: List<List<List<ChartEntry>>>): Boolean {
if (!mutex.tryLock()) return false
Expand All @@ -76,14 +81,15 @@ public class ComposedChartEntryModelProducer private constructor(dispatcher: Cor

private suspend fun setDataSetsSuspending(dataSets: List<List<List<ChartEntry>>>): Deferred<Unit> {
mutex.lock()
this.dataSets = dataSets.copy()
cachedInternalComposedModel = null
registrationLock.lock()
val completableDeferred = CompletableDeferred<Unit>()
val deferredUpdates = updateReceivers.values.map { updateReceiver ->
coroutineScope.async { updateReceiver.handleUpdate() }
}
coroutineScope.launch {
deferredUpdates.awaitAll()
this@ComposedChartEntryModelProducer.dataSets = dataSets.copy()
cachedInternalComposedModel = null
coroutineScope {
updateReceivers.values.forEach { updateReceiver -> launch { updateReceiver.handleUpdate() } }
registrationLock.unlock()
}
mutex.unlock()
completableDeferred.complete(Unit)
}
Expand Down Expand Up @@ -185,8 +191,12 @@ public class ComposedChartEntryModelProducer private constructor(dispatcher: Cor
getOldModel,
updateChartValues,
).run {
updateReceivers[key] = this
handleUpdate()
runBlocking {
registrationLock.withLock {
updateReceivers[key] = this@run
handleUpdate()
}
}
}
}

Expand Down

0 comments on commit 720d6a5

Please sign in to comment.