rbbt-util 5.13.1 → 5.13.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -81,7 +81,7 @@ void post_semaphore(char* name){
81
81
  yield elem
82
82
  end
83
83
  rescue Interrupt
84
- Log.error "Process #{Process.pid} was aborted"
84
+ Log.warn "Process #{Process.pid} was aborted"
85
85
  end
86
86
  end
87
87
  end
@@ -93,10 +93,10 @@ void post_semaphore(char* name){
93
93
  #pids.each do |pid| Process.waitpid pid end
94
94
 
95
95
  rescue Exception
96
- Log.error "Killing children: #{pids.sort * ", " }"
96
+ Log.warn "Killing children: #{pids.sort * ", " }"
97
97
  pids.each do |pid| begin Process.kill("INT", pid); rescue; end; end
98
98
  pids.each do |pid| begin RbbtSemaphore.post_semaphore(file); rescue; end; end
99
- Log.error "Ensuring children are dead: #{pids.sort * ", " }"
99
+ Log.warn "Ensuring children are dead: #{pids.sort * ", " }"
100
100
  pids.each do |pid| begin Process.waitpid pid; rescue; end; end
101
101
  end
102
102
  end
@@ -46,7 +46,6 @@ class Step
46
46
  begin
47
47
  return @info_cache if @info_cache and File.mtime(info_file) < @info_cache_time
48
48
  rescue Exception
49
- Log.exception $!
50
49
  raise $!
51
50
  end
52
51
 
@@ -165,12 +164,18 @@ class Step
165
164
  options = Misc.add_defaults options, :severity => Log::INFO
166
165
  max = Misc.process_options options, :max
167
166
  Log::ProgressBar.with_bar(max, options) do |bar|
168
- yield bar
167
+ begin
168
+ res = yield bar
169
+ raise KeepBar.new res if IO === res
170
+ res
171
+ rescue
172
+ Log.exception $!
173
+ end
169
174
  end
170
175
  end
171
176
 
172
177
  def self.log(status, message, path, &block)
173
- if block_given?
178
+ if block
174
179
  if Hash === message
175
180
  log_progress(status, message, path, &block)
176
181
  else
@@ -202,7 +207,9 @@ class Step
202
207
  def running?
203
208
  return nil if not Open.exists? info_file
204
209
  return nil if info[:pid].nil?
205
- return Misc.pid_exists?(p = info[:pid]) && Process.pid != p
210
+
211
+ pid = @pid || info[:pid]
212
+ return Misc.pid_exists?(pid)
206
213
  end
207
214
 
208
215
  def error?
@@ -352,35 +359,48 @@ module Workflow
352
359
 
353
360
  def rec_dependencies(taskname)
354
361
  if task_dependencies.include? taskname
355
- deps = task_dependencies[taskname].select{|dep| String === dep or Symbol === dep}
356
- deps.concat deps.collect{|dep| rec_dependencies(dep)}.flatten
357
- deps.uniq
362
+ deps = task_dependencies[taskname].select{|dep| String === dep or Symbol === dep or Array === dep}
363
+ all_deps = deps.dup
364
+ deps.each do |dep|
365
+ if Array === dep
366
+ dep.first.rec_dependencies(dep.last).each do |d|
367
+ if Array === d
368
+ d
369
+ else
370
+ all_deps << [dep.first, d]
371
+ end
372
+ end
373
+ else
374
+ all_deps.concat rec_dependencies(dep.to_sym)
375
+ end
376
+ end
377
+ all_deps.uniq
358
378
  else
359
379
  []
360
380
  end
361
381
  end
362
382
 
363
383
  def rec_inputs(taskname)
364
- [taskname].concat(rec_dependencies(taskname)).inject([]){|acc, tn| acc.concat tasks[tn.to_sym].inputs}
384
+ [taskname].concat(rec_dependencies(taskname)).inject([]){|acc, tn| acc.concat((Array === tn ? tn.first.tasks[tn.last] : tasks[tn.to_sym]).inputs) }
365
385
  end
366
386
 
367
387
  def rec_input_defaults(taskname)
368
- [taskname].concat(rec_dependencies(taskname)).inject({}){|acc, tn| acc.merge tasks[tn.to_sym].input_defaults}.
388
+ [taskname].concat(rec_dependencies(taskname)).inject({}){|acc, tn| acc.merge((Array === tn ? tn.first.tasks[tn.last.to_sym] : tasks[tn.to_sym]).input_defaults) }.
369
389
  tap{|h| IndiferentHash.setup(h)}
370
390
  end
371
391
 
372
392
  def rec_input_types(taskname)
373
- [taskname].concat(rec_dependencies(taskname)).inject({}){|acc, tn| acc.merge tasks[tn.to_sym].input_types}.
393
+ [taskname].concat(rec_dependencies(taskname)).inject({}){|acc, tn| acc.merge((Array === tn ? tn.first.tasks[tn.last.to_sym] : tasks[tn.to_sym]).input_types) }.
374
394
  tap{|h| IndiferentHash.setup(h) }
375
395
  end
376
396
 
377
397
  def rec_input_descriptions(taskname)
378
- [taskname].concat(rec_dependencies(taskname)).inject({}){|acc, tn| acc.merge tasks[tn.to_sym].input_descriptions}.
398
+ [taskname].concat(rec_dependencies(taskname)).inject({}){|acc, tn| acc.merge((Array === tn ? tn.first.tasks[tn.last.to_sym] : tasks[tn.to_sym]).input_descriptions) }.
379
399
  tap{|h| IndiferentHash.setup(h)}
380
400
  end
381
401
 
382
402
  def rec_input_options(taskname)
383
- [taskname].concat(rec_dependencies(taskname)).inject({}){|acc, tn| acc.merge tasks[tn.to_sym].input_options}.
403
+ [taskname].concat(rec_dependencies(taskname)).inject({}){|acc, tn| acc.merge((Array === tn ? tn.first.tasks[tn.last.to_sym] : tasks[tn.to_sym]).input_options)}.
384
404
  tap{|h| IndiferentHash.setup(h)}
385
405
  end
386
406
 
@@ -388,6 +408,8 @@ module Workflow
388
408
  real_dependencies = []
389
409
  dependencies.each do |dependency|
390
410
  real_dependencies << case dependency
411
+ when Array
412
+ dependency.first.job(dependency.last, jobname, inputs)
391
413
  when Step
392
414
  dependency
393
415
  when Symbol
@@ -26,10 +26,14 @@ module Workflow
26
26
  end
27
27
 
28
28
  def dep(*dependency_list, &block)
29
- @dependency_list ||= []
30
29
  @dependencies ||= []
31
- dependency_list << block if block_given?
32
- dependencies.concat dependency_list
30
+ if Array === dependency_list and Module === dependency_list.first
31
+ @dependencies << dependency_list
32
+ else
33
+ @dependency_list ||= []
34
+ dependency_list << block if block_given?
35
+ dependencies.concat dependency_list
36
+ end
33
37
  end
34
38
 
35
39
  def task(name, &block)
@@ -47,7 +47,7 @@ class Step
47
47
  end
48
48
 
49
49
  class << self
50
- attr_accessor :log_relay_step
50
+ attr_accessor :log_relay_step
51
51
  end
52
52
 
53
53
  def relay_log(step)
@@ -164,12 +164,13 @@ class Step
164
164
  end
165
165
 
166
166
  def recursive_clean
167
+ clean
167
168
  rec_dependencies.each do |step|
168
- if File.exists?(step.info_file)
169
+ if Open.exists?(step.info_file)
169
170
  step.clean
171
+ else
170
172
  end
171
173
  end
172
- clean
173
174
  end
174
175
 
175
176
  def step(name)
@@ -1,6 +1,6 @@
1
1
  class Step
2
2
 
3
- attr_reader :stream
3
+ attr_reader :stream, :dupped
4
4
 
5
5
  STREAM_CACHE = {}
6
6
  STREAM_CACHE_MUTEX = Mutex.new
@@ -8,11 +8,28 @@ class Step
8
8
  case stream
9
9
  when IO, File
10
10
  return stream if stream.closed?
11
+
11
12
  STREAM_CACHE_MUTEX.synchronize do
12
- if STREAM_CACHE[stream].nil?
13
+ case current = STREAM_CACHE[stream]
14
+ when nil
15
+ Log.medium "Not duplicating stream #{ Misc.fingerprint(stream) }"
13
16
  STREAM_CACHE[stream] = stream
17
+ when File
18
+ if true or current.closed?
19
+ Log.medium "Reopening file #{ Misc.fingerprint(current) }"
20
+ Open.open(current.filename)
21
+ else
22
+ Log.medium "Duplicating file #{ Misc.fingerprint(current) }"
23
+ new = current.dup
24
+ new.rewind
25
+ new
26
+ end
27
+
14
28
  else
15
- Misc.dup_stream(STREAM_CACHE[stream])
29
+ Log.medium "Duplicating stream #{ Misc.fingerprint(stream) }"
30
+ new = Misc.dup_stream(current)
31
+ Log.medium str << Log.color(:green, " -> ") << "#{new.inspect}"
32
+ new
16
33
  end
17
34
  end
18
35
  when TSV::Dumper, TSV::Parser
@@ -21,9 +38,12 @@ class Step
21
38
 
22
39
  STREAM_CACHE_MUTEX.synchronize do
23
40
  if STREAM_CACHE[stream].nil?
41
+ Log.high "Not duplicating dumper #{ stream.inspect }"
24
42
  STREAM_CACHE[stream] = stream
25
43
  else
26
- Misc.dup_stream(STREAM_CACHE[stream])
44
+ new = Misc.dup_stream(STREAM_CACHE[stream])
45
+ Log.high "Duplicating dumper #{ stream.inspect } into #{new.inspect}"
46
+ new
27
47
  end
28
48
  end
29
49
  else
@@ -45,8 +65,12 @@ class Step
45
65
 
46
66
  def get_stream
47
67
  @mutex.synchronize do
48
- @stream = begin
49
- IO === @result ? @result : nil
68
+ begin
69
+ if IO === @result
70
+ @result
71
+ else
72
+ nil
73
+ end
50
74
  ensure
51
75
  @result = nil
52
76
  end
@@ -54,20 +78,24 @@ class Step
54
78
  end
55
79
 
56
80
  def dup_inputs
57
- @inputs.collect do |input|
81
+ return if @dupped or ENV["RBBT_NO_STREAM"] == 'true'
82
+ @inputs = @inputs.collect do |input|
58
83
  Step.dup_stream input
59
84
  end
85
+ @dupped = true
60
86
  end
61
87
 
62
88
  def _exec
63
89
  @exec = true if @exec.nil?
64
- @task.exec_in((bindings ? bindings : self), *dup_inputs)
90
+ @task.exec_in((bindings ? bindings : self), *@inputs)
65
91
  end
66
92
 
67
93
  def exec(no_load=false)
68
94
  dependencies.each{|dependency| dependency.exec(no_load) }
69
- @result = self._exec
70
- @result = @result.stream if TSV::Dumper === @result
95
+ @mutex.synchronize do
96
+ @result = self._exec
97
+ @result = @result.stream if TSV::Dumper === @result
98
+ end
71
99
  no_load ? @result : prepare_result(@result, @task.result_description)
72
100
  end
73
101
 
@@ -91,29 +119,50 @@ class Step
91
119
  end
92
120
 
93
121
  def run_dependencies(seen = [])
94
- seen << self.path
95
- dependencies.uniq.each{|dependency|
96
- next if seen.include? dependency.path
122
+ dependencies.uniq.each do |dependency|
123
+
124
+ next if seen.collect{|d| d.path}.include?(dependency.path)
125
+ seen << dependency
126
+ seen.concat dependency.rec_dependencies.collect{|d| d }
127
+ end
128
+
129
+ seen.each do |dependency|
130
+ next if dependency == self
131
+ dependency.relay_log self
132
+ dependency.dup_inputs
133
+ end
134
+
135
+ seen.each do |dependency|
136
+ next if dependency == self
97
137
  Log.info "#{Log.color :magenta, "Checking dependency"} #{Log.color :yellow, task.name.to_s || ""} => #{Log.color :yellow, dependency.task_name.to_s || ""} -- #{Log.color :blue, dependency.path}"
98
138
  begin
99
- dependency.relay_log self
100
- dependency.clean if not dependency.done? and (dependency.error? or dependency.aborted?)
101
- dependency.clean if dependency.streaming? and not dependency.running?
102
- dependency.run(ENV["RBBT_NO_STREAM"] != 'true') unless dependency.result or dependency.done?
103
- seen << dependency.path
104
- seen.concat dependency.rec_dependencies.collect{|d| d.path}
139
+ if dependency.streaming?
140
+ next if dependency.running?
141
+ dependency.clean
142
+ else
143
+ dependency.clean if not dependency.done? and (dependency.error? or dependency.aborted?)
144
+ end
145
+
146
+ unless dependency.result or dependency.done?
147
+ dependency.run(true)
148
+ end
149
+ rescue Aborted, Interrupt
150
+ backtrace = $!.backtrace
151
+ set_info :backtrace, backtrace
152
+ log(:error, "Aborted dependency #{Log.color :yellow, dependency.task.name.to_s}")
153
+ raise $!
105
154
  rescue Exception
106
155
  backtrace = $!.backtrace
107
156
  set_info :backtrace, backtrace
108
157
  log(:error, "Exception processing dependency #{Log.color :yellow, dependency.task.name.to_s} -- #{$!.class}: #{$!.message}")
109
158
  raise $!
110
159
  end
111
- }
160
+ end
112
161
  end
113
162
 
114
163
  def run(no_load = false)
115
-
116
164
  result = nil
165
+
117
166
  begin
118
167
  @mutex.synchronize do
119
168
  no_load = no_load ? :stream : false
@@ -131,7 +180,15 @@ class Step
131
180
  log(:preparing, "Preparing job: #{Misc.fingerprint dependencies}")
132
181
  set_info :dependencies, dependencies.collect{|dep| [dep.task_name, dep.name]}
133
182
 
134
- run_dependencies
183
+ dup_inputs
184
+ begin
185
+ run_dependencies
186
+ rescue
187
+ log(:error, "Error procesing dependencies")
188
+ stop_dependencies
189
+ raise $!
190
+ end
191
+
135
192
 
136
193
  set_info :inputs, Misc.remove_long_items(Misc.zip2hash(task.inputs, @inputs)) unless task.inputs.nil?
137
194
 
@@ -192,7 +249,6 @@ class Step
192
249
  log :streaming, "#{Log.color :magenta, "Streaming task result TSV::Dumper"} #{Log.color :yellow, task.name.to_s || ""} [#{Process.pid}]"
193
250
  ConcurrentStream.setup result.stream do
194
251
  begin
195
- set_info :done, (done_time = Time.now)
196
252
  set_info :done, (done_time = Time.now)
197
253
  set_info :time_elapsed, (time_elapsed = done_time - start_time)
198
254
  log :done, "#{Log.color :red, "Completed task"} #{Log.color :yellow, task.name.to_s || ""} [#{Process.pid}] +#{time_elapsed.to_i} -- #{path}"
@@ -284,7 +340,10 @@ class Step
284
340
 
285
341
  def stop_dependencies
286
342
  dependencies.each do |dep|
287
- dep.abort unless dep.done?
343
+ begin
344
+ dep.abort unless dep.done? or dep.error? or dep.aborted?
345
+ rescue Aborted
346
+ end
288
347
  end
289
348
  end
290
349
 
@@ -313,16 +372,23 @@ class Step
313
372
  def abort_stream
314
373
  stream = get_stream if @result
315
374
  stream ||= @stream
316
- if stream
317
- stream.abort if stream.respond_to? :abort
375
+ if stream and stream.respond_to? :abort
376
+ Log.medium "Aborting stream #{stream.inspect} -- #{Log.color :blue, path}"
377
+ begin
378
+ stream.abort
379
+ rescue Aborted
380
+ end
318
381
  end
319
382
  end
320
383
 
321
384
  def abort
385
+ Log.medium{"#{Log.color :red, "Aborting"} #{Log.color :blue, path}"}
322
386
  begin
323
387
  abort_pid
324
388
  stop_dependencies
325
389
  abort_stream
390
+ rescue
391
+ Log.exception $!
326
392
  ensure
327
393
  log(:aborted, "Job aborted")
328
394
  end
@@ -333,7 +399,7 @@ class Step
333
399
  if stream
334
400
  begin
335
401
  Misc.consume_stream stream
336
- stream.join if stream.respond_to? :join # and not stream.joined?
402
+ stream.join if stream.respond_to? :join
337
403
  rescue Exception
338
404
  stream.abort if stream.respond_to? :abort
339
405
  self.abort
@@ -342,11 +408,16 @@ class Step
342
408
  end
343
409
  end
344
410
 
411
+ def grace
412
+ until done? or result or streaming? or error? or aborted?
413
+ sleep 1
414
+ end
415
+ self
416
+ end
417
+
345
418
  def join
346
419
 
347
- until done? or result or error? or aborted? or streaming?
348
- sleep 1
349
- end
420
+ grace
350
421
 
351
422
  join_stream if status == :streaming
352
423
 
@@ -362,6 +433,9 @@ class Step
362
433
  begin
363
434
  if pid.nil? or Process.pid == pid
364
435
  dependencies.each{|dep| dep.join }
436
+ while not done?
437
+ sleep 1
438
+ end
365
439
  else
366
440
  begin
367
441
  Log.debug{"Waiting for pid: #{pid}"}
@@ -71,7 +71,7 @@ module Workflow
71
71
  task_name = task
72
72
  task = self.tasks[task_name]
73
73
  end
74
- dependencies = self.rec_dependencies(task_name).collect{|dep_name| self.tasks[dep_name.to_sym]}
74
+ dependencies = self.rec_dependencies(task_name).collect{|dep_name| Array === dep_name ? dep_name.first.tasks[dep_name.last.to_sym] : self.tasks[dep_name.to_sym]}
75
75
 
76
76
  task.doc(dependencies)
77
77
 
@@ -424,11 +424,21 @@ when Step
424
424
  out.write block
425
425
  end #unless io.closed?
426
426
  io.join if io.respond_to? :join
427
+ rescue Aborted, Interrupt
428
+ Log.error "Process interrupted. Aborting step"
429
+ res.abort
430
+ begin
431
+ io.abort if io.respond_to? :abort
432
+ io.join if io.respond_to? :join
433
+ ensure
434
+ exit -1
435
+ end
427
436
  rescue Exception
428
437
  Log.exception $!
438
+ res.abort
429
439
  begin
430
440
  io.abort if io.respond_to? :abort
431
- io.join
441
+ io.join if io.respond_to? :join
432
442
  ensure
433
443
  exit -1
434
444
  end