Arsen
10/30/2021, 10:56 PMval catsState = mutableStateListOf<Cat>()
val sortState = mutableStateOf("ASC") // [ASC, DESC]
// ------ Worker Thread ---------
val snapshot = Snapshot.takeMutableSnapshot()
val sort = sortState.value
val cats = fetchCoolCatsFromNetwork(sort)
snapshot.enter {
catsState.clear()
catsState.addAll(cats)
Snapshot.lockOnGlobalSnapshot { // Does it possible?
val sortOfActualGlobalSnapshot = sortState.value
if(sortOfActualGlobalSnapshot == sort) {
snapshot.apply()
} else {
snapshot.dispose()
}
}
}
P.S. State hoisted to ViewModelZach Klippenstein (he/him) [MOD]
11/01/2021, 5:17 PMArsen
11/01/2021, 6:51 PMZach Klippenstein (he/him) [MOD]
11/01/2021, 10:14 PMChuck Jazdzewski [G]
11/02/2021, 5:11 PMPair
of values, or similar, to ensure they are consistent with each other.
Using the mutation policy is the correct mechanism as it is called during apply
and works with nested snapshots (which lockOnGlobalSnapshot
wouldn't) so it can be used to ensure that order of the sort requested is consistent with the order of the sort retrieved. To accomplish this, for example, the mutation policy for a Pair
would allow states to merge if the first
fields are identical (the sort order) and the second
field goes from null
to a value (the collection). It would then return the record with the non-null value. If the current sort order is not consistent with the collection then the apply fails. The worker thread can then check apply result and re-query the server for a new collection if the apply
fails.
I am on vacation now or I would provide an example of this. I am back on Monday.
The snapshot system guarantees snapshot consistency not serialization. A note about this is in the internal comment for the apply
method and references the following paper that describes a crossing write (the technical description of what your code is an example of) https://arxiv.org/pdf/1412.2324.pdf. Code that requires crossing-write consistency (i.e. serialization) is not currently supported as supporting them would be rather expensive. Snapshot consistency requires consistency requirements be expressed in terms of consistent writes which using a Pair
as described above does.
A quibble with your example: a snapshot should always have its dispose()
called. Disposing a snapshot that has not been applied will discard any changes in the snapshot; however, an applied snapshot should also be disposed. Not disposing of a snapshot can be a serious memory leak as it might cause accumulation of state records that cannot be reused. This typically doesn't happen in the example you have (since it is a child of the global snapshot) but nested snapshots keep their parents in, at minimum, a zombie state if they are not disposed.Arsen
11/30/2021, 1:59 AMChuck Jazdzewski [G]
11/30/2021, 2:10 AMtakeSerializableSnapshot()
that tracks reads without slowing down the cases that don't need this serializable consistency.