flor 0.15.0 → 0.16.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (117) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +14 -1
  3. data/CREDITS.md +1 -0
  4. data/LICENSE.txt +1 -1
  5. data/Makefile +6 -2
  6. data/README.md +2 -1
  7. data/flor.gemspec +12 -2
  8. data/lib/flor.rb +3 -3
  9. data/lib/flor/colours.rb +1 -1
  10. data/lib/flor/conf.rb +3 -4
  11. data/lib/flor/core/executor.rb +31 -61
  12. data/lib/flor/core/node.rb +213 -96
  13. data/lib/flor/core/procedure.rb +194 -75
  14. data/lib/flor/core/texecutor.rb +6 -7
  15. data/lib/flor/djan.rb +41 -22
  16. data/lib/flor/flor.rb +137 -42
  17. data/lib/flor/id.rb +77 -59
  18. data/lib/flor/log.rb +43 -22
  19. data/lib/flor/migrations/0001_tables.rb +7 -7
  20. data/lib/flor/parser.rb +271 -74
  21. data/lib/flor/pcore/_apply.rb +108 -0
  22. data/lib/flor/pcore/_atom.rb +2 -4
  23. data/lib/flor/pcore/_att.rb +54 -37
  24. data/lib/flor/pcore/_dmute.rb +18 -0
  25. data/lib/flor/pcore/_dol.rb +17 -0
  26. data/lib/flor/pcore/_dqs.rb +35 -0
  27. data/lib/flor/pcore/_head.rb +25 -0
  28. data/lib/flor/pcore/_obj.rb +1 -3
  29. data/lib/flor/pcore/_pat_guard.rb +1 -1
  30. data/lib/flor/pcore/_pat_obj.rb +11 -3
  31. data/lib/flor/pcore/_pat_regex.rb +16 -2
  32. data/lib/flor/pcore/_ref.rb +51 -0
  33. data/lib/flor/pcore/_rxs.rb +27 -0
  34. data/lib/flor/pcore/_val.rb +11 -6
  35. data/lib/flor/pcore/{logo.rb → andor.rb} +4 -6
  36. data/lib/flor/pcore/apply.rb +72 -2
  37. data/lib/flor/pcore/arith.rb +16 -4
  38. data/lib/flor/pcore/array_qmark.rb +100 -0
  39. data/lib/flor/pcore/break.rb +1 -2
  40. data/lib/flor/pcore/case.rb +1 -1
  41. data/lib/flor/pcore/cmp.rb +3 -2
  42. data/lib/flor/pcore/collect.rb +2 -2
  43. data/lib/flor/pcore/cond.rb +19 -1
  44. data/lib/flor/pcore/cursor.rb +12 -11
  45. data/lib/flor/pcore/define.rb +30 -4
  46. data/lib/flor/pcore/do_return.rb +3 -0
  47. data/lib/flor/pcore/flatten.rb +39 -0
  48. data/lib/flor/pcore/if.rb +15 -5
  49. data/lib/flor/pcore/includes.rb +5 -2
  50. data/lib/flor/pcore/inject.rb +1 -1
  51. data/lib/flor/pcore/iterator.rb +28 -18
  52. data/lib/flor/pcore/keys.rb +2 -2
  53. data/lib/flor/pcore/map.rb +19 -1
  54. data/lib/flor/pcore/match.rb +2 -2
  55. data/lib/flor/pcore/matchr.rb +18 -5
  56. data/lib/flor/pcore/max.rb +51 -0
  57. data/lib/flor/pcore/merge.rb +134 -0
  58. data/lib/flor/pcore/move.rb +1 -1
  59. data/lib/flor/pcore/noret.rb +1 -1
  60. data/lib/flor/pcore/not.rb +15 -1
  61. data/lib/flor/pcore/on.rb +11 -0
  62. data/lib/flor/pcore/on_cancel.rb +5 -1
  63. data/lib/flor/pcore/on_error.rb +69 -4
  64. data/lib/flor/pcore/push.rb +4 -9
  65. data/lib/flor/pcore/range.rb +5 -5
  66. data/lib/flor/pcore/reduce.rb +5 -18
  67. data/lib/flor/pcore/return.rb +26 -0
  68. data/lib/flor/pcore/reverse.rb +4 -0
  69. data/lib/flor/pcore/sequence.rb +8 -1
  70. data/lib/flor/pcore/set.rb +74 -15
  71. data/lib/flor/pcore/shuffle.rb +71 -0
  72. data/lib/flor/pcore/slice.rb +137 -0
  73. data/lib/flor/pcore/sort.rb +244 -0
  74. data/lib/flor/pcore/sort_by.rb +67 -0
  75. data/lib/flor/pcore/split.rb +39 -0
  76. data/lib/flor/pcore/stall.rb +1 -1
  77. data/lib/flor/pcore/strings.rb +123 -0
  78. data/lib/flor/pcore/timestamp.rb +34 -0
  79. data/lib/flor/pcore/to_array.rb +2 -3
  80. data/lib/flor/pcore/twig.rb +1 -1
  81. data/lib/flor/pcore/type_of.rb +37 -0
  82. data/lib/flor/pcore/until.rb +3 -3
  83. data/lib/flor/punit/cancel.rb +3 -3
  84. data/lib/flor/punit/ccollect.rb +29 -0
  85. data/lib/flor/punit/cmap.rb +76 -20
  86. data/lib/flor/punit/concurrence.rb +440 -33
  87. data/lib/flor/punit/cron.rb +1 -1
  88. data/lib/flor/punit/every.rb +1 -1
  89. data/lib/flor/punit/graft.rb +2 -3
  90. data/lib/flor/punit/on_timeout.rb +5 -1
  91. data/lib/flor/punit/part.rb +63 -0
  92. data/lib/flor/punit/schedule.rb +1 -1
  93. data/lib/flor/punit/task.rb +52 -10
  94. data/lib/flor/punit/trap.rb +4 -5
  95. data/lib/flor/tools/shell.rb +37 -18
  96. data/lib/flor/unit/caller.rb +23 -11
  97. data/lib/flor/unit/executor.rb +33 -12
  98. data/lib/flor/unit/ganger.rb +10 -1
  99. data/lib/flor/unit/hook.rb +2 -1
  100. data/lib/flor/unit/hooker.rb +13 -2
  101. data/lib/flor/unit/loader.rb +7 -7
  102. data/lib/flor/unit/logger.rb +15 -17
  103. data/lib/flor/unit/models.rb +4 -2
  104. data/lib/flor/unit/models/execution.rb +83 -38
  105. data/lib/flor/unit/models/message.rb +16 -0
  106. data/lib/flor/unit/models/pointer.rb +24 -0
  107. data/lib/flor/unit/models/timer.rb +25 -4
  108. data/lib/flor/unit/models/trace.rb +14 -0
  109. data/lib/flor/unit/models/trap.rb +39 -14
  110. data/lib/flor/unit/scheduler.rb +11 -7
  111. data/lib/flor/unit/storage.rb +55 -39
  112. data/lib/flor/unit/taskers.rb +17 -14
  113. data/lib/flor/unit/waiter.rb +4 -3
  114. metadata +40 -10
  115. data/lib/flor/changes.rb +0 -26
  116. data/lib/flor/dollar.rb +0 -224
  117. data/lib/flor/unit/hooks.rb +0 -37
@@ -2,6 +2,30 @@
2
2
  module Flor
3
3
 
4
4
  class Pointer < FlorModel
5
+
6
+ #create_table :flor_pointers do
7
+ #
8
+ # primary_key :id, type: :Integer
9
+ # String :domain, null: false
10
+ # String :exid, null: false
11
+ # String :nid, null: false
12
+ # String :type, null: false # task, tasked, tag, var
13
+ # String :name, null: false # task name, tasked name, tag name, var name
14
+ # String :value
15
+ # String :ctime, null: false
16
+ #
17
+ # # no :status, no :mtime
18
+ #
19
+ # index :exid
20
+ # index [ :exid, :nid ]
21
+ # index [ :type, :name, :value ]
22
+ #
23
+ # String :cunit
24
+ # String :munit
25
+ #
26
+ # #unique [ :exid, :type, :name, :value ]
27
+ # # we don't care, pointers are cleaned anyway when the flow dies
28
+ #end
5
29
  end
6
30
  end
7
31
 
@@ -3,6 +3,29 @@ module Flor
3
3
 
4
4
  class Timer < FlorModel
5
5
 
6
+ #create_table :flor_timers do
7
+ #
8
+ # primary_key :id, type: :Integer
9
+ # String :domain, null: false
10
+ # String :exid, null: false
11
+ # String :nid, null: false
12
+ # String :type, null: false # 'at', 'in', 'cron', 'every', ...
13
+ # String :schedule, null: false # '20141128.103239' or '00 23 * * *'
14
+ # String :ntime # next time
15
+ # File :content # JSON msg to trigger
16
+ # Integer :count, null: false
17
+ # String :status, null: false
18
+ # String :ctime, null: false
19
+ # String :mtime, null: false
20
+ # String :cunit
21
+ # String :munit
22
+ # String :onid, null: false
23
+ # String :bnid, null: false
24
+ #
25
+ # index :exid
26
+ # index [ :exid, :nid ]
27
+ #end
28
+
6
29
  def to_trigger_message
7
30
 
8
31
  d = self.data(false)
@@ -12,8 +35,7 @@ module Flor
12
35
 
13
36
  sm = d['m']
14
37
 
15
- {
16
- 'point' => 'trigger',
38
+ { 'point' => 'trigger',
17
39
  'exid' => self.exid,
18
40
  'nid' => self.onid,
19
41
  'bnid' => self.nid,
@@ -21,8 +43,7 @@ module Flor
21
43
  'schedule' => self.schedule,
22
44
  'timer_id' => self.id,
23
45
  'message' => m,
24
- 'sm' => sm
25
- }
46
+ 'sm' => sm }
26
47
  end
27
48
 
28
49
  def ntime_t
@@ -2,6 +2,20 @@
2
2
  module Flor
3
3
 
4
4
  class Trace < FlorModel
5
+
6
+ #create_table :flor_traces do
7
+ #
8
+ # primary_key :id, type: :Integer
9
+ # String :domain, null: false
10
+ # String :exid, null: false
11
+ # String :nid, null: true
12
+ # String :tracer, null: false # 'executor', 'trace'
13
+ # String :text, null: false # 'blah blah blah'
14
+ # String :ctime, null: false
15
+ # String :cunit
16
+ #
17
+ # index :exid
18
+ #end
5
19
  end
6
20
  end
7
21
 
@@ -3,6 +3,36 @@ module Flor
3
3
 
4
4
  class Trap < FlorModel
5
5
 
6
+ #create_table :flor_traps do
7
+ #
8
+ # primary_key :id, type: :Integer
9
+ # String :domain, null: false
10
+ # String :exid, null: false
11
+ # String :onid, null: false
12
+ # String :nid, null: false
13
+ # #
14
+ # TrueClass :tconsumed, null: false, default: false
15
+ # String :trange, null: false
16
+ # String :tpoints, null: true
17
+ # String :ttags, null: true
18
+ # String :theats, null: true
19
+ # String :theaps, null: true
20
+ # #
21
+ # File :content # JSON msg to trigger
22
+ # #
23
+ # String :status, null: false
24
+ # String :ctime, null: false
25
+ # String :mtime, null: false
26
+ #
27
+ # String :cunit
28
+ # String :munit
29
+ #
30
+ # String :bnid, null: false
31
+ #
32
+ # index :exid
33
+ # index [ :exid, :nid ]
34
+ #end
35
+
6
36
  def to_hook
7
37
 
8
38
  opts = {}
@@ -72,19 +102,14 @@ module Flor
72
102
 
73
103
  msg['trap_id'] = self.id
74
104
 
75
- if vs = msg['vars']
76
-
77
- k = vs.keys.find { |k| k != 'arguments' } || 'msg'
78
- vs[k] = message
105
+ args = msg['arguments'] = [ [ 'msg', message ] ]
79
106
 
80
- if sig = message['point'] == 'signal' && message['name']
81
- vs['sig'] = sig
82
- end
107
+ if sig = (message['point'] == 'signal' && message['name'])
108
+ args << [ 'sig', sig ]
83
109
  end
84
-
85
110
  if dat['pl'] == 'event'
86
- (msg['vars'] ||= {})['payload'] = msg['payload']
87
- msg['payload'] = Flor.dup(message['payload'])
111
+ args << [ 'payload', msg['payload'] ]
112
+ msg['payload'] = Flor.dup(message['payload']) # FIXME try without this line...
88
113
  end
89
114
 
90
115
  { 'point' => 'trigger',
@@ -95,15 +120,15 @@ module Flor
95
120
  'trap_id' => self.id,
96
121
  'message' => msg,
97
122
  'sm' => message['m'] }
98
- #'dbg' => xx
99
- #.tap { |m| pp m['message'] }
100
- #.tap { |m| pp m }
123
+ #.tap { |m| pp m }
124
+ #.tap { |m| pp m['message'] }
125
+ #'dbg' => xx }
101
126
  end
102
127
 
103
128
  def to_hash
104
129
 
105
130
  values
106
- .inject({}) { |h, (k, v)| h[k.to_s ] = v if k != :content; h }
131
+ .inject({}) { |h, (k, v)| h[k.to_s] = v if k != :content; h }
107
132
  end
108
133
 
109
134
  def do_split(v)
@@ -150,7 +150,7 @@ module Flor
150
150
  @thread_status = :running
151
151
 
152
152
  @thread =
153
- if @thread
153
+ if defined?(@thread) && @thread
154
154
  @thread.run
155
155
  else
156
156
  Thread.new do
@@ -242,12 +242,16 @@ module Flor
242
242
 
243
243
  def return(message)
244
244
 
245
- queue({
246
- 'point' => 'return',
247
- 'exid' => message['exid'],
248
- 'nid' => message['nid'],
249
- 'payload' => message['payload'],
250
- 'tasker' => message['tasker'] })
245
+ m =
246
+ if message['point'] == 'failed'
247
+ message
248
+ else
249
+ message
250
+ .select { |k, _| %w[ exid nid payload tasker ].include?(k) }
251
+ .merge!('point' => 'return')
252
+ end
253
+
254
+ queue(m)
251
255
 
252
256
  nil
253
257
  end
@@ -73,7 +73,15 @@ module Flor
73
73
  end
74
74
  end
75
75
 
76
- def migrate(to=nil, from=nil)
76
+ def migrate(to=nil, from=nil, opts=nil)
77
+
78
+ opts = [ to, from, opts ].find { |e| e.is_a?(Hash) } || {}
79
+ opts[:target] ||= to if to.is_a?(Integer)
80
+ opts[:current] ||= from if from.is_a?(Integer)
81
+ #
82
+ # defaults for the migration version table:
83
+ #:table => :schema_info
84
+ #:column => :version
77
85
 
78
86
  dir =
79
87
  @unit.conf['db_migrations'] ||
@@ -83,13 +91,7 @@ module Flor
83
91
 
84
92
  synchronize do
85
93
 
86
- Sequel::Migrator.run(
87
- @db, dir,
88
- :target => to, :current => from)
89
-
90
- # defaults for the migration version table:
91
- #:table => :schema_info
92
- #:column => :version
94
+ Sequel::Migrator.run(@db, dir, opts)
93
95
  end
94
96
  end
95
97
 
@@ -107,9 +109,8 @@ module Flor
107
109
  .first(exid: exid) # status active or terminated doesn't matter
108
110
 
109
111
  return {
110
- 'exid' => exid, 'nodes' => {}, 'errors' => [], 'tasks' => {},
111
- 'counters' => {}, 'start' => Flor.tstamp,
112
- 'size' => -1
112
+ 'exid' => exid, 'nodes' => {}, 'counters' => {},
113
+ 'start' => Flor.tstamp, 'size' => 0
113
114
  } unless e
114
115
 
115
116
  ex = from_blob(e[:content])
@@ -117,7 +118,7 @@ module Flor
117
118
  fail("couldn't parse execution (db id #{e[:id].to_i})") unless ex
118
119
 
119
120
  ex['id'] = e[:id].to_i
120
- ex['size'] = e[:content].length
121
+ ex['size'] = e[:content].size
121
122
 
122
123
  ex
123
124
  end
@@ -141,7 +142,8 @@ module Flor
141
142
  end
142
143
 
143
144
  data = to_blob(exe)
144
- exe['size'] = data.length
145
+ exe['size'] = data.size
146
+
145
147
  u = @unit.identifier
146
148
 
147
149
  transync do
@@ -179,6 +181,7 @@ module Flor
179
181
  end
180
182
 
181
183
  exe
184
+ # return the execution hash
182
185
 
183
186
  rescue => err
184
187
 
@@ -309,14 +312,29 @@ module Flor
309
312
 
310
313
  synchronize(syn) do
311
314
 
315
+ stored, unstored = ms.partition { |m| m['mid'] }
316
+
317
+ #
318
+ # de-reserve any previously stored message, might happen
319
+ # for "terminated" messages that got queued back to let
320
+ # other messages get processed
321
+
322
+ @db[:flor_messages]
323
+ .where(id: stored.collect { |m| m['mid'] })
324
+ .update(status: 'created', mtime: n, munit: u) \
325
+ if stored.any?
326
+
327
+ #
328
+ # store new messages
329
+
312
330
  @db[:flor_messages]
313
331
  .import(
314
332
  [ :domain, :exid, :point, :content,
315
333
  :status, :ctime, :mtime, :cunit, :munit ],
316
- ms.map { |m|
334
+ unstored.map { |m|
317
335
  [ Flor.domain(m['exid']), m['exid'], m['point'], to_blob(m),
318
- 'created', n, n, u, u ]
319
- })
336
+ 'created', n, n, u, u ] }) \
337
+ if unstored.any?
320
338
  end
321
339
 
322
340
  @unit.wake_up
@@ -646,7 +664,8 @@ module Flor
646
664
 
647
665
  def update_pointers(exe, status, now)
648
666
 
649
- # TODO archive old pointers???
667
+ # TODO should we archive old pointers?
668
+
650
669
  exid = exe['exid']
651
670
 
652
671
  if status == 'terminated'
@@ -666,30 +685,27 @@ module Flor
666
685
  dom = Flor.domain(exid)
667
686
  u = @unit.identifier
668
687
 
669
- pointers =
670
- exe['nodes'].inject([]) { |a, (nid, node)|
688
+ pointers = exe['nodes']
689
+ .inject([]) { |a, (nid, node)|
690
+
671
691
  ts = node['tags']
672
- ts.each { |t| a << [ dom, exid, nid, 'tag', t, nil, now, u ] } if ts
673
- a
674
- }
692
+ ts.each { |t|
693
+ a << [ dom, exid, nid, 'tag', t, nil, now, u ] } if ts
675
694
 
676
- pointers +=
677
- (exe['nodes']['0'] || { 'vars' => {} })['vars'].collect { |k, v|
678
- case v; when Integer, String, TrueClass, FalseClass
679
- [ dom, exid, '0', 'var', k, v.to_s, now, u ]
680
- when NilClass
681
- [ dom, exid, '0', 'var', k, nil, now, u ]
682
- else
683
- nil
684
- end
685
- }.compact
695
+ vs = nid == '0' ? node['vars'] : nil
696
+ vs.each { |k, v|
697
+ case v; when Integer, String, TrueClass, FalseClass
698
+ a << [ dom, exid, '0', 'var', k, v.to_s, now, u ]
699
+ when NilClass
700
+ a << [ dom, exid, '0', 'var', k, nil, now, u ]
701
+ end } if vs
702
+
703
+ #ta = node['heap'] == 'task' ? node['task'] : nil
704
+ ta = node['task']
705
+ a << [ dom, exid, nid, 'tasker', ta['tasker'], ta['name'], now, u ] \
706
+ if ta
686
707
 
687
- pointers +=
688
- exe['tasks']
689
- .reject { |_, v|
690
- v['tasker'] == nil }
691
- .collect { |nid, v|
692
- [ dom, exid, nid, 'tasker', v['tasker'], v['name'], now, u ] }
708
+ a }
693
709
 
694
710
  cps = @db[:flor_pointers] # current pointers
695
711
  .where(exid: exid)
@@ -770,7 +786,7 @@ module Flor
770
786
 
771
787
  @db.extension(:connection_validator)
772
788
  @db.pool.connection_validation_timeout = to
773
- # NB: -1 means "check all the time"
789
+ # NB: -1 means "check at every use"
774
790
  end
775
791
 
776
792
  @db_logger = DbLogger.new(@unit)
@@ -14,12 +14,6 @@ module Flor
14
14
 
15
15
  protected
16
16
 
17
- def return(force=false)
18
-
19
- @ganger.return(@message) if force || @ganger
20
- end
21
- alias reply return
22
-
23
17
  def exid; @message['exid']; end
24
18
  def nid; @message['nid']; end
25
19
 
@@ -46,22 +40,31 @@ module Flor
46
40
 
47
41
  if name.is_a?(String)
48
42
 
49
- [
50
- Flor.dup_and_merge(
43
+ [ Flor.dup_and_merge(
51
44
  @message,
52
45
  'tasker' => name, 'original_tasker' => @message['tasker'],
53
- 'routed' => true)
54
- ]
46
+ 'routed' => true) ]
55
47
 
56
48
  else
57
49
 
58
- [
59
- Flor.dup_and_merge(
50
+ [ Flor.dup_and_merge(
60
51
  @message,
61
- 'routed' => !! name)
62
- ]
52
+ 'routed' => !! name) ]
63
53
  end
64
54
  end
55
+
56
+ def reply(message=@message, force=false)
57
+
58
+ @ganger.return(message) if force || @ganger
59
+
60
+ [] # very important, return no further messages
61
+ end
62
+
63
+ def reply_with_error(error)
64
+
65
+ reply(
66
+ Flor.to_error_message(@message, error))
67
+ end
65
68
  end
66
69
  end
67
70
 
@@ -63,7 +63,8 @@ module Flor
63
63
 
64
64
  if @queue.empty?
65
65
  fail RuntimeError.new(
66
- "timeout for #{self.to_s}") if @on_timeout == 'fail'
66
+ "timeout for #{self.to_s}"
67
+ ) if @on_timeout == 'fail'
67
68
  return { 'exid' => @exid, 'timed_out' => @on_timeout }
68
69
  end
69
70
  end
@@ -123,8 +124,8 @@ module Flor
123
124
  return s if s.is_a?(Array) && s.collect(&:class).uniq == [ Array ]
124
125
 
125
126
  (s.is_a?(String) ? s.split(';') : s)
126
- .collect { |s|
127
- ni, pt = s.strip.match(/\A([0-9_\-]+)? *([a-z|, ]+)\z/)[1, 2]
127
+ .collect { |ss|
128
+ ni, pt = ss.strip.match(/\A([0-9_\-]+)? *([a-z|, ]+)\z/)[1, 2]
128
129
  [ ni, pt.split(/[|,]/).collect(&:strip) ]
129
130
  }
130
131
  end