miga-base 1.3.20.10 → 1.3.20.11

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 89f86ec82f63d08729e4f970919dba5762a2888c797cdf6a8a7f32805929508c
4
- data.tar.gz: cb3e930ba1a4acb776bd7bcc7481470363109c2c01a67e1780f1d71dc29659c0
3
+ metadata.gz: 91302d7d75ccc35b6ff9606f8b6d777f1ed9d003884b1239ccf88d1a60e9cd23
4
+ data.tar.gz: d71e38b02f3e54695a4e2c40b07b910ebaf8719511f20fb5c19198aa9b4dbae2
5
5
  SHA512:
6
- metadata.gz: aa6434515aaca67b727e2a725cd2013e3096eb638cfc590e452c4e33c0e72f4c788b14cc0e8254cb91f14082330c038fa826ecab2cca01ccc2d4f96272ce0bac
7
- data.tar.gz: f5aec44b327725934d7585e157a68a653c9567743c46120e90d5280638935194684829acaa0003ff14ed239ee07ead6a604e25d423743986f627cb379767614c
6
+ metadata.gz: e0df7e189c74f4c791493d04f14000671c40a2fe5d9a50c92985a82eb0b7fe9670205a8d5b01ab7fb158df9836fb5d41040c1cf3ac81321dd66dde84d01adbe3
7
+ data.tar.gz: 0f30aac316c440e623405eab59855a3ace6d5bc04e452bfe67d67c1cb486670a48a629e0fd9f631cdd66446907147043d80d03e273423a620074d5a320bd3975
@@ -37,11 +37,12 @@ module MiGA::Cli::Action::Doctor::Base
37
37
  return if fix.empty?
38
38
 
39
39
  cli.say("- Fixing #{fix.size} datasets")
40
- MiGA::Parallel.distribute(fix, cli[:threads]) do |d_n, idx, thr|
40
+ o = MiGA::Parallel.distribute(fix, cli[:threads]) do |d_n, idx, thr|
41
41
  cli.advance(' > Fixing', idx + 1, fix.size, false) if thr == 0
42
42
  p.dataset(d_n).cleanup_distances!
43
43
  end
44
44
  cli.say
45
+ MiGA::Parallel.assess_success(o)
45
46
  end
46
47
 
47
48
  ##
@@ -103,7 +103,7 @@ module MiGA::Cli::Action::Doctor::Distances
103
103
  # Read data (threaded)
104
104
  FileUtils.mkdir_p(tmp)
105
105
  chunks_e = 0 .. chunks - 1
106
- MiGA::Parallel.distribute(chunks_e, cli[:threads]) do |chunk, k, thr|
106
+ o = MiGA::Parallel.distribute(chunks_e, cli[:threads]) do |chunk, k, thr|
107
107
  cli.advance('Reading:', k, chunks, false) if thr == 0
108
108
  dist = {}
109
109
  [:aai, :ani].each do |metric|
@@ -121,6 +121,7 @@ module MiGA::Cli::Action::Doctor::Distances
121
121
  end
122
122
  cli.advance('Reading:', chunks, chunks, false)
123
123
  cli.say
124
+ MiGA::Parallel.assess_success(o)
124
125
 
125
126
  # Save information to indicate that the run is complete and return
126
127
  File.open(tmp_chunks, 'w') { |fh| fh.puts(chunks, n) }
@@ -135,12 +136,12 @@ module MiGA::Cli::Action::Doctor::Distances
135
136
  tmp_done = File.join(tmp, 'chunks.txt')
136
137
  chunks = File.readlines(tmp_done)[0].chomp.to_i
137
138
 
138
- lower_triangle = []
139
+ lower_tr = []
139
140
  chunks.times.each do |i|
140
- (0 .. i).to_a.each { |j| lower_triangle << [i, j] }
141
+ (0 .. i).to_a.each { |j| lower_tr << [i, j] }
141
142
  end
142
- MiGA::Parallel.distribute(lower_triangle, cli[:threads]) do |cell, k, thr|
143
- cli.advance('Writing:', k, lower_triangle.size, false) if thr == 0
143
+ o = MiGA::Parallel.distribute(lower_tr, cli[:threads]) do |cell, k, thr|
144
+ cli.advance('Writing:', k, lower_tr.size, false) if thr == 0
144
145
  done_f = File.join(tmp, "#{cell[0]}-#{cell[1]}.txt")
145
146
  next if File.exist?(done_f)
146
147
 
@@ -148,9 +149,11 @@ module MiGA::Cli::Action::Doctor::Distances
148
149
  File.open("#{done_f}.tmp", 'w') { |fh| fixed_ds.each { |ds| fh.puts ds } }
149
150
  File.rename("#{done_f}.tmp", done_f)
150
151
  end
151
- cli.advance('Writing:', lower_triangle.size, lower_triangle.size, false)
152
+ cli.advance('Writing:', lower_tr.size, lower_tr.size, false)
152
153
  cli.say
153
- lower_triangle.map do |cell|
154
+ MiGA::Parallel.assess_success(o)
155
+
156
+ lower_tr.map do |cell|
154
157
  Set.new.tap do |y|
155
158
  file = File.join(tmp, "#{cell[0]}-#{cell[1]}.txt")
156
159
  raise MiGA::Error.new(
data/lib/miga/common.rb CHANGED
@@ -106,13 +106,13 @@ class MiGA::MiGA
106
106
  ''
107
107
  else
108
108
  left_time = @_advance_time[:avg] * (total - n) / 60 # <- in minutes
109
- left_time < 0.01 ? ' ' :
110
- left_time < 1 ? ('%.0fs left' % (left_time * 60)) :
109
+ left_time < 0.01 ? '' :
110
+ left_time < 1 ? ('%.0fs left' % (left_time * 60)) :
111
111
  left_time > 1440 ? ('%.1fd left' % (left_time / 1440)) :
112
- left_time > 60 ? ('%.1fh left' % (left_time / 60)) :
112
+ left_time > 60 ? ('%.1fh left' % (left_time / 60)) :
113
113
  ('%.1fm left' % left_time)
114
114
  end
115
- $stderr.print("[%s] %s %s %s \r" % [Time.now, step, adv, left])
115
+ $stderr.print("[%s] %s %s %-12s \r" % [Time.now, step, adv, left])
116
116
  end
117
117
 
118
118
  ##
data/lib/miga/parallel.rb CHANGED
@@ -8,10 +8,9 @@ class MiGA::Parallel < MiGA::MiGA
8
8
  # Executes the passed block with the thread number as argument (0-numbered)
9
9
  # in +threads+ processes
10
10
  def process(threads)
11
- threads.times do |i|
12
- Process.fork { yield(i) }
13
- end
14
- Process.waitall
11
+ threads.times
12
+ .map { |i| Process.fork { yield(i) } }
13
+ .map { |pid| Process.waitpid2(pid) }
15
14
  end
16
15
 
17
16
  ##
@@ -21,7 +20,6 @@ class MiGA::Parallel < MiGA::MiGA
21
20
  # 3. Index of the acting thread
22
21
  def distribute(enum, threads, &blk)
23
22
  process(threads) { |thr| thread_enum(enum, threads, thr, &blk) }
24
- Process.waitall # <- Just to double-check, but `process` should suffice
25
23
  end
26
24
 
27
25
  ##
@@ -33,5 +31,23 @@ class MiGA::Parallel < MiGA::MiGA
33
31
  yield(obj, idx, thr) if idx % threads == thr
34
32
  end
35
33
  end
34
+
35
+ ##
36
+ # Assesses the success of all thread exit codes and raises an error if
37
+ # any of the children status in +status+ failed. It can be used as:
38
+ #
39
+ # status = MiGA::Parallel.process(3) { |i| 1/i }
40
+ # MiGA::Parallel.assess_success(status)
41
+ #
42
+ # Or in conjunction with +MiGA::Parallel.distribute+
43
+ def assess_success(status)
44
+ failed = status.map { |i| i[1].success? ? 0 : 1 }.inject(:+)
45
+ return if failed.zero?
46
+
47
+ raise MiGA::Error.new(
48
+ "Child threads failed: #{failed}/#{status.size}. " \
49
+ "Maximum exit status: #{status.map { |i| i[1].exitstatus || 0 }.max}"
50
+ )
51
+ end
36
52
  end
37
53
  end
data/lib/miga/version.rb CHANGED
@@ -12,7 +12,7 @@ module MiGA
12
12
  # - String indicating release status:
13
13
  # - rc* release candidate, not released as gem
14
14
  # - [0-9]+ stable release, released as gem
15
- VERSION = [1.3, 20, 10].freeze
15
+ VERSION = [1.3, 20, 11].freeze
16
16
 
17
17
  ##
18
18
  # Nickname for the current major.minor version.
@@ -20,7 +20,7 @@ module MiGA
20
20
 
21
21
  ##
22
22
  # Date of the current gem relese.
23
- VERSION_DATE = Date.new(2024, 9, 12)
23
+ VERSION_DATE = Date.new(2024, 9, 13)
24
24
 
25
25
  ##
26
26
  # References of MiGA
@@ -19,6 +19,18 @@ class ParallelTest < Test::Unit::TestCase
19
19
  assert_equal([0, 0, 1, 1], t.sort)
20
20
  end
21
21
 
22
+ def test_assess_success
23
+ declare_forks
24
+
25
+ o = MiGA::Parallel.process(1) { |i| i / 2 }
26
+ assert(o.all? { |i| i[1].success? })
27
+ assert_nil(MiGA::Parallel.assess_success(o))
28
+
29
+ o = MiGA::Parallel.process(1) { |i| $stderr = StringIO.new ; 1 / i }
30
+ assert_equal(1, o.map { |i| i[1].success? ? 0 : 1 }.inject(:+))
31
+ assert_raise { MiGA::Parallel.assess_success(o) }
32
+ end
33
+
22
34
  def test_thread_enum
23
35
  MiGA::Parallel.thread_enum(%w[a b c d], 3, 1) do |o, _k, _t|
24
36
  assert_equal('b', o)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: miga-base
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.20.10
4
+ version: 1.3.20.11
5
5
  platform: ruby
6
6
  authors:
7
7
  - Luis M. Rodriguez-R
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-09-12 00:00:00.000000000 Z
11
+ date: 2024-09-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: daemons