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
@@ -58,23 +58,21 @@ module Flor
58
58
 
59
59
  (@unit.conf['exe_max_messages'] || 77).times do |i|
60
60
 
61
+ break if @shutdown
62
+
61
63
  m = @messages.shift
62
64
  break unless m
63
- break if @shutdown
64
65
 
65
- if m['point'] == 'terminated' && @messages.any?
66
- #
67
- # try to handle 'terminated' last
68
- #
69
- @messages << m
70
- m = @messages.shift
71
- end
66
+ m = (@messages << m).shift \
67
+ if m['point'] == 'terminated' && @messages.any?
68
+ #
69
+ # handle 'terminated' messages last
72
70
 
73
71
  ms = process(m)
74
72
 
75
73
  @consumed << m
76
74
 
77
- ims, oms = ms.partition { |m| m['exid'] == @exid }
75
+ ims, oms = ms.partition { |mm| mm['exid'] == @exid }
78
76
  # qui est "in", qui est "out"?
79
77
 
80
78
  counter_add('omsgs', oms.size)
@@ -95,7 +93,7 @@ module Flor
95
93
  t0 = Flor.tstamp(t0)
96
94
 
97
95
  @unit.logger.log_run_end(self, t0, du)
98
- @unit.hooker.notify(self, make_end_message(t0, du))
96
+ @unit.hooker.notify(self, make_end_message(t0, du, @execution['size']))
99
97
 
100
98
  @consumed.clear
101
99
 
@@ -131,6 +129,29 @@ module Flor
131
129
  # dump notification above
132
130
  end
133
131
 
132
+ def task(message)
133
+
134
+ return error_reply(
135
+ node(message['nid']),
136
+ message,
137
+ "don't know how to apply #{message['tasker'].inspect}"
138
+ ) if message['routed'] == false
139
+ #
140
+ # use an error message similar to what the core executor would emit
141
+
142
+ @unit.ganger.task(self, message)
143
+ end
144
+ alias detask task
145
+
146
+ def return(message)
147
+
148
+ [ { 'point' => 'receive',
149
+ 'exid' => message['exid'],
150
+ 'nid' => message['nid'],
151
+ 'payload' => message['payload'],
152
+ 'tasker' => message['tasker'] } ]
153
+ end
154
+
134
155
  def schedule(message)
135
156
 
136
157
  @unit.schedule(message)
@@ -186,7 +207,7 @@ module Flor
186
207
  io.string
187
208
  end
188
209
 
189
- def make_end_message(start, duration)
210
+ def make_end_message(start, duration, execution_size)
190
211
 
191
212
  m = {}
192
213
  m['point'] = 'end'
@@ -196,7 +217,7 @@ module Flor
196
217
  m['consumed'] = @consumed.size
197
218
  m['counters'] = Flor.dup(@execution['counters'])
198
219
  m['nodes'] = @execution['nodes'].size
199
- m['size'] = @execution['size']
220
+ m['execution_size'] = execution_size
200
221
  m['archive_size'] = @unit.archive[@exid].size if @unit.archive
201
222
  m['er'] = @execution['counters']['runs'] # "emitting run"
202
223
  m['pr'] = m['er'] # "processing run"
@@ -62,7 +62,16 @@ module Flor
62
62
 
63
63
  message['vars'] = gather_vars(executor, tconf, message)
64
64
 
65
- @unit.caller.call(self, tconf, message)
65
+ m = Flor.dup(message)
66
+ #
67
+ # the tasker gets a copy of the message (and it can play with it
68
+ # to its heart content), meanwhile the message is handed to the
69
+ # "post" notifiers.
70
+
71
+ @unit.caller.call(self, tconf, m)
72
+ #
73
+ # might return a re-routing message,
74
+ # especially if it's a domain tasker
66
75
  end
67
76
 
68
77
  def return(message)
@@ -1,6 +1,8 @@
1
1
 
2
2
  module Flor
3
3
 
4
+ # Used by Flor::Loader to prepare hooks from hooks.json files.
5
+ #
4
6
  class Hook
5
7
 
6
8
  def initialize(unit, exid, h)
@@ -29,7 +31,6 @@ module Flor
29
31
  [ "hook#{object_id}", opts, self, nil ]
30
32
  end
31
33
 
32
-
33
34
  def notify(executor, message)
34
35
 
35
36
  @unit.caller.call(executor, @h, message)
@@ -22,7 +22,7 @@ module Flor
22
22
 
23
23
  def [](name)
24
24
 
25
- h = @hooks.find { |n, o, h, b| n == name }
25
+ h = @hooks.find { |n, _, _, _| n == name }
26
26
 
27
27
  h ? h[2] || h[3] : nil
28
28
  end
@@ -46,7 +46,7 @@ module Flor
46
46
  end
47
47
  end
48
48
 
49
- hook = hook.new(@unit) if hook.is_a?(Class)
49
+ hook = instantiate_hook(hook) if hook.is_a?(Class)
50
50
 
51
51
  @hooks << [ name, opts, hook, block ]
52
52
  end
@@ -73,6 +73,17 @@ module Flor
73
73
 
74
74
  protected
75
75
 
76
+ def instantiate_hook(hook_class)
77
+
78
+ a =
79
+ case i = hook_class.instance_method(:initialize).arity
80
+ when 0, 1 then [ @unit ][0, i]
81
+ else []
82
+ end
83
+
84
+ hook_class.new(*a)
85
+ end
86
+
76
87
  def o(opts, *keys)
77
88
 
78
89
  array = false
@@ -25,7 +25,7 @@ module Flor
25
25
  .collect { |pa| [ pa, expose_d(pa, {}) ] }
26
26
  .select { |pa, d| is_subdomain?(domain, d) }
27
27
  .sort_by { |pa, d| d.count('.') }
28
- .inject({}) { |vars, (pa, d)| vars.merge!(eval(pa, {})) }
28
+ .inject({}) { |vars, (pa, _)| vars.merge!(eval(pa, {})) }
29
29
  end
30
30
 
31
31
  #def procedures(path)
@@ -45,7 +45,7 @@ module Flor
45
45
  name = name[0..m[1].length - 1]
46
46
  end
47
47
 
48
- path, d, n = (Dir[File.join(@root, '**/*.{flo,flor}')])
48
+ path, _, _ = (Dir[File.join(@root, '**/*.{flo,flor}')])
49
49
  .select { |f| f.index('/lib/') }
50
50
  .collect { |pa| [ pa, *expose_dn(pa, opts) ] }
51
51
  .select { |pa, d, n| n == name && is_subdomain?(domain, d) }
@@ -62,7 +62,7 @@ module Flor
62
62
 
63
63
  domain, name = split_dn(domain, name)
64
64
 
65
- path, d, n = Dir[File.join(@root, '**/*.json')]
65
+ pat, _, nam = Dir[File.join(@root, '**/*.json')]
66
66
  .select { |pa| pa.index('/lib/taskers/') }
67
67
  .collect { |pa| [ pa, *expose_dn(pa, {}) ] }
68
68
  .select { |pa, d, n|
@@ -71,18 +71,18 @@ module Flor
71
71
  .sort_by { |pa, d, n| d.count('.') }
72
72
  .last
73
73
 
74
- return nil unless path
74
+ return nil unless pat
75
75
 
76
- conf = eval(path, message)
76
+ conf = eval(pat, message)
77
77
 
78
- return conf if n == name
78
+ return conf if nam == name
79
79
 
80
80
  conf = conf[name]
81
81
 
82
82
  return nil unless conf
83
83
 
84
84
  (conf.is_a?(Array) ? conf : [ conf ])
85
- .each { |h| h['_path'] = path }
85
+ .each { |h| h['_path'] = pat }
86
86
 
87
87
  conf
88
88
  end
@@ -68,7 +68,6 @@ module Flor
68
68
  line = "#{stp} #{@uni} #{lvl} #{txt}"
69
69
 
70
70
  if err
71
- sts = ' ' * stp.length
72
71
  dig = lvl[0, 1] + Digest::MD5.hexdigest(line)[0, 4]
73
72
  @out.puts("#{stp} #{@uni} #{lvl} #{dig} #{txt}")
74
73
  err.backtrace.each { |lin| @out.puts(" #{dig} #{@uni} #{lin}") }
@@ -117,6 +116,11 @@ module Flor
117
116
  @out.puts "#{_c.blg}sto#{_c.rs} t#{Thread.current.object_id} #{level.upcase} #{msg}"
118
117
  end
119
118
 
119
+ def size_to_s(s)
120
+
121
+ "%.2fk" % (s.to_f / 1024)
122
+ end
123
+
120
124
  def log_run_start(executor)
121
125
 
122
126
  return unless @unit.conf['log_run']
@@ -128,14 +132,11 @@ module Flor
128
132
  s << _c.dg
129
133
  s << " /--- #{_c.lg}run starts#{_c.dg} "
130
134
  s << "#{executor.class} #{executor.object_id} #{execution['exid']}"
131
- s << "\n | "
132
- s << { thread: Thread.current.object_id }.inspect
133
- s << "\n | "
134
- s << {
135
+ s << "\n | "; s << Flor.to_dnc(thread: Thread.current.object_id)
136
+ s << "\n | "; s << Flor.to_dnc(
135
137
  counters: execution['counters'],
136
138
  nodes: execution['nodes'].size,
137
- size: execution['size']
138
- }.inspect
139
+ execution_size: size_to_s(execution['size']))
139
140
  s << _c.rs
140
141
 
141
142
  @out.puts(s.string)
@@ -153,23 +154,20 @@ module Flor
153
154
 
154
155
  s << _c.dg
155
156
  s << " | run ends #{self.class} #{self.object_id} #{exid}"
156
- s << "\n | "; s << { started: tstamp, took: duration }.inspect
157
- s << "\n | "; s << {
157
+ #s << "\n | "; s << Flor.to_dnc(started: tstamp, took: duration)
158
+ s << "\n | "; s << Flor.to_dnc(started: tstamp, took: duration)
159
+ s << "\n | "; s << Flor.to_dnc(
158
160
  thread: Thread.current.object_id,
159
161
  consumed: executor.consumed.count,
160
- traps: executor.traps.count,
161
- }.inspect
162
- s << "\n | "; s << {
162
+ traps: executor.traps.count)
163
+ s << "\n | "; s << Flor.to_dnc(
163
164
  #own_traps: @traps.reject { |t| t.texid == nil }.size, # FIXME
164
165
  counters: execution['counters'],
165
166
  nodes: execution['nodes'].size,
166
- size: execution['size']
167
- }.inspect
167
+ execution_size: size_to_s(execution['size']))
168
168
  if @unit.archive
169
169
  s << "\n | "
170
- s << {
171
- archive_size: (@unit.archive[exid].size rescue '???')
172
- }.inspect
170
+ s << Flor.to_dnc(archive_size: (@unit.archive[exid].size rescue '???'))
173
171
  end
174
172
  s << "\n \\--- ."
175
173
  s << _c.rs
@@ -15,8 +15,8 @@ module Flor
15
15
  end
16
16
 
17
17
  def fetch_rows(sql); yield([]); end
18
- #DJV
19
- # add mising methods from dummy adaptor
18
+ #DJV
19
+ # add missing methods from dummy adaptor
20
20
  def typecast_value_boolean(opts={});true;end
21
21
  def test_connection();true;end
22
22
  #DJV
@@ -26,6 +26,8 @@ module Flor
26
26
 
27
27
  class FlorModel < Sequel::Model(DummySequelAdapter::DB)
28
28
 
29
+ self.require_valid_table = false
30
+
29
31
  def _data
30
32
 
31
33
  d = Flor::Storage.from_blob(content)
@@ -3,6 +3,21 @@ module Flor
3
3
 
4
4
  class Execution < FlorModel
5
5
 
6
+ #create_table :flor_executions do
7
+ #
8
+ # primary_key :id, type: :Integer
9
+ # String :domain, null: false
10
+ # String :exid, null: false
11
+ # File :content # JSON
12
+ # String :status, null: false # 'active' or something else like 'archived'
13
+ # String :ctime, null: false
14
+ # String :mtime, null: false
15
+ # String :cunit
16
+ # String :munit
17
+ #
18
+ # index :exid
19
+ #end
20
+
6
21
  def nodes; data['nodes']; end
7
22
  def zero_node; nodes['0']; end
8
23
 
@@ -43,63 +58,93 @@ module Flor
43
58
  zero_node['vars']
44
59
  end
45
60
 
46
- # class methods
61
+ def to_h
47
62
 
48
- def self.by_status(s)
63
+ h = super
49
64
 
50
- self.where(status: s)
51
- end
65
+ h[:size] = self[:content].size
52
66
 
53
- def self.terminated
67
+ m = h[:meta] = {}
68
+ cs = m[:counts] = {}
69
+ is = m[:nids] = { tasks: [], failures: [] }
54
70
 
55
- by_status('terminated')
71
+ fs = 0
72
+ ts = 0
73
+ nodes.each do |k, v|
74
+ if v['task']
75
+ ts += 1
76
+ is[:tasks] << k
77
+ end
78
+ if v['failure']
79
+ fs += 1
80
+ is[:failures] << k
81
+ end
82
+ end
83
+ cs[:nodes] = nodes.count
84
+ cs[:failures] = fs
85
+ cs[:tasks] = ts
86
+
87
+ h
56
88
  end
57
89
 
58
- def self.by_tag(name)
90
+ class << self
59
91
 
60
- _exids = self.db[:flor_pointers]
61
- .where(type: 'tag', name: name, value: nil)
62
- .select(:exid)
63
- .distinct
92
+ def by_status(s)
64
93
 
65
- self.where(status: 'active', exid: _exids)
66
- end
94
+ where(status: s)
95
+ end
96
+
97
+ def terminated
98
+
99
+ by_status('terminated')
100
+ end
67
101
 
68
- def self.by_var(name, value=:no)
102
+ def by_tag(name)
69
103
 
70
- w = { type: 'var', name: name }
104
+ _exids = db[:flor_pointers]
105
+ .where(type: 'tag', name: name, value: nil)
106
+ .select(:exid)
107
+ .distinct
71
108
 
72
- case value; when nil
73
- w[:value] = nil
74
- when :no
75
- # no w[:value] "constraining"
76
- else
77
- w[:value] = value.to_s
109
+ where(status: 'active', exid: _exids)
78
110
  end
79
111
 
80
- _exids = self.db[:flor_pointers]
81
- .where(w)
82
- .select(:exid)
83
- .distinct
112
+ def by_var(name, value=:no)
84
113
 
85
- self.where(status: 'active', exid: _exids)
86
- end
114
+ w = { type: 'var', name: name }
115
+
116
+ case value; when nil
117
+ w[:value] = nil
118
+ when :no
119
+ # no w[:value] "constraining"
120
+ else
121
+ w[:value] = value.to_s
122
+ end
87
123
 
88
- def self.by_tasker(name, taskname=:no)
124
+ _exids = db[:flor_pointers]
125
+ .where(w)
126
+ .select(:exid)
127
+ .distinct
89
128
 
90
- w = { type: 'tasker', name: name }
91
- w[:value] = taskname if taskname != :no
129
+ where(status: 'active', exid: _exids)
130
+ end
92
131
 
93
- _exids = self.db[:flor_pointers]
94
- .where(w)
95
- .select(:exid)
96
- .distinct
132
+ def by_tasker(name, taskname=:no)
97
133
 
98
- self.where(status: 'active', exid: _exids)
99
- end
134
+ w = { type: 'tasker', name: name }
135
+ w[:value] = taskname if taskname != :no
100
136
 
101
- # def self.by_task(name)
102
- # end
137
+ _exids = db[:flor_pointers]
138
+ .where(w)
139
+ .select(:exid)
140
+ .distinct
141
+
142
+ where(status: 'active', exid: _exids)
143
+ end
144
+
145
+ # def by_task(name)
146
+ # end
147
+ end
103
148
  end
104
149
  end
105
150
 
@@ -2,6 +2,22 @@
2
2
  module Flor
3
3
 
4
4
  class Message < FlorModel
5
+
6
+ #create_table :flor_messages do
7
+ #
8
+ # primary_key :id, type: :Integer
9
+ # String :domain, null: false
10
+ # String :exid, null: false
11
+ # String :point, null: false # 'execute', 'task', 'receive', ...
12
+ # File :content # JSON
13
+ # String :status, null: false
14
+ # String :ctime, null: false
15
+ # String :mtime, null: false
16
+ # String :cunit
17
+ # String :munit
18
+ #
19
+ # index :exid
20
+ #end
5
21
  end
6
22
  end
7
23