Temporarily disabled change sets until the bug is figured out.

This commit is contained in:
Daan Vanden Bosch 2021-06-19 16:34:47 +02:00
parent f228fda979
commit a774ad4e00
3 changed files with 125 additions and 110 deletions

View File

@ -4,19 +4,22 @@ object ChangeManager {
private var currentChangeSet: ChangeSet? = null private var currentChangeSet: ChangeSet? = null
fun inChangeSet(block: () -> Unit) { fun inChangeSet(block: () -> Unit) {
val existingChangeSet = currentChangeSet // TODO: Figure out change set bug and enable change sets again.
val changeSet = existingChangeSet ?: ChangeSet().also { // val existingChangeSet = currentChangeSet
currentChangeSet = it // val changeSet = existingChangeSet ?: ChangeSet().also {
} // currentChangeSet = it
// }
try { //
// try {
block() block()
} finally { // } finally {
if (existingChangeSet == null) { // if (existingChangeSet == null) {
currentChangeSet = null // // Set to null so changed calls are turned into emitDependencyChanged calls
changeSet.complete() // // immediately instead of being deferred.
} // currentChangeSet = null
} // changeSet.complete()
// }
// }
} }
fun changed(dependency: Dependency) { fun changed(dependency: Dependency) {
@ -31,15 +34,24 @@ object ChangeManager {
} }
private class ChangeSet { private class ChangeSet {
private var completing = false
private val changedDependencies: MutableList<Dependency> = mutableListOf() private val changedDependencies: MutableList<Dependency> = mutableListOf()
fun changed(dependency: Dependency) { fun changed(dependency: Dependency) {
check(!completing)
changedDependencies.add(dependency) changedDependencies.add(dependency)
} }
fun complete() { fun complete() {
try {
completing = true
for (dependency in changedDependencies) { for (dependency in changedDependencies) {
dependency.emitDependencyChanged() dependency.emitDependencyChanged()
} }
} finally {
completing = false
}
} }
} }

View File

@ -31,8 +31,8 @@ abstract class AbstractDependentCell<T> : AbstractCell<T>(), Dependent {
override fun emitDependencyChanged() { override fun emitDependencyChanged() {
// Nothing to do because dependent cells emit dependencyChanged immediately. They don't // Nothing to do because dependent cells emit dependencyChanged immediately. They don't
// defer this operation because they only change when there is no transaction or the current // defer this operation because they only change when there is no change set or the current
// transaction is being committed. // change set is being completed.
} }
protected abstract fun dependenciesChanged() protected abstract fun dependenciesChanged()

View File

@ -29,114 +29,117 @@ interface MutableCellTests<T : Any> : CellTests {
assertEquals(newValue, observedValue) assertEquals(newValue, observedValue)
} }
// TODO: Figure out change set bug and enable change sets again.
/** /**
* Modifying mutable cells in a change set doesn't result in calls to * Modifying mutable cells in a change set doesn't result in calls to
* [Dependent.dependencyChanged] of their dependents until the change set is completed. * [Dependent.dependencyChanged] of their dependents until the change set is completed.
*/ */
@Test // @Test
fun cell_changes_in_change_set_dont_immediately_produce_dependencyChanged_calls() = test { // fun cell_changes_in_change_set_dont_immediately_produce_dependencyChanged_calls() = test {
val dependencies = (1..5).map { createProvider() } // val dependencies = (1..5).map { createProvider() }
//
var dependencyMightChangeCount = 0 // var dependencyMightChangeCount = 0
var dependencyChangedCount = 0 // var dependencyChangedCount = 0
//
val dependent = object : Dependent { // val dependent = object : Dependent {
override fun dependencyMightChange() { // override fun dependencyMightChange() {
dependencyMightChangeCount++ // dependencyMightChangeCount++
} // }
//
override fun dependencyChanged(dependency: Dependency, event: ChangeEvent<*>?) { // override fun dependencyChanged(dependency: Dependency, event: ChangeEvent<*>?) {
dependencyChangedCount++ // dependencyChangedCount++
} // }
} // }
//
for (dependency in dependencies) { // for (dependency in dependencies) {
dependency.observable.addDependent(dependent) // dependency.observable.addDependent(dependent)
} // }
//
change { // change {
for (dependency in dependencies) { // for (dependency in dependencies) {
dependency.observable.value = dependency.createValue() // dependency.observable.value = dependency.createValue()
} // }
//
// Calls to dependencyMightChange happen immediately. // // Calls to dependencyMightChange happen immediately.
assertEquals(dependencies.size, dependencyMightChangeCount) // assertEquals(dependencies.size, dependencyMightChangeCount)
// Calls to dependencyChanged happen later. // // Calls to dependencyChanged happen later.
assertEquals(0, dependencyChangedCount) // assertEquals(0, dependencyChangedCount)
} // }
//
assertEquals(dependencies.size, dependencyMightChangeCount) // assertEquals(dependencies.size, dependencyMightChangeCount)
assertEquals(dependencies.size, dependencyChangedCount) // assertEquals(dependencies.size, dependencyChangedCount)
} // }
// TODO: Figure out change set bug and enable change sets again.
/** /**
* Modifying a mutable cell multiple times in one change set results in a single call to * Modifying a mutable cell multiple times in one change set results in a single call to
* [Dependent.dependencyMightChange] and [Dependent.dependencyChanged]. * [Dependent.dependencyMightChange] and [Dependent.dependencyChanged].
*/ */
@Test // @Test
fun multiple_changes_to_one_cell_in_change_set() = test { // fun multiple_changes_to_one_cell_in_change_set() = test {
val dependency = createProvider() // val dependency = createProvider()
//
var dependencyMightChangeCount = 0 // var dependencyMightChangeCount = 0
var dependencyChangedCount = 0 // var dependencyChangedCount = 0
//
val dependent = object : Dependent { // val dependent = object : Dependent {
override fun dependencyMightChange() { // override fun dependencyMightChange() {
dependencyMightChangeCount++ // dependencyMightChangeCount++
} // }
//
override fun dependencyChanged(dependency: Dependency, event: ChangeEvent<*>?) { // override fun dependencyChanged(dependency: Dependency, event: ChangeEvent<*>?) {
dependencyChangedCount++ // dependencyChangedCount++
} // }
} // }
//
dependency.observable.addDependent(dependent) // dependency.observable.addDependent(dependent)
//
// Change the dependency multiple times in a transaction. // // Change the dependency multiple times in a transaction.
change { // change {
repeat(5) { // repeat(5) {
dependency.observable.value = dependency.createValue() // dependency.observable.value = dependency.createValue()
} // }
//
// Calls to dependencyMightChange happen immediately. // // Calls to dependencyMightChange happen immediately.
assertEquals(1, dependencyMightChangeCount) // assertEquals(1, dependencyMightChangeCount)
// Calls to dependencyChanged happen later. // // Calls to dependencyChanged happen later.
assertEquals(0, dependencyChangedCount) // assertEquals(0, dependencyChangedCount)
} // }
//
assertEquals(1, dependencyMightChangeCount) // assertEquals(1, dependencyMightChangeCount)
assertEquals(1, dependencyChangedCount) // assertEquals(1, dependencyChangedCount)
} // }
// TODO: Figure out change set bug and enable change sets again.
/** /**
* Modifying two mutable cells in a change set results in a single recomputation of their * Modifying two mutable cells in a change set results in a single recomputation of their
* dependent. * dependent.
*/ */
@Test // @Test
fun modifying_two_cells_together_results_in_one_recomputation() = test { // fun modifying_two_cells_together_results_in_one_recomputation() = test {
val dependency1 = createProvider() // val dependency1 = createProvider()
val dependency2 = createProvider() // val dependency2 = createProvider()
//
var computeCount = 0 // var computeCount = 0
//
val dependent = DependentCell(dependency1.observable, dependency2.observable) { // val dependent = DependentCell(dependency1.observable, dependency2.observable) {
computeCount++ // computeCount++
Unit // Unit
} // }
//
// Observe dependent to ensure it gets recomputed when its dependencies change. // // Observe dependent to ensure it gets recomputed when its dependencies change.
disposer.add(dependent.observe {}) // disposer.add(dependent.observe {})
//
// DependentCell's compute function is called once when we start observing. // // DependentCell's compute function is called once when we start observing.
assertEquals(1, computeCount) // assertEquals(1, computeCount)
//
change { // change {
dependency1.observable.value = dependency1.createValue() // dependency1.observable.value = dependency1.createValue()
dependency2.observable.value = dependency2.createValue() // dependency2.observable.value = dependency2.createValue()
} // }
//
assertEquals(2, computeCount) // assertEquals(2, computeCount)
} // }
interface Provider<T : Any> : CellTests.Provider { interface Provider<T : Any> : CellTests.Provider {
override val observable: MutableCell<T> override val observable: MutableCell<T>