rbbt-util 5.32.16 → 5.32.21

Sign up to get free protection for your applications and to get access to all the features.
@@ -26,6 +26,7 @@ class Step
26
26
  threads = jobs.collect do |j|
27
27
  Thread.new do
28
28
  begin
29
+ j.soft_grace
29
30
  j.join unless j.done?
30
31
  rescue Exception
31
32
  Log.error "Exception waiting for job: #{Log.color :blue, j.path}"
@@ -206,45 +207,6 @@ class Step
206
207
  #@status_lock
207
208
  end
208
209
 
209
- def info(check_lock = true)
210
- return {:status => :noinfo} if info_file.nil? or not Open.exists? info_file
211
- begin
212
- Misc.insist do
213
- begin
214
- return @info_cache if @info_cache and @info_cache_time and Open.ctime(info_file) < @info_cache_time
215
- rescue Exception
216
- raise $!
217
- end
218
-
219
- begin
220
- @info_cache = Misc.insist(3, 1.6, info_file) do
221
- Misc.insist(2, 1, info_file) do
222
- Misc.insist(3, 0.2, info_file) do
223
- raise TryAgain, "Info locked" if check_lock and info_lock.locked?
224
- info_lock.lock if check_lock and false
225
- begin
226
- Open.open(info_file, :mode => 'rb') do |file|
227
- Step.load_serialized_info(file)
228
- end
229
- ensure
230
- info_lock.unlock if check_lock and false
231
- end
232
- end
233
- end
234
- end
235
- @info_cache_time = Time.now
236
- @info_cache
237
- end
238
- end
239
- rescue Exception
240
- Log.debug{"Error loading info file: " + info_file}
241
- Log.exception $!
242
- Open.rm info_file
243
- Misc.sensiblewrite(info_file, Step.serialize_info({:status => :error, :messages => ["Info file lost"]}))
244
- raise $!
245
- end
246
- end
247
-
248
210
  def init_info(force = false)
249
211
  return nil if @exec || info_file.nil? || (Open.exists?(info_file) && ! force)
250
212
  Open.lock(info_file, :lock => info_lock) do
@@ -286,274 +248,6 @@ class Step
286
248
  end
287
249
  end
288
250
 
289
- def status
290
- begin
291
- info[:status]
292
- rescue Exception
293
- Log.error "Exception reading status: #{$!.message}"
294
- :error
295
- end
296
- end
297
-
298
- def status=(status)
299
- set_info(:status, status)
300
- end
301
-
302
- def messages
303
- if messages = info[:messages]
304
- messages
305
- else
306
- set_info(:messages, []) if self.respond_to?(:set_info)
307
- end
308
- end
309
-
310
- def message(message)
311
- message = Log.uncolor(message)
312
- set_info(:messages, (messages || []) << message)
313
- end
314
-
315
- def self.status_color(status)
316
- status = status.split(">").last
317
- case status
318
- when "starting"
319
- :yellow
320
- when "error", "aborted"
321
- :red
322
- when "done"
323
- :green
324
- else
325
- :cyan
326
- end
327
- end
328
-
329
- def self.log_block(status, message, path, &block)
330
- start = Time.now
331
- status = status.to_s
332
- status_color = self.status_color status
333
-
334
- Log.info do
335
- now = Time.now
336
- str = Log.color :reset
337
- str << "#{ Log.color status_color, status}"
338
- str << ": #{ message }" if message and message != :result
339
- str << " -- #{Log.color :blue, path.to_s}" if path
340
- str << " #{Log.color :yellow, Process.pid}"
341
- str
342
- end
343
- res = yield
344
- eend = Time.now
345
- Log.info do
346
- now = Time.now
347
- str = "#{ Log.color :cyan, status.to_s } +#{Log.color :green, "%.2f" % (eend - start)}"
348
- str << ": #{ res }" if message == :result
349
- str << " -- #{Log.color :blue, path.to_s}" if path
350
- str << " #{Log.color :yellow, Process.pid}"
351
- str
352
- end
353
- res
354
- end
355
-
356
- def self.log_string(status, message, path)
357
- Log.info do
358
-
359
- status = status.to_s
360
- status_color = self.status_color status
361
-
362
- str = Log.color :reset
363
- str << "#{ Log.color status_color, status}"
364
- str << ": #{ message }" if message
365
- str << " -- #{Log.color :blue, path.to_s}" if path
366
- str << " #{Log.color :yellow, Process.pid}"
367
- str
368
- end
369
- end
370
-
371
- def self.log_progress(status, options = {}, path = nil, &block)
372
- options = Misc.add_defaults options, :severity => Log::INFO, :file => (@exec ? nil : path)
373
- max = Misc.process_options options, :max
374
- Log::ProgressBar.with_bar(max, options) do |bar|
375
- begin
376
- res = yield bar
377
- raise KeepBar.new res if IO === res
378
- res
379
- rescue
380
- Log.exception $!
381
- raise $!
382
- end
383
- end
384
- end
385
-
386
- def log_progress(status, options = {}, &block)
387
- Step.log_progress(status, options, file(:progress), &block)
388
- end
389
-
390
- def progress_bar(msg = "Progress", options = nil)
391
- if Hash === msg and options.nil?
392
- options = msg
393
- msg = nil
394
- end
395
- options = {} if options.nil?
396
-
397
- max = options[:max]
398
- Log::ProgressBar.new_bar(max, {:desc => msg, :file => (@exec ? nil : file(:progress))}.merge(options))
399
- end
400
-
401
- def self.log(status, message, path, &block)
402
- if block
403
- if Hash === message
404
- log_progress(status, message, path, &block)
405
- else
406
- log_block(status, message, path, &block)
407
- end
408
- else
409
- log_string(status, message, path)
410
- end
411
- end
412
-
413
- def log(status, message = nil, &block)
414
- self.status = status
415
- if message
416
- self.message Log.uncolor(message)
417
- end
418
- Step.log(status, message, path, &block)
419
- end
420
-
421
- def exception(ex, msg = nil)
422
- ex_class = ex.class.to_s
423
- backtrace = ex.backtrace if ex.respond_to?(:backtrace)
424
- message = ex.message if ex.respond_to?(:message)
425
- set_info :backtrace, backtrace
426
- set_info :exception, {:class => ex_class, :message => message, :backtrace => backtrace}
427
- if msg.nil?
428
- log :error, "#{ex_class} -- #{message}"
429
- else
430
- log :error, "#{msg} -- #{message}"
431
- end
432
- self._abort
433
- end
434
-
435
- def get_exception
436
- if info[:exception].nil?
437
- return Aborted if aborted?
438
- return Exception.new(messages.last) if error?
439
- Exception.new ""
440
- else
441
- ex_class, ex_message, ex_backtrace = info[:exception].values_at :class, :message, :backtrace
442
- begin
443
- klass = Kernel.const_get(ex_class)
444
- ex = klass.new ex_message
445
- ex.set_backtrace ex_backtrace unless ex_backtrace.nil? or ex_backtrace.empty?
446
- ex
447
- rescue
448
- Log.exception $!
449
- Exception.new ex_message
450
- end
451
- end
452
- end
453
-
454
- def recoverable_error?
455
- return true if aborted?
456
- return false unless error?
457
- begin
458
- return true unless info[:exception]
459
- klass = Kernel.const_get(info[:exception][:class])
460
- ! (klass <= RbbtException)
461
- rescue Exception
462
- true
463
- end
464
- end
465
-
466
- def started?
467
- Open.exists?(path) or (Open.exists?(pid_file) && Open.exists?(info_file))
468
- end
469
-
470
- def waiting?
471
- Open.exists?(info_file) and not started?
472
- end
473
-
474
- def dirty_files
475
- rec_dependencies = self.rec_dependencies(true)
476
- return [] if rec_dependencies.empty?
477
- canfail_paths = self.canfail_paths
478
-
479
- dirty_files = rec_dependencies.reject{|dep|
480
- (defined?(WorkflowRemoteClient) && WorkflowRemoteClient::RemoteStep === dep) ||
481
- ! Open.exists?(dep.info_file) ||
482
- (dep.path && (Open.exists?(dep.path) || Open.remote?(dep.path))) ||
483
- ((dep.error? || dep.aborted?) && (! dep.recoverable_error? || canfail_paths.include?(dep.path)))
484
- }
485
- end
486
-
487
- def dirty?
488
- return true if Open.exists?(pid_file) && ! ( Open.exists?(info_file) || done? )
489
- return false unless done? || status == :done
490
- return false unless ENV["RBBT_UPDATE"] == "true"
491
-
492
- status = self.status
493
-
494
- if done? and not (status == :done or status == :ending or status == :producing) and not status == :noinfo
495
- return true
496
- end
497
-
498
- if status == :done and not done?
499
- return true
500
- end
501
-
502
- if dirty_files.any?
503
- Log.low "Some dirty files found for #{self.path}: #{Misc.fingerprint dirty_files}"
504
- true
505
- else
506
- ! self.updated?
507
- end
508
- end
509
-
510
- def done?
511
- path and Open.exists? path
512
- end
513
-
514
- def streaming?
515
- (IO === @result) or (not @saved_stream.nil?) or status == :streaming
516
- end
517
-
518
- def noinfo?
519
- status == :noinfo
520
- end
521
-
522
- def running?
523
- return false if ! (started? || status == :ending)
524
- return nil unless Open.exist?(self.pid_file)
525
- pid = Open.read(self.pid_file).to_i
526
-
527
- return false if done? or error? or aborted?
528
-
529
- if Misc.pid_exists?(pid)
530
- pid
531
- else
532
- done? or error? or aborted?
533
- end
534
- end
535
-
536
- def stalled?
537
- started? && ! (done? || running? || done? || error? || aborted?)
538
- end
539
-
540
- def missing?
541
- status == :done && ! Open.exists?(path)
542
- end
543
-
544
- def error?
545
- status == :error
546
- end
547
-
548
- def nopid?
549
- ! Open.exists?(pid_file) && ! (status.nil? || status == :aborted || status == :done || status == :error || status == :cleaned)
550
- end
551
-
552
- def aborted?
553
- status = self.status
554
- status == :aborted || ((status != :ending && status != :dependencies && status != :cleaned && status != :noinfo && status != :setup && status != :noinfo) && nopid?)
555
- end
556
-
557
251
  # {{{ INFO
558
252
 
559
253
  def files_dir
@@ -650,10 +344,6 @@ class Step
650
344
  provenance
651
345
  end
652
346
 
653
- def resumable?
654
- task && task.resumable
655
- end
656
-
657
347
  def config(key, *tokens)
658
348
  options = tokens.pop if Hash === tokens.last
659
349
  options ||= {}
@@ -1,4 +1,3 @@
1
-
2
1
  class Step
3
2
 
4
3
  STREAM_CACHE = {}
@@ -127,7 +126,7 @@ class Step
127
126
  end
128
127
 
129
128
  def input_dependencies
130
- (inputs.flatten.select{|i| Step === i} + inputs.flatten.select{|dep| Path === dep && Step === dep.resource}.collect{|dep| dep.resource})
129
+ @input_dependencies ||= (recursive_inputs.flatten.select{|i| Step === i } + recursive_inputs.flatten.select{|dep| Path === dep && Step === dep.resource }.collect{|dep| dep.resource })
131
130
  end
132
131
 
133
132
  def execute_dependency(dependency, log = true)
@@ -207,7 +206,7 @@ class Step
207
206
  if dup and step.streaming? and not step.result.nil?
208
207
  if dep_step[step.path] and dep_step[step.path].length > 1
209
208
  stream = step.result
210
- other_steps = dep_step[step.path]
209
+ other_steps = dep_step[step.path].uniq.reject{|d| d.overriden }
211
210
  return unless other_steps.length > 1
212
211
  log_dependency_exec(step, "duplicating #{other_steps.length}")
213
212
  copies = Misc.tee_stream_thread_multiple(stream, other_steps.length)
@@ -369,6 +368,7 @@ class Step
369
368
  end
370
369
  next unless step.dependencies and step.dependencies.any?
371
370
  (step.dependencies + step.input_dependencies).each do |step_dep|
371
+ next unless step.dependencies.include?(step_dep)
372
372
  next if step_dep.done? or step_dep.running? or (ComputeDependency === step_dep and (step_dep.compute == :nodup or step_dep.compute == :ignore))
373
373
  dep_step[step_dep.path] ||= []
374
374
  dep_step[step_dep.path] << step
@@ -483,4 +483,76 @@ class Step
483
483
  kill_children
484
484
  end
485
485
 
486
+ def overriden?
487
+ return true if @overriden
488
+ return true if dependencies.select{|dep| dep.overriden? }.any?
489
+ info[:archived_info].each do |f,i|
490
+ return true if i[:overriden] || i["overriden"]
491
+ end if info[:archived_info]
492
+ return false
493
+ end
494
+
495
+ def overriden
496
+ @overriden
497
+ #if @overriden.nil?
498
+ # return false if dependencies.nil?
499
+ # dependencies.select{|dep| dep.overriden? }.any?
500
+ #else
501
+ # @overriden
502
+ #end
503
+ end
504
+
505
+ def overriden_deps
506
+ ord = []
507
+ deps = dependencies.dup
508
+ while dep = deps.shift
509
+ case dep.overriden
510
+ when FalseClass
511
+ next
512
+ when Symbol
513
+ ord << dep
514
+ else
515
+ deps += dep.dependencies
516
+ end
517
+ end
518
+ ord
519
+ end
520
+
521
+ def dependencies=(dependencies)
522
+ @dependencies = dependencies
523
+ set_info :dependencies, dependencies.collect{|dep| [dep.task_name, dep.name, dep.path]} if dependencies
524
+ end
525
+
526
+ #connected = true means that dependency searching ends when a result is done
527
+ #but dependencies are absent, meanining that the file could have been dropped
528
+ #in
529
+ def rec_dependencies(connected = false, seen = [])
530
+
531
+ # A step result with no info_file means that it was manually
532
+ # placed. In that case, do not consider its dependencies
533
+ return [] if ! (defined? WorkflowRemoteClient && WorkflowRemoteClient::RemoteStep === self) && ! Open.exists?(self.info_file) && Open.exists?(self.path.to_s)
534
+
535
+ return [] if dependencies.nil? or dependencies.empty?
536
+
537
+ new_dependencies = []
538
+ if self.overriden?
539
+ archived_deps = []
540
+ else
541
+ archived_deps = self.info[:archived_info] ? self.info[:archived_info].keys : []
542
+ end
543
+
544
+ dependencies.each{|step|
545
+ #next if self.done? && Open.exists?(info_file) && info[:dependencies] && info[:dependencies].select{|task,name,path| path == step.path }.empty?
546
+ next if archived_deps.include? step.path
547
+ next if seen.include? step.path
548
+ next if self.done? && connected && ! updatable?
549
+
550
+ r = step.rec_dependencies(connected, new_dependencies.collect{|d| d.path})
551
+ new_dependencies.concat r
552
+ new_dependencies << step
553
+ }
554
+
555
+ new_dependencies.uniq
556
+ end
557
+
486
558
  end
@@ -0,0 +1,294 @@
1
+ class Step
2
+ def info(check_lock = true)
3
+ return {:status => :noinfo} if info_file.nil? || ! Open.exists?(info_file)
4
+
5
+ begin
6
+ Misc.insist do
7
+
8
+ begin
9
+ return @info_cache if @info_cache and @info_cache_time and Open.ctime(info_file) < @info_cache_time
10
+ rescue Exception
11
+ raise $!
12
+ end
13
+
14
+
15
+ begin
16
+ @info_cache = Misc.insist(3, 1.6, info_file) do
17
+ Misc.insist(2, 1, info_file) do
18
+ Misc.insist(3, 0.2, info_file) do
19
+ raise TryAgain, "Info locked" if check_lock and info_lock.locked?
20
+ info_lock.lock if check_lock and false
21
+ begin
22
+ Open.open(info_file, :mode => 'rb') do |file|
23
+ Step.load_serialized_info(file)
24
+ end
25
+ ensure
26
+ info_lock.unlock if check_lock and false
27
+ end
28
+ end
29
+ end
30
+ end
31
+ @info_cache_time = Time.now
32
+ @info_cache
33
+ end
34
+ end
35
+ rescue Exception
36
+ Log.debug{"Error loading info file: " + info_file}
37
+ Log.exception $!
38
+ Open.rm info_file
39
+ Misc.sensiblewrite(info_file, Step.serialize_info({:status => :error, :messages => ["Info file lost"]}))
40
+ raise $!
41
+ end
42
+ end
43
+
44
+ def load_inputs_from_info
45
+ if info[:inputs]
46
+ info_inputs = info[:inputs]
47
+ if task && task.respond_to?(:inputs) && task.inputs
48
+ IndiferentHash.setup info_inputs
49
+ @inputs = NamedArray.setup info_inputs.values_at(*task.inputs.collect{|name| name.to_s}), task.inputs
50
+ else
51
+ @inputs = NamedArray.setup info_inputs.values, info_inputs.keys
52
+ end
53
+ else
54
+ nil
55
+ end
56
+ end
57
+
58
+ def load_dependencies_from_info
59
+ relocated = nil
60
+ @dependencies = (self.info[:dependencies] || []).collect do |task,name,dep_path|
61
+ if Open.exists?(dep_path) || Open.exists?(dep_path + '.info')
62
+ Workflow._load_step dep_path
63
+ else
64
+ next if FalseClass === relocated
65
+ new_path = Workflow.relocate(path, dep_path)
66
+ relocated = true if Open.exists?(new_path) || Open.exists?(new_path + '.info')
67
+ Workflow._load_step new_path
68
+ end
69
+ end.compact
70
+ @relocated = relocated
71
+ end
72
+
73
+
74
+ def archive_deps
75
+ self.set_info :archived_info, archived_info
76
+ self.set_info :archived_dependencies, info[:dependencies]
77
+ end
78
+
79
+ def archived_info
80
+ return info[:archived_info] if info[:archived_info]
81
+
82
+ archived_info = {}
83
+ dependencies.each do |dep|
84
+ if Symbol === dep.overriden && ! Open.exists?(dep.info_file)
85
+ archived_info[dep.path] = dep.overriden
86
+ else
87
+ archived_info[dep.path] = dep.info
88
+ end
89
+ archived_info.merge!(dep.archived_info)
90
+ end if dependencies
91
+
92
+ archived_info
93
+ end
94
+
95
+ def archived_inputs
96
+ return {} unless info[:archived_dependencies]
97
+ archived_info = self.archived_info
98
+
99
+ all_inputs = IndiferentHash.setup({})
100
+ deps = info[:archived_dependencies].collect{|p| p.last}
101
+ seen = []
102
+ while path = deps.pop
103
+ dep_info = archived_info[path]
104
+ if dep_info
105
+ dep_info[:inputs].each do |k,v|
106
+ all_inputs[k] = v unless all_inputs.include?(k)
107
+ end if dep_info[:inputs]
108
+ deps.concat(dep_info[:dependencies].collect{|p| p.last } - seen) if dep_info[:dependencies]
109
+ deps.concat(dep_info[:archived_dependencies].collect{|p| p.last } - seen) if dep_info[:archived_dependencies]
110
+ end
111
+ seen << path
112
+ end
113
+
114
+ all_inputs
115
+ end
116
+
117
+ def status
118
+ begin
119
+ info[:status]
120
+ rescue Exception
121
+ Log.error "Exception reading status: #{$!.message}"
122
+ :error
123
+ end
124
+ end
125
+
126
+ def status=(status)
127
+ set_info(:status, status)
128
+ end
129
+
130
+ def messages
131
+ if messages = info[:messages]
132
+ messages
133
+ else
134
+ set_info(:messages, []) if self.respond_to?(:set_info)
135
+ end
136
+ end
137
+
138
+ def message(message)
139
+ message = Log.uncolor(message)
140
+ set_info(:messages, (messages || []) << message)
141
+ end
142
+
143
+ def self.status_color(status)
144
+ status = status.split(">").last
145
+ case status
146
+ when "starting"
147
+ :yellow
148
+ when "error", "aborted"
149
+ :red
150
+ when "done"
151
+ :green
152
+ else
153
+ :cyan
154
+ end
155
+ end
156
+
157
+ def self.log_block(status, message, path, &block)
158
+ start = Time.now
159
+ status = status.to_s
160
+ status_color = self.status_color status
161
+
162
+ Log.info do
163
+ now = Time.now
164
+ str = Log.color :reset
165
+ str << "#{ Log.color status_color, status}"
166
+ str << ": #{ message }" if message and message != :result
167
+ str << " -- #{Log.color :blue, path.to_s}" if path
168
+ str << " #{Log.color :yellow, Process.pid}"
169
+ str
170
+ end
171
+ res = yield
172
+ eend = Time.now
173
+ Log.info do
174
+ now = Time.now
175
+ str = "#{ Log.color :cyan, status.to_s } +#{Log.color :green, "%.2f" % (eend - start)}"
176
+ str << ": #{ res }" if message == :result
177
+ str << " -- #{Log.color :blue, path.to_s}" if path
178
+ str << " #{Log.color :yellow, Process.pid}"
179
+ str
180
+ end
181
+ res
182
+ end
183
+
184
+ def self.log_string(status, message, path)
185
+ Log.info do
186
+
187
+ status = status.to_s
188
+ status_color = self.status_color status
189
+
190
+ str = Log.color :reset
191
+ str << "#{ Log.color status_color, status}"
192
+ str << ": #{ message }" if message
193
+ str << " -- #{Log.color :blue, path.to_s}" if path
194
+ str << " #{Log.color :yellow, Process.pid}"
195
+ str
196
+ end
197
+ end
198
+
199
+ def self.log_progress(status, options = {}, path = nil, &block)
200
+ options = Misc.add_defaults options, :severity => Log::INFO, :file => (@exec ? nil : path)
201
+ max = Misc.process_options options, :max
202
+ Log::ProgressBar.with_bar(max, options) do |bar|
203
+ begin
204
+ res = yield bar
205
+ raise KeepBar.new res if IO === res
206
+ res
207
+ rescue
208
+ Log.exception $!
209
+ raise $!
210
+ end
211
+ end
212
+ end
213
+
214
+ def log_progress(status, options = {}, &block)
215
+ Step.log_progress(status, options, file(:progress), &block)
216
+ end
217
+
218
+ def progress_bar(msg = "Progress", options = nil)
219
+ if Hash === msg and options.nil?
220
+ options = msg
221
+ msg = nil
222
+ end
223
+ options = {} if options.nil?
224
+
225
+ max = options[:max]
226
+ Log::ProgressBar.new_bar(max, {:desc => msg, :file => (@exec ? nil : file(:progress))}.merge(options))
227
+ end
228
+
229
+ def self.log(status, message, path, &block)
230
+ if block
231
+ if Hash === message
232
+ log_progress(status, message, path, &block)
233
+ else
234
+ log_block(status, message, path, &block)
235
+ end
236
+ else
237
+ log_string(status, message, path)
238
+ end
239
+ end
240
+
241
+ def log(status, message = nil, &block)
242
+ self.status = status
243
+ if message
244
+ self.message Log.uncolor(message)
245
+ end
246
+ Step.log(status, message, path, &block)
247
+ end
248
+
249
+ def exception(ex, msg = nil)
250
+ ex_class = ex.class.to_s
251
+ backtrace = ex.backtrace if ex.respond_to?(:backtrace)
252
+ message = ex.message if ex.respond_to?(:message)
253
+ set_info :backtrace, backtrace
254
+ set_info :exception, {:class => ex_class, :message => message, :backtrace => backtrace}
255
+ if msg.nil?
256
+ log :error, "#{ex_class} -- #{message}"
257
+ else
258
+ log :error, "#{msg} -- #{message}"
259
+ end
260
+ self._abort
261
+ end
262
+
263
+ def get_exception
264
+ if info[:exception].nil?
265
+ return Aborted if aborted?
266
+ return Exception.new(messages.last) if error?
267
+ Exception.new ""
268
+ else
269
+ ex_class, ex_message, ex_backtrace = info[:exception].values_at :class, :message, :backtrace
270
+ begin
271
+ klass = Kernel.const_get(ex_class)
272
+ ex = klass.new ex_message
273
+ ex.set_backtrace ex_backtrace unless ex_backtrace.nil? or ex_backtrace.empty?
274
+ ex
275
+ rescue
276
+ Log.exception $!
277
+ Exception.new ex_message
278
+ end
279
+ end
280
+ end
281
+
282
+ def recoverable_error?
283
+ return true if aborted?
284
+ return false unless error?
285
+ begin
286
+ return true unless info[:exception]
287
+ klass = Kernel.const_get(info[:exception][:class])
288
+ ! (klass <= RbbtException)
289
+ rescue Exception
290
+ true
291
+ end
292
+ end
293
+
294
+ end