From 628ba87c54d87f7b5443489ae2dc054e3a9a238b Mon Sep 17 00:00:00 2001 From: Tony Garnock-Jones Date: Fri, 13 May 2016 20:13:09 -0400 Subject: [PATCH] Rewrite JS DemandMatcher to handle important latency-related corner cases. --- doc/demand-matcher.dot | 57 ++++++ doc/demand-matcher.md | 376 +++++++++++++++++++++++++++++++++++++++ doc/demand-matcher.png | Bin 0 -> 71057 bytes js/src/broker.js | 8 +- js/src/demand-matcher.js | 236 ++++++++++++++---------- js/src/timer-driver.js | 12 +- js/src/ui.js | 18 +- 7 files changed, 590 insertions(+), 117 deletions(-) create mode 100644 doc/demand-matcher.dot create mode 100644 doc/demand-matcher.md create mode 100644 doc/demand-matcher.png diff --git a/doc/demand-matcher.dot b/doc/demand-matcher.dot new file mode 100644 index 0000000..4ba3941 --- /dev/null +++ b/doc/demand-matcher.dot @@ -0,0 +1,57 @@ +digraph G { + node[shape=box]; + + // s0000 idle + // s1000 error + // s0100 supply + // s1100 running + // s1010 starting + // s0011 starting_unwanted + // s1011 starting_doomed + // s0101 unwanted + // s1101 running_doomed + + idle -> starting [label="D+/start"]; + supply -> starting [label="D+,S-/start"]; + error -> idle [label="D-"]; + error -> running [label="S+"]; + error -> unwanted [label="D-,S+"]; + running -> unwanted [label="D-"]; + running -> error [label="S-/error"]; + + unwanted -> idle [label="S-"]; + unwanted -> starting [label="D+,S-/start"]; + running_doomed -> starting [label="S-/start"]; + running_doomed -> idle [label="D-,S-"]; + + starting -> starting_unwanted [label="D-"]; + starting -> running [label="S+"]; + starting -> unwanted [label="D-,S+"]; + starting_unwanted -> unwanted [label="S+"]; + starting_unwanted -> running_doomed [label="D+,S+"]; + starting_doomed -> running_doomed [label="S+"]; + starting_doomed -> unwanted [label="D-,S+"]; + + + idle -> supply [label="S+"]; + idle -> running [label="D+S+"]; + supply -> running [label="D+"]; + supply -> idle [label="S-"]; + running -> idle [label="D-,S-"]; + unwanted -> running_doomed [label="D+"]; + running_doomed -> unwanted [label="D-"]; + starting_unwanted -> starting_doomed [label="D+"]; + starting_doomed -> starting_unwanted [label="D-"]; + + + // s0001 -> impossible [label="any"]; + // s0010 -> impossible [label="any"]; + + // s1001 -> impossible [label="any"]; + + // s0110 -> impossible [label="any"]; + // s1110 -> impossible [label="any"]; + // s0111 -> impossible [label="any"]; + // s1111 -> impossible [label="any"]; + +} \ No newline at end of file diff --git a/doc/demand-matcher.md b/doc/demand-matcher.md new file mode 100644 index 0000000..48e1e76 --- /dev/null +++ b/doc/demand-matcher.md @@ -0,0 +1,376 @@ +# Demand-matching and Supervision + +The Demand Matcher pattern (in `demand-matcher.rkt` and in +`demand-matcher.js`'s `DemandMatcher` class) tracks assertions +representing some abstract *demand* for a resource, and causes the +creation or acquisition of matching *supply* of that resource. + +To do this, it tracks the state of each *instance* of the resource. +Each resource instance (called a "task") is uniquely identified by a +projection of the dataspace. + +The basic idea is that: + + - When demand for a task is detected, it is started. + + - Each started task signals its presence to the DemandMatcher. + + - When demand drops, the task should detect this and exit. + + - If the task exits unexpectedly, this is an error, and the + DemandMatcher prints a warning. + +## Latency causes problems + +However, because there can be some latency between requesting the +start of a task and its signalling its presence to the DemandMatcher, +we can't just figure out what to do based on the presence or absence +of demand and supply for a task. We also need to track a few more bits +of information. + +When demand for a task drops briefly, we *expect* a drop in supply, +*even demand increases again before we detect a supply drop*. For this +reason, in some circumstances, the default task supervision strategy +of DemandMatcher *recreates* supply on supply drop in some +circumstances. It keeps track of whether a supply increase is +expected, and of whether a supply decrease is expected for each task. + +It becomes an important part of the DemandMatcher protocol for a task +instance to always drop its supply assertion in response to a drop in +demand. This works well in Syndicate implementations that preserve all +assertion transitions, but not at all well where brief transitions may +be elided. In those cases, we will have to reach for a more heuristic +approach involving something akin to Erlang's "Maximum Restart +Intensity" and/or other kinds of time-based decision. For now though, +the precise case works fine. + +While it seems simple enough to imagine, the details are rather +fiddly. + +## Working out the algorithm that defaultTaskSupervisor should use + +We may assume some expected task behaviour: that it will eventually +assert supply, and *then* upon demand drop eventually exit. + + ◇(supply ∧ (¬demand ⇒ ◇ terminate)) (?!?!) + +### Complete table of actions + +Each row in this table describes actions taken in a particular +circumstance by `defaultTaskSupervisor`. + +The table has seven columns: + - `∃D`, whether demand for the task exists currently + - `∃S`, whether supply for the task exists currently + - `ΔD`, whether (and in which direction) demand is changing now + - `ΔS`, whether (and in which direction) supply is changing now + - `expS+`, whether we expect a supply increase at some point in future + - `expS-`, whether we expect a supply decrease at some point in future + - and an action to take in this circumstance. + +The first two values are drawn from the state of the DemandMatcher; +the second two, from the patch event the DemandMatcher is currently +processing; and the third two are private state variables of the task +supervisor itself. + + ∃D ∃S ΔD ΔS expS+ expS- Action + --------------------------------------------------------------------------- + - - + - - Start task, set expS+ + - - + - - No action (but slightly weird) + - - + + - - No action (but slightly weird) + - Y + - - No action (pre-extant supply) + - Y - - - No action + - Y + - - - Start task, set expS+ + Y - - - - Demand goes after unexpected supply drop + Y - + - - Spontaneous recovery from unexpected supply drop + Y - - + - - Spontaneous recovery from unexpected supply drop; set expS- + Y Y - - - Set expS- + Y Y - - - Unexpected supply drop error + Y Y - - - - No action (but slightly weird) + + - - + - Y Impossible (expS- would be clear or expS+ set) + - - + - Y Impossible (expS- would be clear or expS+ set) + - - + + - Y Impossible (expS- would be clear or expS+ set) + - Y + - Y No action + - Y - - Y Clear expS- + - Y + - - Y Clear expS-, start task, set expS+ + Y - - - Y Impossible (expS+ would be set) + Y - + - Y Impossible (expS+ would be set) + Y - - + - Y Impossible (expS+ would be set) + Y Y - - Y No action + Y Y - - Y Clear expS-, start task, set expS+ + Y Y - - - Y Clear expS- + + - - + Y - Impossible (expS+ would be clear or expS- set) + - - + Y - Impossible (expS+ would be clear or expS- set) + - - + + Y - Impossible (expS+ would be clear or expS- set) + - Y + Y - Impossible (expS+ would be clear) + - Y - Y - Impossible (expS+ would be clear) + - Y + - Y - Impossible (expS+ would be clear) + Y - - Y - Set expS- + Y - + Y - Clear expS+ + Y - - + Y - Clear expS+, set expS- + Y Y - Y - Impossible (expS+ would be clear) + Y Y - Y - Impossible (expS+ would be clear) + Y Y - - Y - Impossible (expS+ would be clear) + + - - + Y Y No action + - - + Y Y Clear expS+ + - - + + Y Y Clear expS+ + - Y + Y Y Impossible (expS+ would be clear) + - Y - Y Y Impossible (expS+ would be clear) + - Y + - Y Y Impossible (expS+ would be clear) + Y - - Y Y No action + Y - + Y Y Clear expS+ + Y - - + Y Y Clear expS+ + Y Y - Y Y Impossible (expS+ would be clear) + Y Y - Y Y Impossible (expS+ would be clear) + Y Y - - Y Y Impossible (expS+ would be clear) + +#### Actions and transitions involving actions + +From the table, we learn that the possible actions are: + + - `START`, Start task, set expS+ + - `EXPDROP`, Set expS- + - `GOTDROP`, Clear expS- + - `RUNNING`, Clear expS+ + +There are also a couple of pseudo-actions, `ERROR` for an unexpected +supply drop, and `RECOVER` for circumstances marking spontaneous +recovery after an unexpected supply drop. + +The final four columns in this table are the new states of the +DemandMatcher and the task supervisor. + + ∃D ∃S ΔD ΔS expS+ expS- Actions Next: ∃D ∃S expS+ expS- + --------------------------------------------------------------------------- + - - + - - START Y - Y - + - Y + - - - START Y - Y - + Y - - - - RECOVERY - - - - + Y - + - - RECOVER Y Y - - + Y - - + - - RECOVER EXPDROP - Y - Y + Y Y - - - EXPDROP - Y - Y + Y Y - - - ERROR Y - - - + + - Y - - Y GOTDROP - - - - + - Y + - - Y GOTDROP START Y - Y - + Y Y - - Y GOTDROP START Y - Y - + Y Y - - - Y GOTDROP - - - - + + Y - - Y - EXPDROP - - Y Y + Y - + Y - RUNNING Y Y - - + Y - - + Y - RUNNING EXPDROP - Y - Y + + - - + Y Y RUNNING - Y - Y + - - + + Y Y RUNNING Y Y - Y + Y - + Y Y RUNNING Y Y - Y + Y - - + Y Y RUNNING - Y - Y + +#### Impossible states + +Some states are impossible to reach. + +It is impossible for neither supply nor demand to exist, when either +but not both of a rise or a drop in supply is expected: + + ∃D ∃S ΔD ΔS expS+ expS- + --------------------------------------------------------------------------- + - - - Y Impossible (expS- would be clear or expS+ set) + - - Y - Impossible (expS+ would be clear or expS- set) + +It is impossible for demand but no supply to exist, when a drop in +supply is expected but no rise in supply is expected: + + ∃D ∃S ΔD ΔS expS+ expS- + --------------------------------------------------------------------------- + Y - - Y Impossible (expS+ would be set) + +It is impossible for supply to exist while a rise in supply is +expected: + + ∃D ∃S ΔD ΔS expS+ expS- + --------------------------------------------------------------------------- + - Y Y - Impossible (expS+ would be clear) + Y Y Y - Impossible (expS+ would be clear) + - Y Y Y Impossible (expS+ would be clear) + Y Y Y Y Impossible (expS+ would be clear) + +#### Transitions involving only DemandMatcher state change + +Where no task supervisor state changes and no actions are needed: + + ∃D ∃S ΔD ΔS expS+ expS- Actions Next: ∃D ∃S expS+ expS- + --------------------------------------------------------------------------- + - - + - - - Y - - + - - + + - - Y Y - - + - Y + - - Y Y - - + - Y - - - - - - - + Y Y - - - - - - - - + - Y + - Y Y Y - Y + Y Y - - Y - Y - Y + - - + Y Y Y - Y Y + Y - - Y Y - - Y Y + +### Transition diagram + +![DemandMatcher task supervisor transition diagram](demand-matcher.png) + +### From state machine to implementation + +We can give the reachable states reasonable names: + + ∃D ∃S expS+ expS- Name + --------------------------------------- + - - - - IDLE + Y - Y - STARTING + Y Y - - RUNNING + - Y - Y UNWANTED + + Y - Y Y STARTING_DOOMED + - - Y Y STARTING_UNWANTED + Y Y - Y RUNNING_DOOMED + + - Y - - SUPPLY + Y - - - ERROR + +However, writing out the full state machine in terms of these states +doesn't exploit all the redundancy in the machine. + +Instead, let's group transitions by their effects on the task +supervisor's state, the "expected" bits. There are only four possible +actions (excluding warnings related to recovery etc.): + + START - set expS+ (and start a task instance) + RUNNING - clear expS+ + EXPDROP - set expS- + GOTDROP - clear expS- + +--------------------------------------------------------------------------- + +Leave expS+ alone, set expS-: + Y - - + - - EXPDROP - Y - Y + Y Y - - - EXPDROP - Y - Y + Y - - Y - EXPDROP - - Y Y + +Leave expS+ alone, clear expS-: + - Y - - Y GOTDROP - - - - + Y Y - - - Y GOTDROP - - - - + +Set expS+, leave expS- alone: + - - + - - START Y - Y - + - Y + - - - START Y - Y - + +Set expS+, clear expS-: + - Y + - - Y START GOTDROP Y - Y - + Y Y - - Y START GOTDROP Y - Y - + +Clear expS+, leave expS- alone: + Y - + Y - RUNNING Y Y - - + - - + Y Y RUNNING - Y - Y + - - + + Y Y RUNNING Y Y - Y + Y - + Y Y RUNNING Y Y - Y + Y - - + Y Y RUNNING - Y - Y + +Clear expS+, set expS-: + Y - - + Y - RUNNING EXPDROP - Y - Y + +--------------------------------------------------------------------------- + +Now, let's look at those grouped by specific action (some rows will +appear twice, because some rows involve more than one action): + +Expdrop: + Y - - + - - EXPDROP - Y - Y + Y Y - - - EXPDROP - Y - Y + Y - - Y - EXPDROP - - Y Y + Y - - + Y - RUNNING EXPDROP - Y - Y + + - "Set expS- whenever a drop in demand is detected, and either (a) + increase in supply is detected, (b) supply exists and is not + falling, or (c) supply is expected to exist." + +Gotdrop: + - Y - - Y GOTDROP - - - - + Y Y - - - Y GOTDROP - - - - + - Y + - - Y START GOTDROP Y - Y - + Y Y - - Y START GOTDROP Y - Y - + + - "Clear expS- whenever a drop in supply is detected." + +Start: + - - + - - START Y - Y - + - Y + - - - START Y - Y - + - Y + - - Y START GOTDROP Y - Y - + Y Y - - Y START GOTDROP Y - Y - + + - "Set expS+ and start a task whenever expS+ is clear and demand + becomes or remains high and supply becomes or remains low UNLESS + demand is already high, supply drops, and expS- is clear, which is + the 'unexpected drop' error case." + +Running: + Y - + Y - RUNNING Y Y - - + - - + Y Y RUNNING - Y - Y + - - + + Y Y RUNNING Y Y - Y + Y - + Y Y RUNNING Y Y - Y + Y - - + Y Y RUNNING - Y - Y + Y - - + Y - RUNNING EXPDROP - Y - Y + + - "Clear expS+ whenever supply increases." + +--------------------------------------------------------------------------- + +Now let's take those rules and check them against the full rulebase: + +"Set expS- whenever a drop in demand is detected, and either (a) +increase in supply is detected, (b) supply exists and is not +falling, or (c) supply is expected to exist." + + Y - - + - - RECOVER EXPDROP - Y - Y + Y Y - - - EXPDROP - Y - Y + Y - - Y - EXPDROP - - Y Y + Y - - + Y - RUNNING EXPDROP - Y - Y + Y - - + Y Y RUNNING - Y - Y + Y Y - - Y - Y - Y + Y - - Y Y - - Y Y + +"Clear expS- whenever a drop in supply is detected." + + - Y + - - - START Y - Y - + Y Y - - - ERROR Y - - - + - Y - - Y GOTDROP - - - - + - Y + - - Y GOTDROP START Y - Y - + Y Y - - Y GOTDROP START Y - Y - + Y Y - - - Y GOTDROP - - - - + - Y - - - - - - - + Y Y - - - - - - - - + +"Set expS+ and start a task whenever expS+ is clear and demand +becomes or remains high and supply becomes or remains low UNLESS +demand is already high, supply drops, and expS- is clear, which is +the 'unexpected drop' error case." + + - - + - - START Y - Y - + - Y + - - - START Y - Y - + Y Y - - - ERROR Y - - - + - Y + - - Y GOTDROP START Y - Y - + Y Y - - Y GOTDROP START Y - Y - + +"Clear expS+ whenever supply increases." + + Y - + - - RECOVER Y Y - - + Y - - + - - RECOVER EXPDROP - Y - Y + Y - + Y - RUNNING Y Y - - + Y - - + Y - RUNNING EXPDROP - Y - Y + - - + Y Y RUNNING - Y - Y + - - + + Y Y RUNNING Y Y - Y + Y - + Y Y RUNNING Y Y - Y + Y - - + Y Y RUNNING - Y - Y + - - + - - - Y - - + - - + + - - Y Y - - + +By looking at the next-state columns corresponding to the action +described, we can see that each predicate used to decide whether to +set or clear each state bit is a sound overapproximation of the +behaviour we want. diff --git a/doc/demand-matcher.png b/doc/demand-matcher.png new file mode 100644 index 0000000000000000000000000000000000000000..110dafd7c2b769ad4da9c0d004ecfbed6f978e29 GIT binary patch literal 71057 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�fku`$Hd4b_V5qsfP>_u0H*XW6R7CeJ)RcHCx;EbaAZHmXPfi=SA24 zES;#FK4`3uUwzYrq;`i~ys8Vh!(-|2K96W?^4Yp`4M_UPfvSnzOSVWXOjlWWSIMSg zRJomy<@^>-z!sQhiNjWkDHgER22zNC35*9C1TKW8tf0v6A==|)oqo)029RIXRl3YV zHHXYKd(~QlHO;Tud2xd$lc@D&Nx_T{x5f#jd(Q6v2-fQ$Mc5HfA{}P8PlPUbuKrwi zTs}ZUCQZ*hcde5oKy*xMfM%B0)@Ek8#p5gaH>>*GJ0?G_5&Rrd%sw| z546j;Cxe zXFl=D%`Yc3d!3vES$7XS%l;ETQNEX96mFLlckn7Jw$JJfxd#~-L$_!Lt%tsf>ZzxX zO_*s1B#C3zP6Yjh?WbPZuD-N2%*5D{YX_`>Hr`=Vbgzrbpp+b-EGxM1RzRhU&$0;L ziGcVek&!9rbaf`wmu>s(C0qJ|8FuAXlJ6H35NX0>Bd}Q}KI^uZ_wL9}Gz@Dk>rORu zpd5wyeG5oac&|*{XmC=I#G2n#%xo8D!zeIKqve}rOYrM!0gpC?hleDK8!fNx=Ts!3 zrRQwOXGgoO^1>Xl_U}KN(RcLs$o>+YB(r?_YW7lDh+`tj;%!2Q6l4(7YJcecktTQX zakcGjuz~{GE;7VC%?u~6Aa4o2{47$mOAnp~?y5HB^n>APZY)y`aHB$_s@L;cOA;8) ziN55OxpygCOOkY_50M6jCnLd!7QnhASLRl~;NLZqwgX=-R1Q~2{hAH#T3BdXU}&d% zV*~9`=?3ZGt~RjIY9_d=)a`{^lbdxK*hwxPj0daAUzPVw+k6H{e)ngs#WrFI+z!8s zN|#PGNV6y183(tRpGN|cG8N!~CWAVS7qHL4T`YK$TfJLeA)FJI27WEtl}v1gWy&81 zKMUN42%Z(!24JcpXolyq>BMaFV%0&_ef8A9+C$1{mtfD#4G)DC|6_~7Q4qhpWr^Fs ztbD;#r5RxA&#lV2zuj}6y|v>;JJTLWSE|z1=I_ood(duVyZo_~OO;4iij!PG20wUb zNLMi$)GrPnBzB8E_tnKs1jX)GAziSQze(nQ0642LIbFUt`dW%W^#f>;4?RmWwg*!4I$~pN8-omdn`GT49uGw zm8yYv%7N?6I0MY$a@Ri8ty70G$<G|ht zn>FM_)bR6E#!VCUS>my{Q%Z_8za*UbvueO;atW3KTpwrLF(}7)Gv&Jkf$r{^4;nqn zHnb5ooI9E#<5Hcd?8w%`(miV5#%C>BE}8i(hqmVU))+PQZpbWX?CO06iBHU!_j_R- z*ESGn?=lpk#=H!&_o-gwd$R1eP#RsKRyfe(u>ax^QAGZo9ML>hfiba@h z*y+#$0V(}9t?=yU8&*!RTcR6!Lb2HmJ&!84Udmhiq`R6k20jqrUInAhW*Jx1hOLJt zJ<;_QsNd859JMC4w}(H~N59Fx?7-gGY5Hj8;Z;G6{1H-nF#S_@0yBF(mH-=6uo!Fu zscaX%(E9Fi(tF-wH+v(%pPLvH5&7Y2UFaY3bS-6Ora|FNC9IRlL;idbeU#9-3Js=f znTu7aB*w>33PR=YRjw6NgcgcHo>e7`y~-_K#Gg~7{9#j9g1I!K>p??^3asDHo!Mo3 z%OS*6{Y{|*(sE0`7c9=tEh#C^1m(6V3kYhds3Q4(U3%0Zr96{O;$Z0ePdsQq|8@YS zukk=GR`7`jpkK3YW<=2jNO`08?$i$ErM z%DeFFW$0OAXROvADe#MrPp$D%L1X@qe?sMB*hOAUGtN213%U6gJT&03l>#pi8JCLk z^nQ^cz_Z?ekvZp}?!Um4KmS${n$W0a!q56sql+KfZuYqxk#!GSDRf$i$F*9dcfa!r zw^8Mmu=dc&d3ju7VcOrb;>MVAe{-8`mN5gPNcO2vW480375jhbC7=J1^n2Kn6tEkW zE8om{B_;lgZqtW+jVprm08N*UBS((N1>eL3yEzBD!(0R1f#ryXnz{~DO&hANX|1jY z)6|4%XhYSsU}|cOzvkTe7lE(8n-?McUj(`^b>LI=|09qTiz)#Kj=*nPm{uC!`~81( C_6lVH literal 0 HcmV?d00001 diff --git a/js/src/broker.js b/js/src/broker.js index 4f2e30e..0073e17 100644 --- a/js/src/broker.js +++ b/js/src/broker.js @@ -31,12 +31,12 @@ function spawnBrokerClientDriver() { Dataspace.spawn( new DemandMatcher([brokerConnection(URL)], [brokerConnection(URL)], + function (c) { + Dataspace.spawn(new BrokerClientConnection(c.url)); + }, { demandMetaLevel: 1, - supplyMetaLevel: 0, - onDemandIncrease: function (c) { - Dataspace.spawn(new BrokerClientConnection(c.url)); - } + supplyMetaLevel: 0 })); })); } diff --git a/js/src/demand-matcher.js b/js/src/demand-matcher.js index 900c285..c8ab9b7 100644 --- a/js/src/demand-matcher.js +++ b/js/src/demand-matcher.js @@ -3,6 +3,100 @@ var Trie = require('./trie.js'); var Patch = require('./patch.js'); var Util = require('./util.js'); +/////////////////////////////////////////////////////////////////////////// +// Protocol between DemandMatcher and taskSupervisor functions + +// Bits: +var IS_CHANGING = 1; +var IS_PRESENT = 2; + +// Bit combinations: +var LOW = 0 ; +var RISING = IS_CHANGING ; +var HIGH = IS_PRESENT ; +var FALLING = IS_PRESENT | IS_CHANGING ; + +/////////////////////////////////////////////////////////////////////////// +// Default task supervision strategy. See syndicate/doc/demand-matcher.md. + +function defaultTaskSupervisor(demandState, supplyState, supervisionState, taskFn, errorFn) { + var oldESI = supervisionState ? supervisionState.expectSupplyIncrease : false; + var oldESD = supervisionState ? supervisionState.expectSupplyDecrease : false; + + var newESI = oldESI; + var newESD = oldESD; + + if ((demandState === FALLING) && ((supplyState === RISING) || + (supplyState === HIGH) || + oldESI)) { + newESD = true; + } + + if (!oldESI && ((demandState === RISING) || + (demandState === HIGH)) && ((supplyState === LOW) || + (supplyState === FALLING))) { + if ((demandState === HIGH) && !oldESD) { + errorFn("Syndicate: DemandMatcher detected unexpected drop in supply"); + } else { + taskFn(); + newESI = true; + } + } + + if (supplyState === FALLING) newESD = false; + if (supplyState === RISING) newESI = false; + + if (newESI || newESD) { + return { expectSupplyIncrease: newESI, expectSupplyDecrease: newESD }; + } else { + return null; + } +} + +/////////////////////////////////////////////////////////////////////////// +// DemandMatcher itself + +function DemandMatcher(demandSpecs, supplySpecs, startTask, options) { + options = Util.extend({ + metaLevel: 0, + demandMetaLevel: null, + supplyMetaLevel: null, + taskSupervisor: defaultTaskSupervisor, + }, options); + + if (typeof startTask !== 'function') { + throw new Error("Syndicate: DemandMatcher expects 'startTask' function as third argument"); + } + + this.demandProjectionNames = ensureMatchingProjectionNames(demandSpecs); + this.supplyProjectionNames = ensureMatchingProjectionNames(supplySpecs); + ensureMatchingProjectionNames([demandSpecs[0], supplySpecs[0]]); + + this.demandSpecs = demandSpecs; + this.supplySpecs = supplySpecs; + + this.demandPatterns = demandSpecs.map(function (s) { return Trie.projectionToPattern(s); }); + this.supplyPatterns = supplySpecs.map(function (s) { return Trie.projectionToPattern(s); }); + + this.demandMetaLevel = + (options.demandMetaLevel === null) ? options.metaLevel : options.demandMetaLevel; + this.supplyMetaLevel = + (options.supplyMetaLevel === null) ? options.metaLevel : options.supplyMetaLevel; + + function metaWrap(n) { + return function (s) { return Patch.prependAtMeta(s, n); }; + } + this.demandProjections = demandSpecs.map(metaWrap(this.demandMetaLevel)); + this.supplyProjections = supplySpecs.map(metaWrap(this.supplyMetaLevel)); + + this.taskSupervisor = options.taskSupervisor; + this.startTask = startTask; + + this.currentDemand = Immutable.Set(); + this.currentSupply = Immutable.Set(); + this.supervisionStates = Immutable.Map(); +} + function ensureMatchingProjectionNames(specs) { if (!(specs.length > 0)) { throw new Error("Syndicate: DemandMatcher needs at least one spec"); @@ -21,52 +115,6 @@ function ensureMatchingProjectionNames(specs) { return names; } -function defaultHandler(side, movement) { - return function (captures) { - console.error("Syndicate: Unhandled "+movement+" in "+side, captures); - }; -} - -function DemandMatcher(demandSpecs, supplySpecs, options) { - options = Util.extend({ - metaLevel: 0, - demandMetaLevel: null, - supplyMetaLevel: null, - onDemandIncrease: defaultHandler('demand', 'increase'), - onDemandDecrease: function (captures) {}, - onSupplyIncrease: function (captures) {}, - onSupplyDecrease: defaultHandler('supply', 'decrease') - }, options); - - this.demandProjectionNames = ensureMatchingProjectionNames(demandSpecs); - this.supplyProjectionNames = ensureMatchingProjectionNames(supplySpecs); - - this.demandSpecs = demandSpecs; - this.supplySpecs = supplySpecs; - - this.demandPatterns = demandSpecs.map(function (s) { return Trie.projectionToPattern(s); }); - this.supplyPatterns = supplySpecs.map(function (s) { return Trie.projectionToPattern(s); }); - - this.demandMetaLevel = - (options.demandMetaLevel === null) ? options.metaLevel : options.demandMetaLevel; - this.supplyMetaLevel = - (options.supplyMetaLevel === null) ? options.metaLevel : options.supplyMetaLevel; - - function metaWrap(n) { - return function (s) { return Patch.prependAtMeta(s, n); }; - } - this.demandProjections = demandSpecs.map(metaWrap(this.demandMetaLevel)); - this.supplyProjections = supplySpecs.map(metaWrap(this.supplyMetaLevel)); - - this.onDemandIncrease = options.onDemandIncrease; - this.onDemandDecrease = options.onDemandDecrease; - this.onSupplyIncrease = options.onSupplyIncrease; - this.onSupplyDecrease = options.onSupplyDecrease; - - this.currentDemand = Immutable.Set(); - this.currentSupply = Immutable.Set(); -} - DemandMatcher.prototype.boot = function () { var p = Patch.emptyPatch; function extend(ml) { @@ -83,6 +131,50 @@ DemandMatcher.prototype.handleEvent = function (e) { } }; +DemandMatcher.prototype.handlePatch = function (p) { + var self = this; + + var dN = self.demandProjectionNames.length; + var sN = self.supplyProjectionNames.length; + var addedDemand = self.extractKeys(p.added, self.demandProjections, dN, 'demand'); + var removedDemand = self.extractKeys(p.removed, self.demandProjections, dN, 'demand'); + var addedSupply = self.extractKeys(p.added, self.supplyProjections, sN, 'supply'); + var removedSupply = self.extractKeys(p.removed, self.supplyProjections, sN, 'supply'); + + // Though the added and removed sets of patches are always disjoint, + // *after projection* this may not hold. Cancel out any overlaps. + var demandOverlap = addedDemand.intersect(removedDemand); + var supplyOverlap = addedSupply.intersect(removedSupply); + addedDemand = addedDemand.subtract(demandOverlap); + removedDemand = removedDemand.subtract(demandOverlap); + addedSupply = addedSupply.subtract(supplyOverlap); + removedSupply = removedSupply.subtract(supplyOverlap); + + var allTasks = addedDemand.union(addedSupply).union(removedDemand).union(removedSupply); + + allTasks.forEach(function (captures) { + function taskFn() { + self.startTask(Trie.captureToObject(captures, self.demandProjectionNames)); + } + function errorFn(msg) { + console.error(msg, captures); + } + + var demandState = computeState(self.currentDemand, addedDemand, removedDemand, captures); + var supplyState = computeState(self.currentSupply, addedSupply, removedSupply, captures); + var oldSupervisionState = self.supervisionStates.get(captures, null); + var newSupervisionState = self.taskSupervisor(demandState, + supplyState, + oldSupervisionState, + taskFn, + errorFn); + self.supervisionStates = self.supervisionStates.set(captures, newSupervisionState); + }); + + self.currentSupply = self.currentSupply.union(addedSupply).subtract(removedSupply); + self.currentDemand = self.currentDemand.union(addedDemand).subtract(removedDemand); +}; + DemandMatcher.prototype.extractKeys = function (trie, projections, keyCount, whichSide) { var ks = Immutable.Set(); projections.forEach(function (proj) { @@ -97,53 +189,11 @@ DemandMatcher.prototype.extractKeys = function (trie, projections, keyCount, whi return ks; }; -DemandMatcher.prototype.handlePatch = function (p) { - var self = this; - - var dN = self.demandProjectionNames.length; - var sN = self.supplyProjectionNames.length; - var addedDemand = this.extractKeys(p.added, self.demandProjections, dN, 'demand'); - var removedDemand = this.extractKeys(p.removed, self.demandProjections, dN, 'demand'); - var addedSupply = this.extractKeys(p.added, self.supplyProjections, sN, 'supply'); - var removedSupply = this.extractKeys(p.removed, self.supplyProjections, sN, 'supply'); - - // Though the added and removed sets of patches are always disjoint, - // *after projection* this may not hold. Cancel out any overlaps. - var demandOverlap = addedDemand.intersect(removedDemand); - var supplyOverlap = addedSupply.intersect(removedSupply); - addedDemand = addedDemand.subtract(demandOverlap); - removedDemand = removedDemand.subtract(demandOverlap); - addedSupply = addedSupply.subtract(supplyOverlap); - removedSupply = removedSupply.subtract(supplyOverlap); - - self.currentSupply = self.currentSupply.union(addedSupply); - self.currentDemand = self.currentDemand.subtract(removedDemand); - - removedSupply.forEach(function (captures) { - if (self.currentDemand.has(captures)) { - self.onSupplyDecrease(Trie.captureToObject(captures, self.supplyProjectionNames)); - } - }); - addedSupply.forEach(function (captures) { - if (!self.currentDemand.has(captures)) { - self.onSupplyIncrease(Trie.captureToObject(captures, self.supplyProjectionNames)); - } - }); - - removedDemand.forEach(function (captures) { - if (self.currentSupply.has(captures)) { - self.onDemandDecrease(Trie.captureToObject(captures, self.demandProjectionNames)); - } - }); - addedDemand.forEach(function (captures) { - if (!self.currentSupply.has(captures)) { - self.onDemandIncrease(Trie.captureToObject(captures, self.demandProjectionNames)); - } - }); - - self.currentSupply = self.currentSupply.subtract(removedSupply); - self.currentDemand = self.currentDemand.union(addedDemand); -}; +function computeState(current, added, removed, captures) { + var isPresent = current.has(captures); + var isChanging = added.has(captures) || removed.has(captures); + return (isPresent ? IS_PRESENT : 0) | (isChanging ? IS_CHANGING : 0); +} /////////////////////////////////////////////////////////////////////////// diff --git a/js/src/timer-driver.js b/js/src/timer-driver.js index 0ee8162..4d8757b 100644 --- a/js/src/timer-driver.js +++ b/js/src/timer-driver.js @@ -15,18 +15,14 @@ function spawnTimerDriver() { Dataspace.spawn( new DemandMatcher([Patch.observe(periodicTick(_$('intervalMS')))], [Patch.advertise(periodicTick(_$('intervalMS')))], - { - onDemandIncrease: function (c) { - Dataspace.spawn(new Tick(c.intervalMS)); - } + function (c) { + Dataspace.spawn(new Tick(c.intervalMS)); })); Dataspace.spawn( new DemandMatcher([Patch.observe(timeLaterThan(_$('deadlineMS')))], [Patch.advertise(timeLaterThan(_$('deadlineMS')))], - { - onDemandIncrease: function (c) { - Dataspace.spawn(new Alarm(c.deadlineMS)); - } + function (c) { + Dataspace.spawn(new Alarm(c.deadlineMS)); })); } diff --git a/js/src/ui.js b/js/src/ui.js index 0013a43..8848f1f 100644 --- a/js/src/ui.js +++ b/js/src/ui.js @@ -78,29 +78,23 @@ function spawnUIDriver(options) { Dataspace.spawn( new DemandMatcher([Patch.observe(globalEventProj)], [Patch.advertise(globalEventProj)], - { - onDemandIncrease: function (c) { - Dataspace.spawn(new GlobalEventSupply(c.selector, c.eventType)); - } + function (c) { + Dataspace.spawn(new GlobalEventSupply(c.selector, c.eventType)); })); var windowEventProj = windowEvent(_$('eventType'), __); Dataspace.spawn( new DemandMatcher([Patch.observe(windowEventProj)], [Patch.advertise(windowEventProj)], - { - onDemandIncrease: function (c) { - Dataspace.spawn(new WindowEventSupply(c.eventType)); - } + function (c) { + Dataspace.spawn(new WindowEventSupply(c.eventType)); })); Dataspace.spawn( new DemandMatcher([uiFragment(_$('fragmentId'), __, __)], [uiFragmentExists(_$('fragmentId'))], - { - onDemandIncrease: function (c) { - Dataspace.spawn(new UIFragment(c.fragmentId)); - } + function (c) { + Dataspace.spawn(new UIFragment(c.fragmentId)); })); Dataspace.spawn(new LocationHashTracker(options.defaultLocationHash || '/'));