The version of the Model Relay system delivered for
FLUID-5114 etc. implemented what could be called a "belt and braces" approach to oscillation prevention. Firstly SCHEME I there is the inbuilt "caution" of the system in only recognising changes where model values genuinely altered - this was backed up by utilities like "fluid.model.isSameValue" which allows a certain "floating point slop" so that changes are not recognised where they simply result from floating point imprecision in running a transform such as fluid.transform.linearScale backwards and forwards over the same values. Secondly SCHEME II there was a "link counting system" that would update and track update counts associated with each linkage (relay) as well as each applier in the model skeleton. These counts were "per transaction" and were periodically reset when it was determined that "fresh data" had entered the transaction.
Unfortunately a test case supplied for
FLUID-5293 revealed that the link counting scheme in its current form at least is overly aggressive. It propagated a single array value which was mapped by transformation to a set of two booleans. After the updates for the first boolean were processed, all the link counts were saturated and the update relay for the second one would not be processed.
Here is the relevant content of the test case - the relay is set up as follows:
and the requested change is
that.applier.requestChange("accessibilityHazard", ["flashing", "noflashing"]);
This should relay onto two boolean flags of "true" but after the first relay, the link counts are saturated and the 2nd one is not honoured.
Given that this "explosion" of values occurred internally, during the course of model transformation, it would be hard to express or account for the fact that each exploded value independently represented "fresh data" - the model transform system simply relays a set of changes to fluid.requestChanges and these show up directly in fluid.registerDirectChangeRelay's "sourceListener" - such explosion could occur at any sub-step of propagating a model update through the skeleton and it becomes unclear what this notion of "freshness" could be considered relative to.
In practice it seems that the quality of the relay system has improved sufficiently that we can just defer to SCHEME I for preventing infinite propagation in practice - even though the system may now take a little longer to stabilise when it could rely on link counting. The fix to
FLUID-5293 currently consists of disabling the link count check in "sourceListener" since it seems that everything currently works well without it.
We should rethink whether we can come up with some more subtle notion of "freshness" other than just "a fresh value external to the current model skeleton", or whether we can just remove link counting entirely. The danger is that some new class of model transformation emerges that cannot invert itself properly, and thus causes an infinite loop with the current implementation. The "belt and braces" (SCHEME II) approach was designed to make the system stable in the face of such transforms, but it seems we must disable at least the current version of link counting for now. If we could eliminate it entirely, it would certainly substantially simplify the implementation.