rbbt-util 5.14.38 → 5.14.39

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 (37) hide show
  1. checksums.yaml +4 -4
  2. data/etc/app.d/grid_system.rb +1 -0
  3. data/etc/app.d/resources.rb +3 -0
  4. data/lib/rbbt/association/database.rb +4 -2
  5. data/lib/rbbt/association/index.rb +20 -10
  6. data/lib/rbbt/association/open.rb +7 -4
  7. data/lib/rbbt/association/util.rb +12 -0
  8. data/lib/rbbt/knowledge_base/registry.rb +6 -5
  9. data/lib/rbbt/knowledge_base.rb +2 -2
  10. data/lib/rbbt/persist.rb +12 -8
  11. data/lib/rbbt/tsv/change_id.rb +10 -5
  12. data/lib/rbbt/tsv/manipulate.rb +3 -2
  13. data/lib/rbbt/tsv/matrix.rb +0 -1
  14. data/lib/rbbt/tsv/parallel/traverse.rb +2 -0
  15. data/lib/rbbt/tsv/util.rb +18 -0
  16. data/lib/rbbt/util/R/eval.rb +1 -1
  17. data/lib/rbbt/util/R/model.rb +28 -4
  18. data/lib/rbbt/util/R.rb +6 -0
  19. data/lib/rbbt/util/concurrency/processes/socket.rb +7 -1
  20. data/lib/rbbt/util/concurrency/processes/worker.rb +15 -7
  21. data/lib/rbbt/util/concurrency/processes.rb +8 -4
  22. data/lib/rbbt/util/log/progress/report.rb +3 -3
  23. data/lib/rbbt/util/log/progress.rb +20 -15
  24. data/lib/rbbt/util/misc/concurrent_stream.rb +2 -1
  25. data/lib/rbbt/util/misc/development.rb +11 -3
  26. data/lib/rbbt/util/misc/objects.rb +1 -1
  27. data/lib/rbbt/workflow/accessor.rb +19 -16
  28. data/lib/rbbt/workflow/step/run.rb +7 -0
  29. data/share/rbbt_commands/app/start +3 -2
  30. data/test/rbbt/knowledge_base/test_entity.rb +2 -1
  31. data/test/rbbt/knowledge_base/test_query.rb +2 -1
  32. data/test/rbbt/test_entity.rb +12 -13
  33. data/test/rbbt/test_knowledge_base.rb +13 -1
  34. data/test/rbbt/tsv/test_util.rb +15 -0
  35. data/test/rbbt/util/R/test_model.rb +25 -1
  36. data/test/rbbt/util/test_misc.rb +43 -40
  37. metadata +16 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d8a0ba5fcb0625780c5a1cca6a17d1c7716533d0
4
- data.tar.gz: db0e0a4843e3e8b63e7526ca1c1c6c156ee20f05
3
+ metadata.gz: fb9eba165b567301078196458cb721d1ca1f130b
4
+ data.tar.gz: e2f067c01e6a2aff41d00d76d89fbad6c895678d
5
5
  SHA512:
6
- metadata.gz: 9a4554bce956bd3ae4c4f457cc815d084622bde543504f4105b2b218bb2fb99e1ec33accae814a278b4062d92ad35b30d19e8295ffb9633484ccdb3d89f4a91b
7
- data.tar.gz: 3de5de3a7f71fdcbc40f0ca62132e1dbc49dc5924c62101361fbf0f5caf1bdcee797775a5e6d6777871a5b128e1fd74b37eef48e245f12cb8835e7cad968b656
6
+ metadata.gz: e943920dabb8863f3fc5b1b142c7c02bd1ce1131ddf4173cf42463f4d77726bca36f700b50ba67aa0d6d952c3033f96f164009a626d3a2fd050cbd0db00201b7
7
+ data.tar.gz: 77591c927621415e7030ac7f8e4d2efad8d1c7b4b977c07147d49639de2ed1b8f018a753c32453830aa6e8a5585ad079730e3e56f86896d0859b159bc7a6ed48
@@ -1,3 +1,4 @@
1
1
  #require 'zen-grids'
2
2
  require 'compass'
3
3
  require 'compass-susy'
4
+ require 'font-awesome-sass'
@@ -5,9 +5,12 @@ RbbtRESTHelpers.template_resources.unshift Rbbt.www.views.find if Rbbt.www.views
5
5
  #load Rbbt.etc['app.d']['foundation.rb'].find if Rbbt.etc['app.d']['foundation.rb'].exists?
6
6
  load Rbbt.etc['app.d']['grid_system.rb'].find if Rbbt.etc['app.d']['grid_system.rb'].exists?
7
7
 
8
+ require 'sass-css-importer'
9
+
8
10
  Compass::Frameworks::ALL.each do |importer|
9
11
  next unless importer.respond_to? :path
10
12
  path = importer.stylesheets_directory
11
13
  RbbtRESTHelpers.add_sass_load_path path
12
14
  end
15
+ RbbtRESTHelpers.add_sass_load_path './www/views/compass'
13
16
 
@@ -71,8 +71,9 @@ module Association
71
71
  info_fields = field_pos.collect{|f| f == :key ? :key : all_fields[f]}
72
72
  options = options.merge({:key_field => source_field, :fields => info_fields})
73
73
 
74
-
75
- tsv = tsv.reorder source_field, fields if true or source_field != tsv.key_field or (fields and tsv.fields != fields)
74
+ tsv.with_monitor(options[:monitor]) do
75
+ tsv = tsv.reorder source_field, fields if true or source_field != tsv.key_field or (fields and tsv.fields != fields)
76
+ end
76
77
 
77
78
  tsv.key_field = source_header
78
79
  tsv.fields = field_headers
@@ -124,6 +125,7 @@ module Association
124
125
  end
125
126
 
126
127
  open_options = options.merge(parser.options).merge(:parser => parser)
128
+ open_options = Misc.add_defaults open_options, :monitor => {:desc => "Parsing #{ Misc.fingerprint stream }"}
127
129
 
128
130
  tsv = TSV.parse parser.stream, {}, open_options
129
131
  tsv.key_field = source_header
@@ -7,12 +7,12 @@ module Association
7
7
  options = options.nil? ? {} : options.dup
8
8
  persist_options = persist_options.nil? ? Misc.pull_keys(options, :persist) : persist_options.dup
9
9
 
10
- persist_options = Misc.add_defaults persist_options.dup, :persist => true, :engine => "BDB"
10
+ persist_options = Misc.add_defaults persist_options.dup, :persist => true
11
11
  persist = persist_options[:persist]
12
12
 
13
13
  file = version_file(file, options[:namespace]) if options[:namespace] and String === file
14
-
15
- Persist.persist_tsv(file, "Association Index", options, persist_options.dup) do |data|
14
+ Persist.persist_tsv(file, "Association Index", options, persist_options.merge(:engine => "BDB")) do |data|
15
+ options = Misc.add_defaults options.dup, :monitor => "Building index for #{Misc.fingerprint file}"
16
16
  recycle = options[:recycle]
17
17
  undirected = options[:undirected]
18
18
 
@@ -117,29 +117,39 @@ module Association
117
117
 
118
118
  if File.exists?(reverse_filename)
119
119
  new = Persist.open_tokyocabinet(reverse_filename, false, serializer, TokyoCabinet::BDB)
120
+ raise "Index has no info: #{reverse_filename}" if new.key_field.nil?
121
+ Association::Index.setup new
120
122
  new
121
123
  else
122
- FileUtils.mkdir_p File.dirname(reverse_filename) unless File.exists?(File.basename(reverse_filename))
124
+ FileUtils.mkdir_p File.dirname(reverse_filename) unless File.exists?(File.dirname(reverse_filename))
125
+
123
126
  new = Persist.open_tokyocabinet(reverse_filename, true, serializer, TokyoCabinet::BDB)
124
- new.write
127
+
125
128
  self.with_unnamed do
126
- through do |key, value|
127
- new_key = key.split("~").reverse.join("~")
128
- new[new_key] = value
129
+ self.with_monitor :desc => "Reversing #{ persistence_path }" do
130
+ self.through do |key, value|
131
+ new_key = key.split("~").reverse.join("~")
132
+ new[new_key] = value
133
+ end
129
134
  end
130
135
  end
131
136
  annotate(new)
132
137
  new.key_field = key_field.split("~").values_at(1,0,2).compact * "~"
138
+ new.read_and_close do
139
+ Association::Index.setup new
140
+ end
133
141
  new.read
134
142
  end
135
143
 
136
144
  new.unnamed = true
137
145
 
138
- Association::Index.setup new
139
-
140
146
  new.undirected = undirected
141
147
 
142
148
  new
149
+ rescue Exception
150
+ Log.error "Deleting after error reversing database: #{ reverse_filename }"
151
+ FileUtils.rm reverse_filename if File.exists? reverse_filename
152
+ raise $!
143
153
  end
144
154
  end
145
155
 
@@ -11,7 +11,7 @@ module Association
11
11
  options = options.nil? ? {} : options.dup
12
12
  persist_options = persist_options.nil? ? Misc.pull_keys(options, :persist) : persist_options.dup
13
13
 
14
- options = Misc.add_defaults options, :zipped => true
14
+ options = Misc.add_defaults options, :zipped => true, :monitor => {:desc => "Opening database #{Misc.fingerprint file}"}
15
15
  persist_options = Misc.add_defaults persist_options, :persist => true, :dir => Rbbt.var.associations
16
16
  persist = persist_options[:persist]
17
17
 
@@ -19,15 +19,18 @@ module Association
19
19
  file = file.call if Proc === file
20
20
 
21
21
  data = Persist.persist_tsv(file, "Association Database", options, persist_options) do |data|
22
+ options = options.dup
22
23
  tsv = Association.database(file, options.merge(:persist => persist))
23
24
  tsv = tsv.to_double unless tsv.type == :double
24
25
 
25
26
  tsv.annotate data
26
27
 
27
28
  data.serializer = :double if data.respond_to? :serializer
28
- tsv.with_monitor(options[:monitor]) do
29
- tsv.through do |k,v|
30
- data[k] = v
29
+ tsv.with_unnamed do
30
+ tsv.with_monitor(options[:monitor]) do
31
+ tsv.through do |k,v|
32
+ data[k] = v
33
+ end
31
34
  end
32
35
  end
33
36
 
@@ -55,6 +55,18 @@ module Association
55
55
  source_specs[2] = source_format if source_format
56
56
  target_specs[2] = target_format if target_format
57
57
 
58
+ if source_specs.first and not all_fields.include? source_specs.first and defined? Entity and (_format = Entity.formats[source_specs.first.to_s])
59
+ _source = all_fields.select{|f| Entity.formats[f.to_s] == _format }.first
60
+ raise "Source not found #{source_specs}. Options: #{Misc.fingerprint all_fields}" if _target.nil?
61
+ source_specs[0] = _source
62
+ end
63
+
64
+ if target_specs.first and not all_fields.include? target_specs.first and defined? Entity and (_format = Entity.formats[target_specs.first.to_s])
65
+ _target = all_fields.select{|f| Entity.formats[f.to_s].to_s == _format.to_s }.first
66
+ raise "Target not found #{target_specs}. Options: #{Misc.fingerprint all_fields}" if _target.nil?
67
+ target_specs[0] = _target
68
+ end
69
+
58
70
  if source_specs[0].nil? and target_specs[0].nil?
59
71
  source_specs[0] = key_field
60
72
  target_specs[0] = fields[0]
@@ -44,7 +44,7 @@ class KnowledgeBase
44
44
  Persist.memory("Index:" << [key, dir] * "@") do
45
45
  options = options.dup
46
46
  persist_dir = dir
47
- persist_file = persist_dir[key]
47
+ persist_file = persist_dir[key].find
48
48
  file, registered_options = registry[name]
49
49
 
50
50
  options = Misc.add_defaults options, registered_options if registered_options and registered_options.any?
@@ -79,15 +79,16 @@ class KnowledgeBase
79
79
 
80
80
  def get_database(name, options = {})
81
81
  name = name.to_s
82
- key = "Index:" + name.to_s + "_" + Misc.digest(Misc.fingerprint([name,options.dup]))
83
- @indices[key] ||=
82
+ @databases[[name, options]] ||=
84
83
  begin
84
+ fp = Misc.fingerprint([name,options])
85
+ key = name.to_s + "_" + Misc.digest(fp) + '.database'
85
86
  Persist.memory("Database:" << [key, dir] * "@") do
86
87
  options = options.dup
87
- persist_file = dir.indices[key]
88
+ persist_dir = dir
89
+ persist_file = persist_dir[key].find
88
90
  file, registered_options = registry[name]
89
91
 
90
-
91
92
  options = Misc.add_defaults options, registered_options if registered_options and registered_options.any?
92
93
  options = Misc.add_defaults options, :persist_file => persist_file, :namespace => namespace, :format => format, :persist => true
93
94
 
@@ -7,9 +7,9 @@ require 'rbbt/knowledge_base/syndicate'
7
7
 
8
8
  class KnowledgeBase
9
9
 
10
- attr_accessor :namespace, :dir, :indices, :registry, :format, :databases, :entity_options
10
+ attr_accessor :namespace, :dir, :databases, :indices, :registry, :format, :entity_options
11
11
  def initialize(dir, namespace = nil)
12
- @dir = Path.setup(dir.dup).find
12
+ @dir = Path.setup(dir.dup)
13
13
 
14
14
  @namespace = namespace
15
15
  @format = IndiferentHash.setup({})
data/lib/rbbt/persist.rb CHANGED
@@ -253,16 +253,20 @@ module Persist
253
253
  end
254
254
 
255
255
  def self.persist_file(path, type, persist_options, &block)
256
- begin
257
- if is_persisted?(path, persist_options)
258
- Log.low "Persist up-to-date: #{ path } - #{Misc.fingerprint persist_options}"
259
- return path if persist_options[:no_load]
260
- return load_file(path, type)
261
- else
256
+ Misc.insist do
257
+ begin
258
+ if is_persisted?(path, persist_options)
259
+ Log.low "Persist up-to-date: #{ path } - #{Misc.fingerprint persist_options}"
260
+ return path if persist_options[:no_load]
261
+ return load_file(path, type)
262
+ else
263
+ Open.rm path if Open.exists? path
264
+ end
265
+ rescue Exception
266
+ Log.warn "Exception loading persistence (#{ type }) #{ path }: #{$!.message}. Erase and retry."
262
267
  Open.rm path if Open.exists? path
268
+ raise $!
263
269
  end
264
- rescue Exception
265
- Open.rm path if Open.exists? path
266
270
  end
267
271
 
268
272
  lock_filename = Persist.persistence_path(path + '.persist', {:dir => Persist.lock_dir})
@@ -98,11 +98,16 @@ module TSV
98
98
  return file.index(options.merge(:target => target, :fields => fields, :order => true))
99
99
  end
100
100
  else
101
- all_fields = TSV.parse_header(file).all_fields
102
- target = all_fields[1] if target.nil?
103
- if (source.nil? or all_fields.include? source) and all_fields.include? target
104
- index = TSV.index(file, options.merge(:target => target, :fields => fields, :order => true))
105
- return index
101
+ next unless file.exists?
102
+ begin
103
+ all_fields = TSV.parse_header(file).all_fields
104
+ target = all_fields[1] if target.nil?
105
+ if (source.nil? or all_fields.include? source) and all_fields.include? target
106
+ index = TSV.index(file, options.merge(:target => target, :fields => fields, :order => true))
107
+ return index
108
+ end
109
+ rescue Exception
110
+ Log.error "Exception reading identifier file: #{file.find}"
106
111
  end
107
112
  end
108
113
  end
@@ -636,14 +636,15 @@ module TSV
636
636
  @monitor = {:desc => "Adding field #{ names * ", " }"} if TrueClass === monitor
637
637
 
638
638
  through do |key, values|
639
+ values ||= fields ? [nil] * fields : []
639
640
  new_values = yield(key, values)
640
641
 
641
642
  case type
642
643
  when :double
643
644
  new_values = new_values.collect{|v| [v] } if Array === new_values and new_values.first and not Array === new_values.first
644
- values += new_values
645
+ values += new_values || [nil] * names.length
645
646
  when :list
646
- values += new_values
647
+ values += new_values || [nil] * names.length
647
648
  end
648
649
 
649
650
  self[key] = values
@@ -3,7 +3,6 @@ require 'rbbt/association'
3
3
  module TSV
4
4
  def self.read_matrix(tsv, field_format = "ID", value_format = "Value", *others)
5
5
  tsv = TSV.open(tsv) unless TSV === tsv
6
-
7
6
 
8
7
  if others.any?
9
8
  other_tsv = tsv.slice(others)
@@ -335,7 +335,9 @@ module TSV
335
335
  def self.traverse_cpus(num, obj, options, &block)
336
336
  begin
337
337
  callback, cleanup, join, respawn = Misc.process_options options, :callback, :cleanup, :join, :respawn
338
+ respawn = true if ENV["RBBT_RESPAWN"] and ENV["RBBT_RESPAWN"] == "true"
338
339
 
340
+ Log.low "Traversing in #{ num } cpus: #{respawn ? "respawn" : "no respawn"}"
339
341
  q = RbbtProcessQueue.new num, cleanup, join, respawn
340
342
  q.callback &callback
341
343
  q.init &block
data/lib/rbbt/tsv/util.rb CHANGED
@@ -186,6 +186,24 @@ module TSV
186
186
  self
187
187
  end
188
188
 
189
+ def unzip_replicates
190
+ raise "Can only unzip replicates in :double TSVs" unless type == :double
191
+
192
+ new = {}
193
+ self.with_unnamed do
194
+ through do |k,vs|
195
+ Misc.zip_fields(vs).each_with_index do |v,i|
196
+ new[k + "(#{i})"] = v
197
+ end
198
+ end
199
+ end
200
+
201
+ self.annotate(new)
202
+ new.type = :list
203
+
204
+ new
205
+ end
206
+
189
207
  def to_list
190
208
  new = {}
191
209
  case type
@@ -31,9 +31,9 @@ module R
31
31
  end
32
32
 
33
33
  def self.clear
34
- Log.warn "Clearing Rserver session #{SESSION}, PID #{@@instance_process}"
35
34
  @@instance = nil
36
35
  if defined? @@instance_process and @@instance_process and Misc.pid_exists? @@instance_process
36
+ Log.warn "Clearing Rserver session #{SESSION}, PID #{@@instance_process}"
37
37
  begin
38
38
  Process.kill :INT, @@instance_process
39
39
  rescue Exception
@@ -19,13 +19,18 @@ module R
19
19
  R_METHOD = :eval
20
20
 
21
21
  attr_accessor :name, :formula
22
- def initialize(name, formula, options = {})
22
+ def initialize(name, formula, data = nil, options = {})
23
23
  @name = name
24
24
  @formula = formula
25
25
  @options = options || {}
26
+ if data and not model_file.exists?
27
+ method = Misc.process_options options, :fit
28
+ fit(data, method || "lm", options)
29
+ end
26
30
  end
27
31
 
28
32
  def colClasses(tsv)
33
+ return nil unless TSV === tsv
29
34
  "c('character', " <<
30
35
  (tsv.fields.collect{|f| R.ruby2R(@options[f] ? @options[f].to_s : ":NA") } * ", ") <<
31
36
  ")"
@@ -63,12 +68,31 @@ data = NULL
63
68
  end
64
69
 
65
70
  def predict(tsv, field = "Prediction")
66
- tsv = Model.groom tsv, formula
67
- tsv.R <<-EOF, r_options(tsv)
71
+ case tsv
72
+ when TSV
73
+ tsv = Model.groom tsv, formula
74
+ tsv.R <<-EOF, r_options(tsv)
68
75
  model = rbbt.model.load('#{model_file}');
69
76
  data.groomed = rbbt.model.groom(data,formula=#{formula})
70
77
  data$#{field} = predict(model, data.groomed);
71
- EOF
78
+ EOF
79
+ when Hash
80
+ res = R.eval_a <<-EOF
81
+ model = rbbt.model.load('#{model_file}');
82
+ predict(model, data.frame(#{R.ruby2R tsv}));
83
+ EOF
84
+ Array === tsv.values.first ? res : res.first
85
+ when Fixnum, Array, Float, String
86
+ field = formula.split("~").last.strip
87
+
88
+ res = R.eval_a <<-EOF
89
+ model = rbbt.model.load('#{model_file}');
90
+ predict(model, data.frame(#{field} = #{R.ruby2R tsv}));
91
+ EOF
92
+ Array === tsv ? res : res.first
93
+ else
94
+ raise "Unknown object for predict: #{Misc.fingerprint tsv}"
95
+ end
72
96
  end
73
97
 
74
98
  def exists?
data/lib/rbbt/util/R.rb CHANGED
@@ -86,8 +86,12 @@ source('#{UTIL}');
86
86
 
87
87
  def self.ruby2R(object)
88
88
  case object
89
+ when Float::INFINITY
90
+ "Inf"
89
91
  when nil
90
92
  "NULL"
93
+ when "NA"
94
+ "NA"
91
95
  when TSV
92
96
  "matrix(#{R.ruby2R object.values},dimnames=list(#{R.ruby2R object.keys}, #{R.ruby2R object.fields}))"
93
97
  when Symbol
@@ -102,6 +106,8 @@ source('#{UTIL}');
102
106
  "FALSE"
103
107
  when Array
104
108
  "c(#{object.collect{|e| ruby2R(e) } * ", "})"
109
+ when Hash
110
+ object.collect{|k,v| [k, ruby2R(v)] * "="} * ", "
105
111
  else
106
112
  raise "Type of object not known: #{ object.inspect }"
107
113
  end
@@ -55,7 +55,12 @@ class RbbtProcessQueue
55
55
  payload = Misc.read_stream stream, size
56
56
  case type
57
57
  when "S"
58
- @serializer.load(payload)
58
+ begin
59
+ @serializer.load(payload)
60
+ rescue Exception
61
+ Log.exception $!
62
+ raise $!
63
+ end
59
64
  when "C"
60
65
  payload
61
66
  end
@@ -84,6 +89,7 @@ class RbbtProcessQueue
84
89
 
85
90
  def push(obj)
86
91
  RbbtSemaphore.synchronize(@write_sem) do
92
+ obj = Annotated.purge(obj)
87
93
  self.dump(obj, @swrite)
88
94
  end
89
95
  end
@@ -30,7 +30,7 @@ class RbbtProcessQueue
30
30
  Kernel.exit! 28
31
31
  rescue ClosedStream
32
32
  rescue Aborted, Interrupt
33
- Log.warn "Worker #{Process.pid} aborted"
33
+ Log.info "Worker #{Process.pid} aborted"
34
34
  rescue Exception
35
35
  Log.exception $!
36
36
  @callback_queue.push($!) if @callback_queue
@@ -56,17 +56,24 @@ class RbbtProcessQueue
56
56
  @current = Process.fork do
57
57
  run
58
58
  end
59
- Log.warn "Worker #{Process.pid} started with #{@current}"
59
+ @asked = false
60
+
61
+ initial = Misc.memory_use(Process.pid)
62
+ memory_cap = multiplier * initial
63
+ Log.medium "Worker #{Process.pid} started with #{@current} -- initial: #{initial} - multiplier: #{multiplier} - cap: #{memory_cap}"
60
64
 
61
65
  @monitor_thread = Thread.new do
62
66
  begin
63
67
  while true
64
68
  current = Misc.memory_use(@current)
65
- initial = Misc.memory_use(Process.pid)
66
- if current > multiplier * initial
67
- Process.kill "USR1", @current
69
+ if current > memory_cap and not @asked
70
+ Log.medium "Worker #{@current} for #{Process.pid} asked to respawn -- initial: #{initial} - multiplier: #{multiplier} - cap: #{memory_cap} - current: #{current}"
71
+ RbbtSemaphore.synchronize(@callback_queue.write_sem) do
72
+ Process.kill "USR1", @current
73
+ end
74
+ @asked = true
68
75
  end
69
- sleep 1
76
+ sleep 3 + rand(5)
70
77
  end
71
78
  rescue
72
79
  Log.exception $!
@@ -80,7 +87,8 @@ class RbbtProcessQueue
80
87
  @current = Process.fork do
81
88
  run
82
89
  end
83
- Log.warn "Worker #{Process.pid} respawning to #{@current}"
90
+ @asked = false
91
+ Log.high "Worker #{Process.pid} respawning to #{@current}"
84
92
  end
85
93
  rescue Aborted, Interrupt
86
94
  Log.warn "Worker #{Process.pid} aborted"
@@ -24,8 +24,13 @@ class RbbtProcessQueue
24
24
  begin
25
25
  loop do
26
26
  p = @callback_queue.pop
27
- raise p if Exception === p
28
- raise p.first if Array === p and Exception === p.first
27
+
28
+ if Exception === p or (Array === p and Exception === p.first)
29
+ e = Array === p ? p.first : p
30
+ Log.warn "Callback recieved exception from worker: #{e.message}" unless Aborted === e or ClosedStream === e
31
+ raise e
32
+ end
33
+
29
34
  @callback.call p
30
35
  end
31
36
  rescue Aborted
@@ -34,8 +39,7 @@ class RbbtProcessQueue
34
39
  raise $!
35
40
  rescue ClosedStream
36
41
  rescue Exception
37
- Log.warn "Callback thread exception: #{$!.message}"
38
- Log.exception $!
42
+ Log.warn "Exception captured in callback: #{$!.message}"
39
43
  @process_monitor.raise $!
40
44
  raise $!
41
45
  ensure
@@ -64,7 +64,7 @@ module Log
64
64
  indicator << " #{Log.color(:blue, percent.to_s << "%")}"
65
65
 
66
66
  used = time - @start
67
- if @mean_max and @mean_max > 0
67
+ if @mean_max and @mean_max > 0 and @mean > 0
68
68
  eta = (@max - @ticks) / @mean
69
69
  else
70
70
  eta = (@max - @ticks) / (@ticks/used)
@@ -73,7 +73,7 @@ module Log
73
73
  used = Misc.format_seconds(used)
74
74
  eta = [eta/3600, eta/60 % 60, eta % 60].map{|t| "%02i" % t }.join(':')
75
75
 
76
- indicator << " #{Log.color :yellow, used} used #{Log.color :yellow, eta} left"
76
+ indicator << " #{Log.color :yellow, used} used #{Log.color :yellow, eta} left - #{Log.color :yellow, ticks.to_s} of #{Log.color :yellow, @max.to_s}"
77
77
 
78
78
  indicator
79
79
  end
@@ -83,7 +83,7 @@ module Log
83
83
  return str << " " << Log.color(:yellow, "waiting") if @ticks == 0
84
84
  str << " " << thr_msg
85
85
  if max
86
- str << Log.color(:blue, " -- ") << eta_msg
86
+ str << Log.color(:blue, " -- ") << eta_msg
87
87
  else
88
88
  str << Log.color(:blue, " -- ") << ticks.to_s
89
89
  end
@@ -27,24 +27,29 @@ module Log
27
27
  return if ENV["RBBT_NO_PROGRESS"] == "true"
28
28
  @ticks += 1
29
29
 
30
- time = Time.now
31
- if @last_time.nil?
32
- @last_time = time
33
- @last_count = @ticks
34
- @start = time
35
- return
36
- end
30
+ begin
31
+ time = Time.now
32
+ if @last_time.nil?
33
+ @last_time = time
34
+ @last_count = @ticks
35
+ @start = time
36
+ return
37
+ end
37
38
 
38
- diff = time - @last_time
39
- report and return if diff > @frequency
40
- return unless max
39
+ diff = time - @last_time
40
+ report and return if diff > @frequency
41
+ return unless max
41
42
 
42
- percent = self.percent
43
- if @last_percent.nil?
44
- @last_percent = percent
45
- return
43
+ percent = self.percent
44
+ if @last_percent.nil?
45
+ @last_percent = percent
46
+ return
47
+ end
48
+ report and return if percent > @last_percent and diff > 0.3
49
+ rescue Exception
50
+ Log.warn "Exception during report: " << $!.message
51
+ Log.exception $!
46
52
  end
47
- report and return if percent > @last_percent and diff > 0.3
48
53
  end
49
54
  end
50
55
  end
@@ -77,13 +77,14 @@ module ConcurrentStream
77
77
  end
78
78
 
79
79
  def join
80
- @joined = true
81
80
 
82
81
  join_threads
83
82
  join_pids
84
83
 
85
84
  join_callback
86
85
 
86
+ @joined = true
87
+
87
88
  lockfile.unlock if lockfile and lockfile.locked?
88
89
  close unless closed?
89
90
  end
@@ -6,7 +6,9 @@ module Misc
6
6
  end
7
7
 
8
8
  def self.pre_fork
9
- Persist::CONNECTIONS.values.each do |db| db.close if db.write? end
9
+ Persist::CONNECTIONS.values.each do |db|
10
+ db.close if db.write?
11
+ end
10
12
  ObjectSpace.each_object(Mutex) do |m|
11
13
  begin
12
14
  m.unlock
@@ -276,7 +278,8 @@ module Misc
276
278
  end
277
279
  end
278
280
 
279
- def self.bootstrap(elems, num = :current, file = nil, options = {}, &block)
281
+ def self.bootstrap(elems, num = :current, options = {}, &block)
282
+ IndiferentHash.setup options
280
283
  num = :current if num.nil?
281
284
  cpus = case num
282
285
  when :current
@@ -289,10 +292,14 @@ module Misc
289
292
  else
290
293
  32000 / num
291
294
  end
295
+ else
296
+ raise "Parameter 'num' not understood: #{Misc.fingerprint num}"
292
297
  end
293
298
 
294
299
 
295
- options = Misc.add_defaults options, :cpus => cpus, :bar => "Bootstrap in #{ cpus } cpus: #{ Misc.fingerprint Annotated.purge(elems) }", :into => Set.new
300
+ options = Misc.add_defaults options, :respawn => true, :cpus => cpus, :into => Set.new
301
+ options = Misc.add_defaults options, :bar => "Bootstrap in #{ options[:cpus] } cpus: #{ Misc.fingerprint Annotated.purge(elems) }"
302
+ respawn = options[:respawn] and options[:cpus] and options[:cpus].to_i > 1
296
303
 
297
304
  index = (0..elems.length-1).to_a.collect{|v| v.to_s }
298
305
  TSV.traverse index, options do |pos|
@@ -303,6 +310,7 @@ module Misc
303
310
  rescue Interrupt
304
311
  Log.warn "Process #{Process.pid} was aborted"
305
312
  end
313
+ raise RbbtProcessQueue::RbbtProcessQueueWorker::Respawn if respawn == :always and cpus > 1
306
314
  nil
307
315
  end
308
316
  end