miga-base 0.7.16.12 → 0.7.18.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1e89d0bc90eef4ca458fbc415cbeff6eaa6c2b07ee4df77268826ecfbe0720df
4
- data.tar.gz: b082d83022262e82d309e8ff70f077fe28cebddacf5b85844547ed24a8a877f7
3
+ metadata.gz: 78b020bda6120b5a284100b9544d7a488d385630f21b5d6d5e2bb9b365c832fb
4
+ data.tar.gz: d8332711fdf86308726700654ee8db91bb097f022a26e1240e62d107efa833a1
5
5
  SHA512:
6
- metadata.gz: fa0746c6173b1b7a504b6d40ed0a158ef647694970f9222aeeaa5465dcad73f4647894164d0edc823b54dce837410393ac61186a6b217ff5edacbfc81a01591d
7
- data.tar.gz: b8411e7c9fb0f62de20e5a909dbf7b4c998bcb18aa4fa79fbe48dc128292f8983ce1dfae54d9e3082807449b6c5cf9d4a3bb913bc9dde77c1c2d4bab6aa8fe27
6
+ metadata.gz: 8b766a40acf37193204e6369e07f2ecba1a67aa6141133654ab69f89b2ba9a63a959bd3f5b7fd21c56542eea7e3174cc342b05dc76b73ed27c6a2b273c546ca9
7
+ data.tar.gz: 6f8d791b9bf443a1eb43198625ebce48501ebaa3680be0c4cef55931b176fd2365407865e6e43cd549217ada6c67e5c86b156bd0816b80f91c388af812af810c
@@ -1,5 +1,5 @@
1
1
  require 'miga/cli/action'
2
- require 'sqlite3'
2
+ require 'miga/sqlite'
3
3
 
4
4
  class MiGA::Cli::Action::Doctor < MiGA::Cli::Action
5
5
  end
@@ -10,9 +10,7 @@ module MiGA::Cli::Action::Doctor::Base
10
10
  # tables saving +metric+ (:ani or :aai) and call +blk+ if the
11
11
  # file is corrupt or doesn't contain the expected structure
12
12
  def check_sqlite3_database(db_file, metric, &blk)
13
- SQLite3::Database.new(db_file) do |conn|
14
- conn.execute("select count(*) from #{metric}").first
15
- end
13
+ MiGA::SQLite.new(db_file).run("select count(*) from #{metric}")
16
14
  rescue SQLite3::SQLException, SQLite3::CorruptException
17
15
  blk.call
18
16
  end
@@ -107,11 +105,7 @@ module MiGA::Cli::Action::Doctor::Base
107
105
  dist = dataset.result(:distances) or return
108
106
  path = dist.file_path(:aai_db) or return
109
107
 
110
- o = []
111
- SQLite3::Database.new(path) do |conn|
112
- o = conn.execute('select seq2 from aai').map(&:first)
113
- end
114
- o
108
+ MiGA::SQLite.new(path).run('select seq2 from aai').map(&:first)
115
109
  end
116
110
 
117
111
  ##
@@ -120,34 +114,20 @@ module MiGA::Cli::Action::Doctor::Base
120
114
  def save_bidirectional(a, b)
121
115
  each_database_file(a) do |db_file, metric, result|
122
116
  data = nil
123
- SQLite3::Database.new(db_file) do |conn|
124
- data =
125
- conn.execute(
126
- "select seq1, seq2, #{metric}, sd, n, omega " +
127
- "from #{metric} where seq2 = ? limit 1", b.name
128
- ).first
129
- end
117
+ data = MiGA::SQLite.new(db_file).run(
118
+ "select seq1, seq2, #{metric}, sd, n, omega " +
119
+ "from #{metric} where seq2 = ? limit 1", b.name
120
+ ).first
130
121
  next if data.nil? || data.empty?
131
122
 
132
123
  db_file_b = File.join(File.dirname(db_file), "#{b.name}.db")
133
124
  next unless File.exist?(db_file_b)
134
125
 
135
126
  data[0], data[1] = data[1], data[0]
136
- SQLite3::Database.new(db_file_b) do |conn|
137
- attempts = 0
138
- begin
139
- attempts += 1
140
- conn.execute(
141
- "insert into #{metric} (seq1, seq2, #{metric}, sd, n, omega) " +
142
- "values(?, ?, ?, ?, ?, ?)", data
143
- )
144
- rescue SQLite3::BusyException => e
145
- raise "Cannot populate #{db_file_b}: #{e.message}" if attempts > 3
146
-
147
- sleep(1)
148
- retry
149
- end
150
- end
127
+ MiGA::SQLite.new(db_file_b).run(
128
+ "insert into #{metric} (seq1, seq2, #{metric}, sd, n, omega) " +
129
+ "values(?, ?, ?, ?, ?, ?)", data
130
+ )
151
131
  end
152
132
  end
153
133
  end
@@ -73,7 +73,7 @@ class MiGA::Daemon < MiGA::MiGA
73
73
  say 'MiGA:%s launched' % project.name
74
74
  say '-----------------------------------'
75
75
  miga_say "Saving log to: #{output_file}" unless show_log?
76
- recalculate_status!
76
+ queue_maintenance
77
77
  load_status
78
78
  say 'Configuration options:'
79
79
  say @runopts.to_s
@@ -92,7 +92,7 @@ class MiGA::Daemon < MiGA::MiGA
92
92
  flush!
93
93
  if (loop_i % 12).zero?
94
94
  purge!
95
- recalculate_status!
95
+ queue_maintenance
96
96
  end
97
97
  save_status
98
98
  sleep(latency)
@@ -100,11 +100,13 @@ class MiGA::Daemon < MiGA::MiGA
100
100
  true
101
101
  end
102
102
 
103
- def recalculate_status!
104
- say 'Recalculating status for all complete datasets'
105
- project.each_dataset do |ds|
106
- ds.recalculate_status if ds.status == :complete
107
- end
103
+ ##
104
+ # Queue maintenance tasks as an analysis job
105
+ def queue_maintenance
106
+ return if bypass_maintenance?
107
+
108
+ say 'Queueing maintenance tasks'
109
+ queue_job(:maintenance)
108
110
  end
109
111
 
110
112
  ##
@@ -272,6 +274,11 @@ class MiGA::Daemon < MiGA::MiGA
272
274
  # Avoid single datasets hogging resources
273
275
  @jobs_to_run.rotate! rand(jobs_to_run.size)
274
276
 
277
+ # Prioritize project-wide jobs
278
+ project_jobs = @jobs_to_run.select { |i| i[:ds].nil? }
279
+ @jobs_to_run.delete_if { |i| i[:ds].nil? }
280
+ @jobs_to_run.prepend(*project_jobs)
281
+
275
282
  # Launch as many +jobs_to_run+ as possible
276
283
  while (hostk = next_host)
277
284
  break if jobs_to_run.empty?
@@ -17,7 +17,7 @@ module MiGA::Daemon::Base
17
17
  if !force && v == 0 && k != :verbosity
18
18
  raise "Daemon's #{k} cannot be set to zero"
19
19
  end
20
- when :shutdown_when_done, :show_log
20
+ when :shutdown_when_done, :show_log, :bypass_maintenance
21
21
  v = !!v
22
22
  when :nodelist
23
23
  if v =~ /^\$/
@@ -63,6 +63,12 @@ module MiGA::Daemon::Base
63
63
  !!runopts(:shutdown_when_done)
64
64
  end
65
65
 
66
+ ##
67
+ # Should the daemon ignore regular maintenance steps?
68
+ def bypass_maintenance?
69
+ !!runopts(:bypass_maintenance)
70
+ end
71
+
66
72
  ##
67
73
  # Returns the level of verbosity for the daemon as an Integer, or 1 if unset.
68
74
  # Verbosity levels are:
@@ -7,7 +7,7 @@ require 'miga/metadata'
7
7
  require 'miga/dataset/result'
8
8
  require 'miga/dataset/status'
9
9
  require 'miga/dataset/hooks'
10
- require 'sqlite3'
10
+ require 'miga/sqlite'
11
11
 
12
12
  ##
13
13
  # Dataset representation in MiGA
@@ -190,8 +190,7 @@ class MiGA::Dataset < MiGA::MiGA
190
190
  r = result(ref_project ? :taxonomy : :distances)
191
191
  return nil if r.nil?
192
192
 
193
- db = SQLite3::Database.new(r.file_path(:aai_db))
194
- db.execute(
193
+ MiGA::SQLite.new(r.file_path(:aai_db)).run(
195
194
  'SELECT seq2, aai FROM aai WHERE seq2 != ? ' \
196
195
  'GROUP BY seq2 ORDER BY aai DESC LIMIT ?', [name, how_many]
197
196
  )
@@ -1,4 +1,4 @@
1
- require 'sqlite3'
1
+ require 'miga/sqlite'
2
2
  require 'miga/result'
3
3
  require 'miga/dataset/base'
4
4
  require 'miga/common/with_result'
@@ -151,13 +151,13 @@ module MiGA::Dataset::Result
151
151
  db = r.file_path(db_type)
152
152
  next if db.nil? || !File.size?(db)
153
153
 
154
- sqlite_db = SQLite3::Database.new db
154
+ sqlite_db = MiGA::SQLite.new(db)
155
155
  table = db_type[-6..-4]
156
- val = sqlite_db.execute "select seq2 from #{table}"
156
+ val = sqlite_db.run("select seq2 from #{table}")
157
157
  next if val.empty?
158
158
 
159
159
  (val.map(&:first) - ref).each do |extra|
160
- sqlite_db.execute "delete from #{table} where seq2=?", extra
160
+ sqlite_db.run("delete from #{table} where seq2=?", extra)
161
161
  end
162
162
  end
163
163
  end
@@ -0,0 +1,49 @@
1
+ # @package MiGA
2
+ # @license Artistic-2.0
3
+
4
+ require 'sqlite3'
5
+
6
+ ##
7
+ # SQLite3 wrapper for MiGA.
8
+ class MiGA::SQLite < MiGA::MiGA
9
+ class << self
10
+ ##
11
+ # Default parsing options. Supported +opts+ keys:
12
+ # - +:busy_attempts+: Number of times to retry when database is busy
13
+ # (default: 3)
14
+ def default_opts(opts = {})
15
+ opts[:busy_attempts] ||= 3
16
+ opts
17
+ end
18
+ end
19
+
20
+ ##
21
+ # Options hash
22
+ attr :opts
23
+
24
+ ##
25
+ # Database absolute path
26
+ attr :path
27
+
28
+ ##
29
+ # Create MiGA::SQLite with database in +path+ (without opening a connection)
30
+ # and options +opts+ (see +.default_opts+)
31
+ def initialize(path, opts = {})
32
+ @opts = MiGA::SQLite.default_opts(opts)
33
+ @path = File.absolute_path(path)
34
+ end
35
+
36
+ ##
37
+ # Executes +cmd+ and returns the result
38
+ def run(*cmd)
39
+ busy_attempts ||= 0
40
+ conn = SQLite3::Database.new(path)
41
+ conn.execute(*cmd)
42
+ rescue SQLite3::BusyException => e
43
+ busy_attempts += 1
44
+ raise "Database busy #{path}: #{e.message}" if busy_attempts >= 3
45
+
46
+ sleep(1)
47
+ retry
48
+ end
49
+ end
@@ -8,7 +8,7 @@ module MiGA
8
8
  # - Float representing the major.minor version.
9
9
  # - Integer representing gem releases of the current version.
10
10
  # - Integer representing minor changes that require new version number.
11
- VERSION = [0.7, 16, 12]
11
+ VERSION = [0.7, 18, 0]
12
12
 
13
13
  ##
14
14
  # Nickname for the current major.minor version.
@@ -16,7 +16,7 @@ module MiGA
16
16
 
17
17
  ##
18
18
  # Date of the current gem release.
19
- VERSION_DATE = Date.new(2020, 12, 24)
19
+ VERSION_DATE = Date.new(2020, 12, 27)
20
20
 
21
21
  ##
22
22
  # Reference of MiGA.
@@ -0,0 +1,9 @@
1
+ #!/bin/bash
2
+ # Available variables: $PROJECT, $RUNTYPE, $MIGA, $CORES
3
+ set -e
4
+ SCRIPT="maintenance"
5
+ # shellcheck source=scripts/miga.bash
6
+ . "$MIGA/scripts/miga.bash" || exit 1
7
+
8
+ miga doctor --only status -P "$PROJECT" -t "$CORES" -v
9
+
@@ -12,12 +12,15 @@ cd "$DIR"
12
12
  miga date > "miga-project.start"
13
13
 
14
14
  # Execute doctor
15
+ echo "# Doctor"
15
16
  miga doctor -P "$PROJECT" -t "$CORES" -v
16
17
 
17
18
  # Index taxonomy
19
+ echo "# Index taxonomy"
18
20
  miga tax_index -P "$PROJECT" -i "miga-project.taxonomy.json" --ref --active
19
21
 
20
22
  # Index metadata
23
+ echo "# Index metadata"
21
24
  ruby -I "$MIGA/lib" \
22
25
  "$MIGA/utils/index_metadata.rb" "$PROJECT" "miga-project.metadata.db"
23
26
 
@@ -93,7 +93,7 @@ class DaemonTest < Test::Unit::TestCase
93
93
  0 => /-{20}\n/,
94
94
  1 => /MiGA:#{p.name} launched/,
95
95
  2 => /-{20}\n/,
96
- 6 => /Probing running jobs\n/
96
+ 8 => /Probing running jobs\n/
97
97
  }.each { |k, v| assert_match(v, l[k], "unexpected line: #{k}") }
98
98
  ensure
99
99
  begin
@@ -160,8 +160,9 @@ class DaemonTest < Test::Unit::TestCase
160
160
  assert_equal(0, d1.jobs_running.size)
161
161
  assert_equal(0, d1.jobs_to_run.size)
162
162
  capture_stderr { d1.in_loop }
163
+ # 3 dataset jobs + 1 maintenance job:
163
164
  assert_equal(1, d1.jobs_running.size)
164
- assert_equal(2, d1.jobs_to_run.size)
165
+ assert_equal(3, d1.jobs_to_run.size)
165
166
  end
166
167
 
167
168
  def test_maxjobs_runopts
@@ -172,7 +173,7 @@ class DaemonTest < Test::Unit::TestCase
172
173
  assert_equal(0, d1.jobs_to_run.size)
173
174
  capture_stderr { d1.in_loop }
174
175
  assert_equal(2, d1.jobs_running.size)
175
- assert_equal(1, d1.jobs_to_run.size)
176
+ assert_equal(2, d1.jobs_to_run.size)
176
177
  end
177
178
 
178
179
  def test_load_status
@@ -232,6 +233,7 @@ class DaemonTest < Test::Unit::TestCase
232
233
  end
233
234
 
234
235
  def test_shutdown_when_done
236
+ daemon.runopts(:bypass_maintenance, true)
235
237
  daemon.runopts(:shutdown_when_done, true)
236
238
  out = capture_stderr { assert { !daemon.in_loop } }.string
237
239
  assert_match(/Nothing else to do/, out)
@@ -317,4 +319,20 @@ class DaemonTest < Test::Unit::TestCase
317
319
  out = capture_stderr { d1.in_loop }.string
318
320
  assert_match(/Daemon loop start/, out)
319
321
  end
322
+
323
+ def test_bypass_maintenance
324
+ # Default (run maintenance)
325
+ d = daemon(0)
326
+ d.runopts(:latency, 0, true)
327
+ capture_stderr { d.in_loop }
328
+ assert_equal(1, d.jobs_running.size)
329
+ assert_equal(:maintenance, d.jobs_running.first[:job])
330
+
331
+ # Bypassing maintenance
332
+ d = daemon(1)
333
+ d.runopts(:latency, 0, true)
334
+ d.runopts(:bypass_maintenance, true)
335
+ capture_stderr { d.in_loop }
336
+ assert_equal([], d.jobs_running)
337
+ end
320
338
  end
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: 0.7.16.12
4
+ version: 0.7.18.0
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: 2020-12-24 00:00:00.000000000 Z
11
+ date: 2020-12-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: daemons
@@ -196,6 +196,7 @@ files:
196
196
  - lib/miga/result/dates.rb
197
197
  - lib/miga/result/source.rb
198
198
  - lib/miga/result/stats.rb
199
+ - lib/miga/sqlite.rb
199
200
  - lib/miga/tax_dist.rb
200
201
  - lib/miga/tax_index.rb
201
202
  - lib/miga/taxonomy.rb
@@ -211,6 +212,7 @@ files:
211
212
  - scripts/essential_genes.bash
212
213
  - scripts/haai_distances.bash
213
214
  - scripts/init.bash
215
+ - scripts/maintenance.bash
214
216
  - scripts/miga.bash
215
217
  - scripts/mytaxa.bash
216
218
  - scripts/mytaxa_scan.bash