flor 0.11.0 → 0.12.0

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.
Files changed (60) hide show
  1. data/CHANGELOG.md +7 -0
  2. data/Makefile +3 -0
  3. data/lib/flor.rb +1 -1
  4. data/lib/flor/colours.rb +7 -3
  5. data/lib/flor/conf.rb +21 -15
  6. data/lib/flor/core/executor.rb +71 -77
  7. data/lib/flor/core/node.rb +6 -1
  8. data/lib/flor/core/procedure.rb +112 -58
  9. data/lib/flor/core/texecutor.rb +6 -5
  10. data/lib/flor/log.rb +9 -7
  11. data/lib/flor/migrations/0003_timer_onid_bnid.rb +35 -0
  12. data/lib/flor/migrations/0004_trap_bnid.rb +16 -0
  13. data/lib/flor/pcore/_arr.rb +2 -2
  14. data/lib/flor/pcore/_atom.rb +1 -1
  15. data/lib/flor/pcore/_att.rb +59 -13
  16. data/lib/flor/pcore/_happly.rb +3 -3
  17. data/lib/flor/pcore/_obj.rb +22 -2
  18. data/lib/flor/pcore/_skip.rb +2 -2
  19. data/lib/flor/pcore/apply.rb +1 -1
  20. data/lib/flor/pcore/arith.rb +1 -1
  21. data/lib/flor/pcore/break.rb +2 -2
  22. data/lib/flor/pcore/case.rb +1 -1
  23. data/lib/flor/pcore/cmp.rb +1 -1
  24. data/lib/flor/pcore/cond.rb +1 -1
  25. data/lib/flor/pcore/cursor.rb +2 -2
  26. data/lib/flor/pcore/define.rb +1 -1
  27. data/lib/flor/pcore/fail.rb +1 -6
  28. data/lib/flor/pcore/if.rb +2 -2
  29. data/lib/flor/pcore/map.rb +1 -1
  30. data/lib/flor/pcore/matchr.rb +92 -0
  31. data/lib/flor/pcore/move.rb +2 -3
  32. data/lib/flor/pcore/noeval.rb +1 -1
  33. data/lib/flor/pcore/noret.rb +1 -1
  34. data/lib/flor/pcore/push.rb +1 -1
  35. data/lib/flor/pcore/rand.rb +1 -1
  36. data/lib/flor/pcore/set.rb +1 -1
  37. data/lib/flor/pcore/twig.rb +2 -2
  38. data/lib/flor/pcore/until.rb +4 -1
  39. data/lib/flor/pcore/val.rb +1 -1
  40. data/lib/flor/punit/cancel.rb +2 -3
  41. data/lib/flor/punit/cmap.rb +5 -6
  42. data/lib/flor/punit/concurrence.rb +3 -5
  43. data/lib/flor/punit/schedule.rb +20 -5
  44. data/lib/flor/punit/signal.rb +1 -1
  45. data/lib/flor/punit/sleep.rb +2 -2
  46. data/lib/flor/punit/task.rb +3 -3
  47. data/lib/flor/punit/trace.rb +1 -1
  48. data/lib/flor/punit/trap.rb +22 -6
  49. data/lib/flor/to_string.rb +2 -1
  50. data/lib/flor/unit/executor.rb +3 -5
  51. data/lib/flor/unit/hooker.rb +2 -3
  52. data/lib/flor/unit/models/timer.rb +9 -3
  53. data/lib/flor/unit/models/trap.rb +1 -0
  54. data/lib/flor/unit/scheduler.rb +40 -35
  55. data/lib/flor/unit/storage.rb +70 -59
  56. data/lib/flor/unit/waiter.rb +2 -3
  57. data/t.txt +4 -0
  58. metadata +6 -4
  59. data/fail.txt +0 -3
  60. data/lib/flor/pcore/match.rb +0 -46
@@ -21,7 +21,7 @@ class Flor::Pro::Trace < Flor::Procedure
21
21
 
22
22
  payload['ret'] = node_payload_ret
23
23
 
24
- reply
24
+ wrap
25
25
  end
26
26
  end
27
27
 
@@ -42,13 +42,14 @@ class Flor::Pro::Trap < Flor::Procedure
42
42
 
43
43
  msg =
44
44
  if fun
45
- apply(fun, [], tree[2], false).first.merge('noreply' => true)
45
+ apply(fun, [], tree[2], false).first
46
46
  else
47
- reply.first
47
+ wrap_reply.first
48
48
  end
49
49
 
50
50
  tra = {}
51
- tra['bnid'] = parent || '0' # shouldn't it be [the real] root?
51
+ tra['nid'] = nid
52
+ tra['bnid'] = parent || '0'
52
53
  tra['points'] = points
53
54
  tra['tags'] = tags
54
55
  tra['heaps'] = heaps
@@ -63,14 +64,29 @@ class Flor::Pro::Trap < Flor::Procedure
63
64
 
64
65
  tra['range'] = att('range') || att('scope') || 'subnid'
65
66
 
66
- reply('point' => 'trap','nid' => nid, 'trap' => tra) +
67
- (fun ? reply : [])
67
+ @node['trapped'] = true
68
+
69
+ wrap('point' => 'trap', 'nid' => nid, 'trap' => tra) +
70
+ (fun ? flank : [])
68
71
  end
69
72
 
70
73
  def receive_last
71
74
 
72
- #fail ArgumentError.new('trap requires a function')
73
75
  receive_non_att
74
76
  end
77
+
78
+ def receive
79
+
80
+ return [] if @node['trapped']
81
+ super
82
+ end
83
+
84
+ # "trap" keeps track of its children, but does not cascade 'cancel' to them,
85
+ # unless the cancel flavour is 'kill'.
86
+ #
87
+ def wrap_cancel_children(h={})
88
+
89
+ h['flavour'] == 'kill' ? super : []
90
+ end
75
91
  end
76
92
 
@@ -37,8 +37,9 @@ module Flor
37
37
 
38
38
  def self.node_status_to_s(n)
39
39
 
40
- s = StringIO.new
41
40
  stas = n['status'].reverse
41
+
42
+ s = StringIO.new
42
43
  while sta = stas.shift
43
44
  s << '(status ' << (sta['status'] || 'o') # o for open
44
45
  s << ' pt:' << sta['point']
@@ -70,8 +70,6 @@ module Flor
70
70
  m = @messages.shift
71
71
  end
72
72
 
73
- point = m['point']
74
-
75
73
  ms = process(m)
76
74
 
77
75
  @consumed << m
@@ -86,11 +84,11 @@ module Flor
86
84
  @unit.storage.put_messages(oms)
87
85
  end
88
86
 
89
- @unit.storage.consume(@consumed)
90
-
91
87
  @alive = false
92
88
 
93
89
  @unit.storage.put_execution(@execution)
90
+ @unit.storage.consume(@consumed)
91
+
94
92
  @unit.storage.put_messages(@messages)
95
93
 
96
94
  du = Time.now - t0
@@ -135,7 +133,7 @@ module Flor
135
133
 
136
134
  def schedule(message)
137
135
 
138
- @unit.put_timer(message)
136
+ @unit.schedule(message)
139
137
 
140
138
  []
141
139
  end
@@ -134,10 +134,10 @@ module Flor
134
134
 
135
135
  if hook.is_a?(Flor::Trap) && o(opts, :subnid)
136
136
  if node = executor.node(message['nid'], true)
137
- return false unless node.descendant_of?(hook.nid, true)
137
+ return false unless node.descendant_of?(hook.bnid, true)
138
138
  node = node.h
139
139
  else
140
- return false if hook.nid != '0'
140
+ return false if hook.bnid != '0'
141
141
  end
142
142
  end
143
143
 
@@ -145,7 +145,6 @@ module Flor
145
145
  return false unless node ||= executor.node(message['nid'])
146
146
  return false unless hps.include?(node['heap'])
147
147
  end
148
- #p :yyy if hook.is_a?(Flor::Trap)
149
148
 
150
149
  if hts = o(opts, :heat, :ht, [])
151
150
  return false unless node ||= executor.node(message['nid'])
@@ -5,17 +5,23 @@ module Flor
5
5
 
6
6
  def to_trigger_message
7
7
 
8
- m = self.data(false)['message']
8
+ d = self.data(false)
9
+
10
+ m = d['message']
9
11
  m['timer_id'] = self.id
10
12
 
13
+ sm = d['m']
14
+
11
15
  {
12
16
  'point' => 'trigger',
13
17
  'exid' => self.exid,
14
- 'nid' => self.nid,
18
+ 'nid' => self.onid,
19
+ 'bnid' => self.nid,
15
20
  'type' => self.type,
16
21
  'schedule' => self.schedule,
17
22
  'timer_id' => self.id,
18
- 'message' => m
23
+ 'message' => m,
24
+ 'sm' => sm
19
25
  }
20
26
  end
21
27
 
@@ -89,6 +89,7 @@ module Flor
89
89
  'trap' => to_hash,
90
90
  'trap_id' => self.id,
91
91
  'message' => msg,
92
+ 'sm' => message['m'],
92
93
  #'dbg' => xx
93
94
  }#.tap { |m| pp m }
94
95
  end
@@ -14,9 +14,7 @@ module Flor
14
14
 
15
15
  def initialize(conf={}, over_conf={})
16
16
 
17
- @conf = conf.is_a?(Hash) ? conf : Flor::Conf.read(conf)
18
- @conf.merge!(Flor::Conf.read_env)
19
- @conf.merge!(over_conf)
17
+ @conf = Flor::Conf.prepare(conf, over_conf)
20
18
 
21
19
  fail ArgumentError.new(
22
20
  "invalid domain name #{@conf['domain']}"
@@ -65,7 +63,7 @@ module Flor
65
63
  #
66
64
  Kernel.const_set(c, self) if c
67
65
 
68
- @archive = nil # used, so far, only for testing
66
+ @archive = @conf['archive'] ? {} : nil # used, so far, only for testing
69
67
  end
70
68
 
71
69
  def name
@@ -254,27 +252,26 @@ module Flor
254
252
  nil
255
253
  end
256
254
 
257
- def cancel(h)
255
+ def cancel(exid, *as)
258
256
 
259
- queue(prepare_message('cancel', h), h)
257
+ queue(*prepare_message('cancel', [ exid, *as ]))
260
258
  end
261
259
 
262
260
  def signal(name, h={})
263
261
 
264
262
  h[:payload] ||= {}
265
263
  h[:name] ||= name
266
- queue(prepare_message('signal', h), h)
264
+
265
+ queue(*prepare_message('signal', [ h ]))
267
266
  end
268
267
 
269
- def re_apply(h)
268
+ def re_apply(exid, *as)
270
269
 
271
- queue(prepare_message('cancel', h.merge(re_apply: true)), h)
270
+ queue(*prepare_message('cancel', [ exid, *as, { re_apply: true } ]))
272
271
  end
273
272
 
274
- def put_timer(message)
273
+ def schedule(message)
275
274
 
276
- #timer = @storage.put_timer(message)
277
- #@mutex.synchronize { @timers.push(timer).sort_by!(&:ntime) }
278
275
  @storage.put_timer(message)
279
276
  end
280
277
 
@@ -304,16 +301,14 @@ module Flor
304
301
  @storage.put_trap(node, tra)
305
302
  end
306
303
 
307
- def remove_node(exid, n)
304
+ def archive_node(exid, node)
308
305
 
309
- #@storage.remove_node(exid, n)
310
- # done in Storage#put_execution
306
+ (@archive[exid] ||= {})[node['nid']] = Flor.dup(node) if @archive
307
+ end
311
308
 
312
- #@mutex.synchronize do
313
- # @timers.reject! { |t| t.exid == exid && t.nid == n['nid'] }
314
- #end
309
+ def archived_node(exid, nid)
315
310
 
316
- (@archive[exid] ||= {})[n['nid']] = Flor.dup(n) if @archive
311
+ (@archive[exid] || {})[nid]
317
312
  end
318
313
 
319
314
  def executor(exid)
@@ -362,35 +357,45 @@ module Flor
362
357
  puts on_start_exc(ex)
363
358
  end
364
359
 
365
- def prepare_on_receive_last(h)
360
+ def prepare_on_receive_last(msg, opts)
366
361
 
367
- ei = h[:exid] || h['exid']
368
- ni = h[:nid] || h['nid']
369
- t = h[:tree] || h['tree']
370
- pl = h[:payload] || h['payload']
362
+ fail ArgumentError.new("missing 'payload' to re_apply") \
363
+ unless msg['payload']
371
364
 
372
- fail ArgumentError.new('missing :payload to re_apply') unless pl
373
-
374
- t = Flor::Lang.parse(t, 're_apply', {})
365
+ t = Flor::Lang.parse(opts[:tree], 're_apply', {})
375
366
 
376
367
  [
377
368
  { 'point' => 'execute',
378
- 'exid' => ei, 'nid' => ni,
369
+ 'exid' => msg['exid'], 'nid' => msg['nid'],
379
370
  'from' => 'parent',
380
371
  'tree' => t,
381
- 'payload' => pl }
372
+ 'payload' => msg['payload'] }
382
373
  ]
383
374
  end
384
375
 
385
- def prepare_message(point, h)
376
+ def prepare_message(point, args)
377
+
378
+ h =
379
+ args.inject({}) { |hh, a|
380
+ if a.is_a?(Hash) then a.each { |k, v| hh[k.to_s] = v }
381
+ elsif ! hh.has_key?('exid') then hh['exid'] = a
382
+ elsif ! hh.has_key?('nid') then hh['nid'] = a
383
+ end
384
+ hh }
386
385
 
387
386
  msg = { 'point' => point }
387
+ opts = {}
388
388
 
389
- [ :exid, :name, :nid, :payload, :on_receive_last ]
390
- .each { |k| v = h[k] || h[k.to_s]; msg[k.to_s] = v if v }
389
+ h.each do |k, v|
390
+ if %w[ exid name nid payload on_receive_last ].include?(k)
391
+ msg[k] = v
392
+ else
393
+ opts[k.to_sym] = v
394
+ end
395
+ end
391
396
 
392
- if h[:re_apply]
393
- msg['on_receive_last'] = prepare_on_receive_last(h)
397
+ if opts[:re_apply]
398
+ msg['on_receive_last'] = prepare_on_receive_last(msg, opts)
394
399
  end
395
400
 
396
401
  fail ArgumentError.new('missing :exid key') \
@@ -398,7 +403,7 @@ module Flor
398
403
  fail ArgumentError.new('missing :name string key') \
399
404
  if point == 'signal' && ! msg['name'].is_a?(String)
400
405
 
401
- msg
406
+ [ msg, opts ]
402
407
  end
403
408
 
404
409
  def make_idle_message
@@ -121,27 +121,25 @@ module Flor
121
121
  end
122
122
  end
123
123
 
124
- def put_execution(ex)
124
+ def put_execution(exe)
125
125
 
126
126
  status =
127
- if ex['nodes']['0'] && ex['nodes']['0']['removed']
128
- 'terminated'
129
- else
130
- 'active'
131
- end
127
+ exe['nodes'].find { |_, n| n['status'].last['status'] != 'ended' } ?
128
+ 'active' :
129
+ 'terminated'
132
130
 
133
- id = ex['id']
131
+ id = exe['id']
134
132
 
135
133
  if id
136
134
 
137
- ex['end'] ||= Flor.tstamp \
135
+ exe['end'] ||= Flor.tstamp \
138
136
  if status == 'terminated'
139
- ex['duration'] = Time.parse(ex['end']) - Time.parse(ex['start']) \
140
- if ex['end']
137
+ exe['duration'] = Time.parse(exe['end']) - Time.parse(exe['start']) \
138
+ if exe['end']
141
139
  end
142
140
 
143
- data = to_blob(ex)
144
- ex['size'] = data.length
141
+ data = to_blob(exe)
142
+ exe['size'] = data.length
145
143
  u = @unit.identifier
146
144
 
147
145
  transync do
@@ -160,13 +158,13 @@ module Flor
160
158
 
161
159
  else
162
160
 
163
- ex['id'] =
161
+ exe['id'] =
164
162
  @db[:flor_executions]
165
163
  .insert(
166
- domain: Flor.domain(ex['exid']),
167
- exid: ex['exid'],
164
+ domain: Flor.domain(exe['exid']),
165
+ exid: exe['exid'],
168
166
  content: data,
169
- status: 'active',
167
+ status: status,
170
168
  ctime: now,
171
169
  mtime: now,
172
170
  cunit: u,
@@ -174,15 +172,15 @@ module Flor
174
172
  .to_i
175
173
  end
176
174
 
177
- remove_nodes(ex, status, now)
178
- update_pointers(ex, status, now)
175
+ remove_nodes(exe, status, now)
176
+ update_pointers(exe, status, now)
179
177
  end
180
178
 
181
- ex
179
+ exe
182
180
 
183
181
  rescue => err
184
182
 
185
- Thread.current[:sto_errored_items] = [ ex ]
183
+ Thread.current[:sto_errored_items] = [ exe ]
186
184
  raise err
187
185
  end
188
186
 
@@ -351,6 +349,13 @@ module Flor
351
349
  .where { mtime < tstamp }
352
350
  .update(status: 'created')
353
351
  end
352
+
353
+ rescue => err
354
+
355
+ @unit.logger.warn(
356
+ "#{self.class}#unreserve_messages(#{max_sec})", err, '(returning nil)')
357
+
358
+ -1 # not zero, to indicate a problem
354
359
  end
355
360
 
356
361
  def put_timer(message)
@@ -364,20 +369,23 @@ module Flor
364
369
 
365
370
  synchronize do
366
371
 
367
- @db[:flor_timers].insert(
368
- domain: Flor.domain(message['exid']),
369
- exid: message['exid'],
370
- nid: message['nid'],
371
- type: type,
372
- schedule: string,
373
- ntime: next_time,
374
- content: to_blob(message),
375
- count: 0,
376
- status: 'active',
377
- ctime: now,
378
- mtime: now,
379
- cunit: u,
380
- munit: u)
372
+ @db[:flor_timers]
373
+ .insert(
374
+ domain: Flor.domain(message['exid']),
375
+ exid: message['exid'],
376
+ nid: message['nid'],
377
+ onid: message['onid'] || message['nid'],
378
+ bnid: message['nid'],
379
+ type: type,
380
+ schedule: string,
381
+ ntime: next_time,
382
+ content: to_blob(message),
383
+ count: 0,
384
+ status: 'active',
385
+ ctime: now,
386
+ mtime: now,
387
+ cunit: u,
388
+ munit: u)
381
389
  end
382
390
 
383
391
  @unit.wake_up
@@ -414,22 +422,24 @@ module Flor
414
422
  id =
415
423
  synchronize do
416
424
 
417
- @db[:flor_traps].insert(
418
- domain: dom,
419
- exid: exid,
420
- nid: tra['bnid'],
421
- onid: node['nid'],
422
- trange: tra['range'],
423
- tpoints: tra['points'],
424
- ttags: tra['tags'],
425
- theats: tra['heats'],
426
- theaps: tra['heaps'],
427
- content: to_blob(tra),
428
- status: 'active',
429
- ctime: now,
430
- mtime: now,
431
- cunit: u,
432
- munit: u)
425
+ @db[:flor_traps]
426
+ .insert(
427
+ domain: dom,
428
+ exid: exid,
429
+ nid: tra['nid'],
430
+ onid: tra['onid'] || tra['nid'],
431
+ bnid: tra['bnid'],
432
+ trange: tra['range'],
433
+ tpoints: tra['points'],
434
+ ttags: tra['tags'],
435
+ theats: tra['heats'],
436
+ theaps: tra['heaps'],
437
+ content: to_blob(tra),
438
+ status: 'active',
439
+ ctime: now,
440
+ mtime: now,
441
+ cunit: u,
442
+ munit: u)
433
443
  end
434
444
 
435
445
  traps[id]
@@ -446,14 +456,15 @@ module Flor
446
456
 
447
457
  synchronize do
448
458
 
449
- @db[:flor_traces].insert(
450
- domain: Flor.domain(exid),
451
- exid: exid,
452
- nid: nid,
453
- tracer: tracer,
454
- text: text,
455
- ctime: Flor.tstamp,
456
- cunit: @unit.identifier)
459
+ @db[:flor_traces]
460
+ .insert(
461
+ domain: Flor.domain(exid),
462
+ exid: exid,
463
+ nid: nid,
464
+ tracer: tracer,
465
+ text: text,
466
+ ctime: Flor.tstamp,
467
+ cunit: @unit.identifier)
457
468
  end
458
469
  end
459
470
 
@@ -558,7 +569,7 @@ module Flor
558
569
 
559
570
  exid = exe['exid']
560
571
 
561
- x = status == 'terminated' ? {} : { nid: exe['nodes'].keys }
572
+ x = (status == 'terminated') ? {} : { nid: exe['nodes'].keys }
562
573
  # if 'terminated' include all nodes
563
574
 
564
575
  if @archive