flor 0.16.1 → 0.16.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +8 -0
- data/CREDITS.md +1 -0
- data/Makefile +1 -1
- data/README.md +82 -6
- data/lib/flor.rb +1 -1
- data/lib/flor/conf.rb +19 -6
- data/lib/flor/core/executor.rb +45 -16
- data/lib/flor/core/node.rb +4 -4
- data/lib/flor/core/procedure.rb +40 -0
- data/lib/flor/djan.rb +5 -2
- data/lib/flor/flor.rb +92 -7
- data/lib/flor/id.rb +19 -0
- data/lib/flor/migrations/0001_tables.rb +6 -6
- data/lib/flor/migrations/0005_pointer_content.rb +20 -0
- data/lib/flor/pcore/_apply.rb +103 -57
- data/lib/flor/pcore/_att.rb +15 -1
- data/lib/flor/pcore/_ref.rb +2 -1
- data/lib/flor/pcore/arith.rb +46 -9
- data/lib/flor/pcore/break.rb +1 -1
- data/lib/flor/pcore/case.rb +41 -0
- data/lib/flor/pcore/collect.rb +1 -1
- data/lib/flor/pcore/cursor.rb +1 -1
- data/lib/flor/pcore/define.rb +32 -6
- data/lib/flor/pcore/iterator.rb +12 -0
- data/lib/flor/pcore/on_cancel.rb +1 -1
- data/lib/flor/pcore/set.rb +14 -4
- data/lib/flor/punit/{ccollect.rb → c_collect.rb} +2 -2
- data/lib/flor/punit/c_each.rb +11 -0
- data/lib/flor/punit/c_for_each.rb +41 -0
- data/lib/flor/punit/c_iterator.rb +160 -0
- data/lib/flor/punit/c_map.rb +43 -0
- data/lib/flor/punit/concurrence.rb +43 -200
- data/lib/flor/punit/graft.rb +3 -2
- data/lib/flor/punit/m_ram.rb +281 -0
- data/lib/flor/unit.rb +1 -0
- data/lib/flor/unit/caller.rb +6 -1
- data/lib/flor/unit/executor.rb +17 -4
- data/lib/flor/unit/ganger.rb +12 -1
- data/lib/flor/unit/hloader.rb +251 -0
- data/lib/flor/unit/hook.rb +74 -15
- data/lib/flor/unit/hooker.rb +9 -12
- data/lib/flor/unit/loader.rb +41 -17
- data/lib/flor/unit/models.rb +54 -18
- data/lib/flor/unit/models/execution.rb +15 -4
- data/lib/flor/unit/models/pointer.rb +11 -0
- data/lib/flor/unit/scheduler.rb +126 -30
- data/lib/flor/unit/spooler.rb +5 -3
- data/lib/flor/unit/storage.rb +40 -13
- data/lib/flor/unit/waiter.rb +165 -26
- data/lib/flor/unit/wlist.rb +98 -5
- metadata +10 -4
- data/lib/flor/punit/cmap.rb +0 -112
data/lib/flor/pcore/collect.rb
CHANGED
data/lib/flor/pcore/cursor.rb
CHANGED
data/lib/flor/pcore/define.rb
CHANGED
@@ -50,7 +50,19 @@ class Flor::Pro::Define < Flor::Procedure
|
|
50
50
|
|
51
51
|
def receive_att
|
52
52
|
|
53
|
-
t = flatten_tree
|
53
|
+
t, sig = flatten_tree
|
54
|
+
|
55
|
+
bad_param =
|
56
|
+
sig.inject(nil) { |r, a|
|
57
|
+
a10 = a[1][0]
|
58
|
+
pa = a10[0] == '_ref' && a10[1].size > 1 && a10[1].collect { |e| e[1] }
|
59
|
+
break pa.join('.') if pa && ! pa[0].match(/\A(f|fld|field)\z/)
|
60
|
+
nil }
|
61
|
+
|
62
|
+
fail Flor::FlorError.new(
|
63
|
+
"cannot accept #{bad_param.inspect} as parameter", self
|
64
|
+
) if bad_param
|
65
|
+
|
54
66
|
cnode = lookup_var_node(@node, 'l')
|
55
67
|
cnid = cnode['nid']
|
56
68
|
fun = counter_next('funs') - 1
|
@@ -79,16 +91,22 @@ class Flor::Pro::Define < Flor::Procedure
|
|
79
91
|
|
80
92
|
def flatten_tree
|
81
93
|
|
94
|
+
#puts "== tree"
|
95
|
+
#pp tree
|
96
|
+
tre = tree
|
82
97
|
off = heap == 'define' ? 1 : 0
|
83
|
-
sig =
|
98
|
+
sig = tre[1][off..-1].select { |t| t[0] == '_att' }
|
99
|
+
#puts "sig: " + sig.inspect
|
100
|
+
#p sig[0][0]
|
101
|
+
#p sig[0][1][0]
|
84
102
|
|
85
|
-
return
|
103
|
+
return [ tre, sig ] unless wrapped?(sig)
|
86
104
|
|
87
105
|
# There is a parenthese around the parameters, let's unwrap that...
|
88
106
|
|
89
|
-
hed = Flor.dup(
|
107
|
+
hed = Flor.dup(tre[1][0, off])
|
90
108
|
sig = Flor.dup(sig)
|
91
|
-
bdy = Flor.dup(
|
109
|
+
bdy = Flor.dup(tre[1][(off + sig.length)..-1])
|
92
110
|
|
93
111
|
att0 = sig[0][1][0]
|
94
112
|
att0atts = att0[1]
|
@@ -96,7 +114,15 @@ class Flor::Pro::Define < Flor::Procedure
|
|
96
114
|
|
97
115
|
sig = sig + att0atts
|
98
116
|
|
99
|
-
[ heap, hed + sig + bdy, *
|
117
|
+
[ [ heap, hed + sig + bdy, *tre[2..-1] ],
|
118
|
+
sig ]
|
119
|
+
end
|
120
|
+
|
121
|
+
def wrapped?(sig)
|
122
|
+
|
123
|
+
return false if sig.length != 1
|
124
|
+
return false if sig[0][1][0][0] == '_ref'
|
125
|
+
sig[0][1][1] != []
|
100
126
|
end
|
101
127
|
end
|
102
128
|
|
data/lib/flor/pcore/iterator.rb
CHANGED
@@ -26,6 +26,18 @@ class Flor::Pro::Iterator < Flor::Procedure
|
|
26
26
|
end
|
27
27
|
end
|
28
28
|
|
29
|
+
def add
|
30
|
+
|
31
|
+
elts = message['elements']
|
32
|
+
|
33
|
+
elts = elts.inject([]) { |a, e| a.concat(e.to_a) } \
|
34
|
+
if @node['ocol'].is_a?(Hash)
|
35
|
+
|
36
|
+
@node['col'].concat(elts)
|
37
|
+
|
38
|
+
[] # no new messages to queue
|
39
|
+
end
|
40
|
+
|
29
41
|
protected
|
30
42
|
|
31
43
|
def receive_argument
|
data/lib/flor/pcore/on_cancel.rb
CHANGED
data/lib/flor/pcore/set.rb
CHANGED
@@ -9,6 +9,7 @@ class Flor::Pro::Set < Flor::Procedure
|
|
9
9
|
# set a false # sets the `false` in the variable 'a'
|
10
10
|
# set v.b [ 1 2 ] # sets `[ 1, 2 ]` in the variable 'b'
|
11
11
|
# set v.c.0 -1 # sets `-1` in first slot of the array in var 'c'
|
12
|
+
# set v.a f.a.0 # copy the value in field 'a' (first elt) into var 'a'
|
12
13
|
# ```
|
13
14
|
#
|
14
15
|
# When set has a single child, it uses as value to copy the content of
|
@@ -27,6 +28,15 @@ class Flor::Pro::Set < Flor::Procedure
|
|
27
28
|
#
|
28
29
|
# ## splat
|
29
30
|
#
|
31
|
+
# There is a splat system using underscores to extract array values and
|
32
|
+
# assign them to variables.
|
33
|
+
#
|
34
|
+
# 3 underscores following a variable name instructs "set" to place
|
35
|
+
# as many values as possible into an array under the given variable name.
|
36
|
+
# 2 underscores following a variable name and followed by an integer
|
37
|
+
# restrict the number of values thus globbed.
|
38
|
+
# Underscores following nothing simply discard the array values.
|
39
|
+
#
|
30
40
|
# ```
|
31
41
|
# sequence
|
32
42
|
# set a b___ c
|
@@ -56,10 +66,10 @@ class Flor::Pro::Set < Flor::Procedure
|
|
56
66
|
# value set by its last child (usually the value set).
|
57
67
|
#
|
58
68
|
# ```
|
59
|
-
#
|
60
|
-
#
|
61
|
-
#
|
62
|
-
#
|
69
|
+
# sequence
|
70
|
+
# 123 # payload.ret is set to `123`
|
71
|
+
# set a 456 # var 'a' is set to 456, payload.ret is reset to `123`
|
72
|
+
# setr b 789 # var 'b' is set to `789`, payload.ret as well
|
63
73
|
# ```
|
64
74
|
|
65
75
|
names %w[ set setr ]
|
@@ -0,0 +1,41 @@
|
|
1
|
+
|
2
|
+
require 'flor/punit/c_iterator'
|
3
|
+
|
4
|
+
|
5
|
+
class Flor::Pro::CforEach < Flor::Pro::ConcurrentIterator
|
6
|
+
#
|
7
|
+
# Concurrent "for-each", launches a concurrent branch for each elt or entry
|
8
|
+
# of the incoming collection.
|
9
|
+
#
|
10
|
+
# ```
|
11
|
+
# c-for-each [ 'alice' 'bob' 'charly' ]
|
12
|
+
# def user \ task user 'contact customer group'
|
13
|
+
# #
|
14
|
+
# # is thus equivalent to
|
15
|
+
# #
|
16
|
+
# task 'alice' 'contact customer group'
|
17
|
+
# task 'bob' 'contact customer group'
|
18
|
+
# task 'charly' 'contact customer group'
|
19
|
+
# ```
|
20
|
+
#
|
21
|
+
# By default, the incoming `f.ret` collection is used:
|
22
|
+
# ```
|
23
|
+
# [ 'alice' 'bob' 'charly' ]
|
24
|
+
# c-for-each
|
25
|
+
# def user \ task user 'contact customer group'
|
26
|
+
# ```
|
27
|
+
#
|
28
|
+
# ## see also
|
29
|
+
#
|
30
|
+
# For-each, cmap, and ceach.
|
31
|
+
|
32
|
+
name 'c-for-each'
|
33
|
+
|
34
|
+
protected
|
35
|
+
|
36
|
+
def post_merge
|
37
|
+
|
38
|
+
@node['merged_payload'].merge!('ret' => @node['col'])
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
@@ -0,0 +1,160 @@
|
|
1
|
+
|
2
|
+
require 'flor/punit/m_ram'
|
3
|
+
|
4
|
+
|
5
|
+
# Parent class for "c-for-each" and "c-map"
|
6
|
+
#
|
7
|
+
class Flor::Pro::ConcurrentIterator < Flor::Procedure
|
8
|
+
|
9
|
+
include Flor::Pro::ReceiveAndMerge
|
10
|
+
|
11
|
+
def pre_execute
|
12
|
+
|
13
|
+
@node['atts'] = []
|
14
|
+
@node['args'] = []
|
15
|
+
@node['col'] = nil
|
16
|
+
|
17
|
+
reff_att_children
|
18
|
+
unatt_unkeyed_children
|
19
|
+
end
|
20
|
+
|
21
|
+
def receive_non_att
|
22
|
+
|
23
|
+
if Flor.same_sub?(nid, from)
|
24
|
+
@node['args'] << payload['ret']
|
25
|
+
super
|
26
|
+
elsif @node['on_receive_nids'] && @node['on_receive_nids'][0] == from
|
27
|
+
receive_from_receiver
|
28
|
+
elsif @node['merging']
|
29
|
+
receive_from_merger
|
30
|
+
else
|
31
|
+
receive_from_branch
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def receive_last
|
36
|
+
|
37
|
+
t1 = tree[1]
|
38
|
+
|
39
|
+
col = nil
|
40
|
+
fun = nil
|
41
|
+
refs = []
|
42
|
+
#
|
43
|
+
@node['args'].each_with_index do |a, i|
|
44
|
+
if ( ! fun) && Flor.is_func_tree?(a)
|
45
|
+
fun = a
|
46
|
+
elsif ( ! col) && Flor.is_collection?(a)
|
47
|
+
col = a
|
48
|
+
else
|
49
|
+
tt = t1[i]
|
50
|
+
refs << Flor.ref_to_path(tt) if Flor.is_ref_tree?(tt)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
#
|
54
|
+
col ||= node_payload_ret
|
55
|
+
|
56
|
+
fail Flor::FlorError.new("collection not given to #{heap.inspect}", self) \
|
57
|
+
unless Flor.is_collection?(col)
|
58
|
+
return wrap('ret' => col) \
|
59
|
+
unless Flor.is_func_tree?(fun)
|
60
|
+
|
61
|
+
@node['col'] = col
|
62
|
+
@node['cnt'] = col.size
|
63
|
+
@node['fun'] = fun
|
64
|
+
@node['refs'] = refs
|
65
|
+
|
66
|
+
col
|
67
|
+
.collect
|
68
|
+
.with_index { |e, i|
|
69
|
+
apply(fun, determine_iteration_args(col, i), tree[2]) }
|
70
|
+
.flatten(1)
|
71
|
+
end
|
72
|
+
|
73
|
+
def add
|
74
|
+
|
75
|
+
col = @node['col']
|
76
|
+
elts = message['elements']
|
77
|
+
|
78
|
+
fail Flor::FlorError.new(
|
79
|
+
"cannot add branches to #{heap}", self
|
80
|
+
) unless elts
|
81
|
+
|
82
|
+
tcol = Flor.type(col)
|
83
|
+
|
84
|
+
x =
|
85
|
+
if tcol == :object
|
86
|
+
elts.inject(nil) { |r, e|
|
87
|
+
next r if r
|
88
|
+
t = Flor.type(e)
|
89
|
+
t != :object ? t : r }
|
90
|
+
else
|
91
|
+
nil
|
92
|
+
end
|
93
|
+
fail Flor::FlorError.new("cannot add #{x} to object", self) \
|
94
|
+
if x
|
95
|
+
|
96
|
+
if tcol == :array
|
97
|
+
col.concat(elts)
|
98
|
+
else # tcol == :object
|
99
|
+
elts.each { |e| col.merge!(e) }
|
100
|
+
end
|
101
|
+
|
102
|
+
cnt = @node['cnt']
|
103
|
+
@node['cnt'] += elts.size
|
104
|
+
|
105
|
+
pl = message['payload'] || node_payload.current
|
106
|
+
|
107
|
+
elts
|
108
|
+
.collect
|
109
|
+
.with_index { |e, i|
|
110
|
+
apply(
|
111
|
+
@node['fun'], determine_iteration_args(col, cnt + i), tree[2],
|
112
|
+
payload: Flor.dup(pl)) }
|
113
|
+
.flatten(1)
|
114
|
+
end
|
115
|
+
|
116
|
+
protected
|
117
|
+
|
118
|
+
def branch_count
|
119
|
+
|
120
|
+
@node['col'].size
|
121
|
+
end
|
122
|
+
|
123
|
+
def determine_iteration_args(col, idx)
|
124
|
+
|
125
|
+
refs = @node['refs'].dup
|
126
|
+
|
127
|
+
args =
|
128
|
+
if col.is_a?(Array)
|
129
|
+
[ [ refs.shift || 'elt', col[idx] ] ]
|
130
|
+
else
|
131
|
+
e = col.to_a[idx]
|
132
|
+
[ [ refs.shift || 'key', e[0] ], [ refs.shift || 'val', e[1] ] ]
|
133
|
+
end
|
134
|
+
args << [ refs.shift || 'idx', idx ]
|
135
|
+
args << [ refs.shift || 'len', col.length ]
|
136
|
+
|
137
|
+
args
|
138
|
+
end
|
139
|
+
|
140
|
+
# TODO: eventually move me up to Flor::Procedure, as Flor::Iterator might
|
141
|
+
# use me
|
142
|
+
#
|
143
|
+
def reff_att_children
|
144
|
+
|
145
|
+
t = tree
|
146
|
+
t1 = t[1]
|
147
|
+
|
148
|
+
is = t1.each.with_index.inject([]) { |a, (tt, i)|
|
149
|
+
a << i \
|
150
|
+
if tt[0] == '_att' && tt[1].size == 1 && Flor.is_ref_tree?(tt[1][0])
|
151
|
+
a }
|
152
|
+
|
153
|
+
return if is.empty?
|
154
|
+
|
155
|
+
is.each { |i| t1[i][1][0][0] = '_reff' }
|
156
|
+
|
157
|
+
@node['tree'] = [ t[0], t1, *t[2..-1] ]
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
@@ -0,0 +1,43 @@
|
|
1
|
+
|
2
|
+
require 'flor/punit/c_iterator'
|
3
|
+
|
4
|
+
|
5
|
+
class Flor::Pro::Cmap < Flor::Pro::ConcurrentIterator
|
6
|
+
#
|
7
|
+
# Concurrent version of "map". Spins a concurrent child for each
|
8
|
+
# element of the incoming/argument collection.
|
9
|
+
#
|
10
|
+
# ```
|
11
|
+
# cmap [ 1 2 3 ]
|
12
|
+
# def x \ * x 2
|
13
|
+
# # yields: [ 2, 4, 6 ]
|
14
|
+
#
|
15
|
+
# [ 1 2 3 ]
|
16
|
+
# cmap (def x \ * x 2)
|
17
|
+
# # yields: [ 2, 4, 6 ]
|
18
|
+
#
|
19
|
+
# define double x \ * x 2
|
20
|
+
# cmap double [ 1 2 3 ]
|
21
|
+
# # yields: [ 2, 4, 6 ]
|
22
|
+
# ```
|
23
|
+
#
|
24
|
+
# "cmap" is over when all the children have answered. For more complex
|
25
|
+
# concurrent behaviours, look at [concurrence](concurrence.md).
|
26
|
+
#
|
27
|
+
# ## see also
|
28
|
+
#
|
29
|
+
# Map, concurrence.
|
30
|
+
|
31
|
+
names %w[ cmap c-map ]
|
32
|
+
|
33
|
+
protected
|
34
|
+
|
35
|
+
def post_merge
|
36
|
+
|
37
|
+
@node['merged_payload'].merge!(
|
38
|
+
'ret' => @node['payloads']
|
39
|
+
.sort_by { |k, v| k.split('-').last }
|
40
|
+
.collect { |_, v| v['ret'] })
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
@@ -1,4 +1,7 @@
|
|
1
1
|
|
2
|
+
require 'flor/punit/m_ram'
|
3
|
+
|
4
|
+
|
2
5
|
class Flor::Pro::Concurrence < Flor::Procedure
|
3
6
|
#
|
4
7
|
# Executes its children concurrently.
|
@@ -144,7 +147,7 @@ class Flor::Pro::Concurrence < Flor::Procedure
|
|
144
147
|
# + 56 78
|
145
148
|
# ```
|
146
149
|
#
|
147
|
-
# ## on_merge: / merger:
|
150
|
+
# ## on_merge: / merger: / merge:
|
148
151
|
#
|
149
152
|
# the function given to `on_merge:` or `merger:` is called once the
|
150
153
|
# concurrence has gathered enough replies (or the right replies,
|
@@ -180,6 +183,25 @@ class Flor::Pro::Concurrence < Flor::Procedure
|
|
180
183
|
# * _branch_count_ simply contains the count of branches. It should be
|
181
184
|
# superior or equal to the size of _rets_ and _replies_.
|
182
185
|
#
|
186
|
+
# ### merge: and string values
|
187
|
+
#
|
188
|
+
# By default, the merge technique is a deep merge favouring the first
|
189
|
+
# branches to reply. By passing a string value to merge:/merger:/on_merge:
|
190
|
+
# one can select a different merge technique.
|
191
|
+
#
|
192
|
+
# * "first" (the default) - the first branch to reply has priority in the deep # merge
|
193
|
+
# * "last" - the last branch to reply has priority in the deep merge
|
194
|
+
# * "top" or "north" - the branch are prioritized in the order they are
|
195
|
+
# in the flow definition
|
196
|
+
# * "bottom" or "south" - the branch are prioritized in the reverse order of
|
197
|
+
# the flow definition
|
198
|
+
#
|
199
|
+
# Adding "plain" (for example "south plain") tells the "concurrence" not to
|
200
|
+
# use a deep merge but the plain/vanilla merge found in Ruby.
|
201
|
+
#
|
202
|
+
# "north plain" can be abbreviated to "np", "bottom" to "b", "first plain" to
|
203
|
+
# "fp", etc...
|
204
|
+
#
|
183
205
|
# ## on_merge (non-attribute)
|
184
206
|
#
|
185
207
|
# Like `receiver:` / `:on_receive` has the `on_receive` construct, there
|
@@ -271,15 +293,13 @@ class Flor::Pro::Concurrence < Flor::Procedure
|
|
271
293
|
# push l 2
|
272
294
|
# ```
|
273
295
|
|
296
|
+
include Flor::Pro::ReceiveAndMerge
|
297
|
+
|
274
298
|
name 'concurrence'
|
275
299
|
|
276
300
|
def pre_execute
|
277
301
|
|
278
302
|
@node['atts'] = []
|
279
|
-
@node['payloads'] = {}
|
280
|
-
|
281
|
-
@node['on_receive_nids'] = nil
|
282
|
-
@node['on_receive_queue'] = []
|
283
303
|
|
284
304
|
pre_execute_rewrite
|
285
305
|
end
|
@@ -288,20 +308,11 @@ class Flor::Pro::Concurrence < Flor::Procedure
|
|
288
308
|
|
289
309
|
return wrap_reply unless children[@ncid]
|
290
310
|
|
291
|
-
@node['receiver'] = determine_receiver
|
292
|
-
@node['merger'] = determine_merger
|
293
|
-
|
294
|
-
|
295
311
|
branches = (@ncid..children.size - 1).to_a
|
296
312
|
@node['branch_count'] = branches.count
|
297
313
|
|
298
|
-
coe = att('children_on_error', 'child_on_error')
|
299
|
-
# might be nil
|
300
|
-
|
301
314
|
branches
|
302
|
-
.map { |i|
|
303
|
-
execute_child(
|
304
|
-
i, 0, 'payload' => payload.copy_current, 'on_error_handler' => coe) }
|
315
|
+
.map { |i| execute_child(i, 0, 'payload' => payload.copy_current) }
|
305
316
|
.flatten(1)
|
306
317
|
#
|
307
318
|
# call execute for each of the (non _att) children
|
@@ -323,202 +334,34 @@ class Flor::Pro::Concurrence < Flor::Procedure
|
|
323
334
|
end
|
324
335
|
end
|
325
336
|
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
def receive_from_child_when_closed
|
330
|
-
|
331
|
-
ms = receive
|
332
|
-
|
333
|
-
return [] if ms.empty?
|
334
|
-
|
335
|
-
pop_on_receive_last || ms
|
336
|
-
end
|
337
|
-
|
338
|
-
def receive_from_branch
|
339
|
-
|
340
|
-
@node['payloads'][from] = @message['payload']
|
341
|
-
|
342
|
-
apply_receiver
|
343
|
-
end
|
344
|
-
|
345
|
-
def apply_receiver
|
346
|
-
|
347
|
-
if @node['receiver'].is_a?(String)
|
348
|
-
apply_receiver_method
|
349
|
-
else
|
350
|
-
apply_receiver_function
|
351
|
-
end
|
352
|
-
end
|
353
|
-
|
354
|
-
def apply_receiver_method
|
355
|
-
|
356
|
-
ret = send('rm__' + @node['receiver'])
|
357
|
-
msg = { 'payload' => { 'ret' => ret } }
|
358
|
-
|
359
|
-
receive_from_receiver(msg)
|
360
|
-
end
|
361
|
-
|
362
|
-
def apply_receiver_function
|
363
|
-
|
364
|
-
@node['on_receive_queue'] << from
|
365
|
-
|
366
|
-
dequeue_receiver_function
|
367
|
-
end
|
368
|
-
|
369
|
-
def dequeue_receiver_function
|
370
|
-
|
371
|
-
if @node['on_receive_nids']
|
372
|
-
[]
|
373
|
-
elsif f = @node['on_receive_queue'].shift
|
374
|
-
ms = apply(@node['receiver'], receiver_args(f), tree[2])
|
375
|
-
@node['on_receive_nids'] = [ ms.first['nid'], f ]
|
376
|
-
ms
|
377
|
-
else
|
378
|
-
[]
|
379
|
-
end
|
380
|
-
end
|
381
|
-
|
382
|
-
def receiver_args(from)
|
383
|
-
|
384
|
-
rs = Flor.dup(@node['payloads'])
|
385
|
-
|
386
|
-
[ [ 'reply', rs[from] ],
|
387
|
-
[ 'from', from ],
|
388
|
-
[ 'replies', rs ],
|
389
|
-
[ 'branch_count', @node['branch_count'] ],
|
390
|
-
[ 'over', !! @node['over'] ] ]
|
391
|
-
end
|
392
|
-
|
393
|
-
def receive_from_receiver(msg=message)
|
394
|
-
|
395
|
-
ret = msg['payload']['ret']
|
396
|
-
over = @node['over']
|
397
|
-
|
398
|
-
if ret.is_a?(Hash) && ret.keys == %w[ done payload ]
|
399
|
-
over = over || ret['done']
|
400
|
-
from = @node['on_receive_nids'][1]
|
401
|
-
@node['payloads'][from] = ret['payload']
|
402
|
-
else
|
403
|
-
over = over || ret
|
404
|
-
end
|
405
|
-
|
406
|
-
@node['on_receive_nids'] = nil
|
407
|
-
|
408
|
-
just_over = over && ! @node['over']
|
409
|
-
|
410
|
-
@node['over'] ||= just_over
|
411
|
-
|
412
|
-
if just_over
|
413
|
-
apply_merger
|
414
|
-
elsif ! over
|
415
|
-
[] # wait for more branches
|
416
|
-
else
|
417
|
-
receive_from_merger(nil)
|
418
|
-
end +
|
419
|
-
dequeue_receiver_function
|
420
|
-
end
|
421
|
-
|
422
|
-
def apply_merger
|
423
|
-
|
424
|
-
if @node['merger'].is_a?(String)
|
425
|
-
apply_merger_method
|
426
|
-
else
|
427
|
-
apply_merger_function
|
428
|
-
end
|
429
|
-
end
|
430
|
-
|
431
|
-
def apply_merger_method
|
337
|
+
def add
|
432
338
|
|
433
|
-
|
434
|
-
msg = { 'payload' => pld }
|
339
|
+
super
|
435
340
|
|
436
|
-
|
437
|
-
|
341
|
+
i = Flor.child_id(message['tnid'])
|
342
|
+
ts = message['trees']
|
438
343
|
|
439
|
-
|
344
|
+
@node['branch_count'] += ts.size
|
440
345
|
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
rs = Flor.dup(@node['payloads'])
|
447
|
-
|
448
|
-
[ [ 'rets', rs.inject({}) { |h, (k, v)| h[k] = v['ret']; h } ],
|
449
|
-
[ 'replies', rs ],
|
450
|
-
[ 'branch_count', @node['branch_count'] ] ]
|
451
|
-
end
|
452
|
-
|
453
|
-
def receive_from_merger(msg=message)
|
454
|
-
|
455
|
-
pl = msg ? msg['payload'] : {}
|
456
|
-
ret = pl['ret']
|
457
|
-
|
458
|
-
pl = ret['payload'] \
|
459
|
-
if ret.is_a?(Hash) && ret.keys == %w[ done payload ]
|
460
|
-
|
461
|
-
# TODO somehow, what if done is false, should we un-over the concurrence?
|
462
|
-
|
463
|
-
@node['merged_payload'] = pl \
|
464
|
-
if msg && ! @node.has_key?('merged_payload')
|
465
|
-
|
466
|
-
rem = determine_remainder
|
467
|
-
|
468
|
-
cancel_children(rem) + reply_to_parent(rem)
|
469
|
-
end
|
470
|
-
|
471
|
-
def rm__default_receive
|
472
|
-
|
473
|
-
@node['payloads'].size >= non_att_count
|
474
|
-
end
|
475
|
-
|
476
|
-
def rm__expect_integer_receive
|
477
|
-
|
478
|
-
@node['payloads'].size >= att(:expect)
|
479
|
-
end
|
480
|
-
|
481
|
-
def mm__default_merge
|
482
|
-
|
483
|
-
@node['payloads'].values
|
484
|
-
.reverse
|
485
|
-
.inject({}) { |h, pl| h.merge!(pl) }
|
486
|
-
end
|
487
|
-
|
488
|
-
def determine_remainder
|
489
|
-
|
490
|
-
att(:remaining, :rem) || 'cancel'
|
491
|
-
end
|
492
|
-
|
493
|
-
def determine_receiver
|
494
|
-
|
495
|
-
ex = att(:expect)
|
496
|
-
|
497
|
-
return 'expect_integer_receive' if ex && ex.is_a?(Integer) && ex > 0
|
498
|
-
|
499
|
-
att(:on_receive, :receiver) || 'default_receive'
|
500
|
-
end
|
501
|
-
|
502
|
-
def determine_merger
|
503
|
-
|
504
|
-
att(:on_merge, :merger) || 'default_merge'
|
346
|
+
ts
|
347
|
+
.collect.with_index { |t, j|
|
348
|
+
pl = Flor.dup(message['payload'] || node_payload.copy)
|
349
|
+
execute_child(i + j, 0, 'payload' => pl) }
|
350
|
+
.flatten(1)
|
505
351
|
end
|
506
352
|
|
507
|
-
|
353
|
+
protected
|
508
354
|
|
509
|
-
|
510
|
-
|
355
|
+
alias branch_count non_att_count
|
356
|
+
# used by ReceiveAndMerge to determine procedure end
|
511
357
|
|
512
|
-
def
|
358
|
+
def receive_from_child_when_closed
|
513
359
|
|
514
|
-
|
515
|
-
if @node['replied']
|
516
|
-
return [] \
|
517
|
-
if @node['payloads'].size < non_att_count && ( ! rem || rem == 'wait')
|
360
|
+
ms = receive
|
518
361
|
|
519
|
-
|
362
|
+
return [] if ms.empty?
|
520
363
|
|
521
|
-
|
364
|
+
pop_on_receive_last || ms
|
522
365
|
end
|
523
366
|
|
524
367
|
def make_on_def(cn, l)
|