zold 0.16.4 → 0.16.5

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: 6878147c3eac159d72548009bed74eda692af6b465f82ae47c2fd071de818512
4
- data.tar.gz: 42401944fc5709a6fb6ea30de6f4af5ebc789538ca87ed204c0386792fbd3011
3
+ metadata.gz: c73944cf9e705895a711529a97a3ab56cd4561724c1b2009416db8355ae9a0e9
4
+ data.tar.gz: ece33aa66164e63afebc6f2383d4ad18997fa616abf0311b0956d62ec38f10f6
5
5
  SHA512:
6
- metadata.gz: 97e5df269652087a17d29b3b603cc6b26992e189ce7005cb944ede9559884fdd8d0c1c60bb0463dd5a4dc267f1d6f57c9ad867864b98b679b8fce3431da4a6df
7
- data.tar.gz: 52ac1e64157997658b5b4be0230960ca61099b4aabdbab7ba43faefd69d4b948a5a4b4a4e0d123c8a0e92915a362aeb63ee333a37a98e4f559f8916231aafacb
6
+ metadata.gz: 911f89497f640f092f3f7f2acfc192cb7154be4be191f5a75e4101045bd71432cb7235f31595a1c0290de9ce5848cc60e23e803b447f4a2c1e4e02cd449ae012
7
+ data.tar.gz: f98b5bb83459de3cd8c1576e9736a3f873a5a44255e66a0417307804dccb15702f72a9323b6defb43816e121c1388421d25106376cbff54e8fad563ef6dd06ed
data/lib/zold/cache.rb ADDED
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright (c) 2018 Yegor Bugayenko
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the 'Software'), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in all
13
+ # copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ # SOFTWARE.
22
+
23
+ # Cache.
24
+ # Author:: Yegor Bugayenko (yegor256@gmail.com)
25
+ # Copyright:: Copyright (c) 2018 Yegor Bugayenko
26
+ # License:: MIT
27
+ module Zold
28
+ # Cache
29
+ class Cache
30
+ def initialize
31
+ @hash = {}
32
+ @mutex = Mutex.new
33
+ end
34
+
35
+ def get(key, lifetime: 60 * 60)
36
+ @mutex.synchronize do
37
+ rec = @hash[key]
38
+ rec = nil if !rec.nil? && rec[:start] < Time.now - rec[:lifetime]
39
+ if rec.nil?
40
+ @hash[key] = {
41
+ value: yield,
42
+ start: Time.now,
43
+ lifetime: lifetime
44
+ }
45
+ end
46
+ @hash[key][:value]
47
+ end
48
+ end
49
+ end
50
+ end
@@ -23,6 +23,7 @@
23
23
  require 'open3'
24
24
  require 'slop'
25
25
  require 'backtrace'
26
+ require 'concurrent'
26
27
  require_relative '../version'
27
28
  require_relative '../age'
28
29
  require_relative '../score'
@@ -78,8 +79,8 @@ module Zold
78
79
  "The strength of the score (default: #{Score::STRENGTH})",
79
80
  default: Score::STRENGTH
80
81
  o.integer '--threads',
81
- 'How many threads to use for scores finding (default: 2)',
82
- default: 2
82
+ "How many threads to use for scores finding (default: #{Concurrent.processor_count})",
83
+ default: Concurrent.processor_count
83
84
  o.bool '--dump-errors',
84
85
  'Make HTTP front-end errors visible in the log (false by default)',
85
86
  default: false
@@ -324,8 +325,12 @@ module Zold
324
325
  @log.info('Metronome hasn\'t been started because of --no-metronome')
325
326
  return metronome
326
327
  end
327
- require_relative 'routines/spread'
328
- metronome.add(Routines::Spread.new(opts, @wallets, @remotes, log: @log))
328
+ # This was a good idea to spread wallets among other nodes,
329
+ # but with the growing number of wallets it's obvious that this
330
+ # doesn't make a lot of sense. We better focus of HungryWallets
331
+ # implementation, where wallets are being pulled if they are missed.
332
+ # require_relative 'routines/spread'
333
+ # metronome.add(Routines::Spread.new(opts, @wallets, @remotes, log: @log))
329
334
  unless opts['standalone']
330
335
  require_relative 'routines/reconnect'
331
336
  metronome.add(Routines::Reconnect.new(opts, @remotes, farm, network: opts['network'], log: @log))
@@ -74,7 +74,7 @@ module Zold
74
74
  loop do
75
75
  VerboseThread.new(@log).run(true) { take }
76
76
  break if @pool.shuttingdown?
77
- sleep Random.rand(100) / 100
77
+ sleep(1 + Random.rand(100) / 100)
78
78
  end
79
79
  end
80
80
  end
@@ -119,6 +119,7 @@ in #{Age.new(start, limit: 0.05)}")
119
119
  opts = queue
120
120
  return if opts.empty?
121
121
  id = opts[0]
122
+ Thread.current.thread_variable_set(:wallet, id.to_s)
122
123
  body = Futex.new(file(id), log: @log).open do |f|
123
124
  b = File.exist?(f) ? IO.read(f) : ''
124
125
  FileUtils.rm_f(f)
@@ -24,6 +24,7 @@ require 'time'
24
24
  require 'open3'
25
25
  require 'backtrace'
26
26
  require 'futex'
27
+ require 'json'
27
28
  require_relative '../log'
28
29
  require_relative '../score'
29
30
  require_relative '../age'
@@ -59,16 +60,24 @@ module Zold
59
60
  end
60
61
 
61
62
  def to_text
62
- @threads.map do |t|
63
- trace = t.backtrace || []
64
- "#{t.name}: status=#{t.status}; alive=#{t.alive?};\n #{trace.join("\n ")}"
65
- end.join("\n")
63
+ [
64
+ "Current time: #{Time.now.utc.iso8601}",
65
+ JSON.pretty_generate(to_json),
66
+ @threads.map do |t|
67
+ trace = t.backtrace || []
68
+ [
69
+ "#{t.name}: status=#{t.status}; alive=#{t.alive?}",
70
+ 'Vars: ' + t.thread_variables.map { |v| "#{v}=\"#{t.thread_variable_get(v)}\"" }.join('; '),
71
+ " #{trace.join("\n ")}"
72
+ ].join("\n")
73
+ end
74
+ ].flatten.join("\n\n")
66
75
  end
67
76
 
68
77
  def to_json
69
78
  {
70
79
  threads: @threads.map do |t|
71
- "#{t.name}/#{t.status}/#{t.alive? ? 'A' : 'D'}"
80
+ "#{t.name}/#{t.status}/#{t.alive? ? 'alive' : 'dead'}"
72
81
  end.join(', '),
73
82
  cleanup: @cleanup.status,
74
83
  pipeline: @pipeline.size,
@@ -177,6 +186,7 @@ module Zold
177
186
  return unless s.port == port
178
187
  return unless s.strength >= strength
179
188
  Thread.current.name = s.to_mnemo
189
+ Thread.current.thread_variable_set(:start, Time.now.utc.iso8601)
180
190
  score = @farmer.up(s)
181
191
  @log.debug("New score discovered: #{score}")
182
192
  save(threads, [score])
@@ -51,6 +51,7 @@ module Zold
51
51
  bin = File.expand_path(File.join(File.dirname(__FILE__), '../../../bin/zold'))
52
52
  raise "Zold binary not found at #{bin}" unless File.exist?(bin)
53
53
  Open3.popen2e("ruby #{bin} --skip-upgrades --low-priority next \"#{score}\"") do |stdin, stdout, thr|
54
+ Thread.current.thread_variable_set(:pid, thr.pid.to_s)
54
55
  @log.debug("Scoring started in proc ##{thr.pid} \
55
56
  for #{score.value}/#{score.strength} at #{score.host}:#{score.port}")
56
57
  begin
@@ -73,6 +74,7 @@ for #{score.value}/#{score.strength} at #{score.host}:#{score.port}")
73
74
  break
74
75
  end
75
76
  sleep 0.25
77
+ Thread.current.thread_variable_set(:buffer, buffer.length.to_s)
76
78
  end
77
79
  after = Score.parse(buffer.strip)
78
80
  @log.debug("Next score #{after.value}/#{after.strength} found in proc ##{thr.pid} \
@@ -26,8 +26,6 @@ require 'eventmachine'
26
26
  require 'thin'
27
27
  require 'json'
28
28
  require 'sinatra/base'
29
- require 'cachy'
30
- require 'moneta'
31
29
  require 'get_process_mem'
32
30
  require 'diffy'
33
31
  require 'usagewatch_ext'
@@ -41,6 +39,7 @@ require_relative '../copies'
41
39
  require_relative '../log'
42
40
  require_relative '../id'
43
41
  require_relative '../http'
42
+ require_relative '../cache'
44
43
 
45
44
  # The web front of the node.
46
45
  # Author:: Yegor Bugayenko (yegor256@gmail.com)
@@ -51,7 +50,6 @@ module Zold
51
50
  class Front < Sinatra::Base
52
51
  configure do
53
52
  Thread.current.name = 'sinatra'
54
- Cachy.cache_store = Moneta.new(:Memory)
55
53
  set :bind, '0.0.0.0'
56
54
  set :suppress_messages, true
57
55
  set :start, Time.now
@@ -79,10 +77,12 @@ module Zold
79
77
  set :remotes, nil? # to be injected at node.rb
80
78
  set :copies, nil? # to be injected at node.rb
81
79
  set :node_alias, nil? # to be injected at node.rb
80
+ set :cache, Cache.new
82
81
  end
83
82
  use Rack::Deflater
84
83
 
85
84
  before do
85
+ Thread.current.thread_variable_set(:uri, request.url)
86
86
  @start = Time.now
87
87
  if !settings.halt.empty? && params[:halt] && params[:halt] == settings.halt
88
88
  settings.log.error('Halt signal received, shutting the front end down...')
@@ -189,10 +189,10 @@ in #{Age.new(@start, limit: 1)}")
189
189
  protocol: settings.protocol,
190
190
  score: score.to_h,
191
191
  pid: Process.pid,
192
- cpus: Cachy.cache(:a_cpus) { Concurrent.processor_count },
192
+ cpus: settings.cache.get(:cpus) { Concurrent.processor_count },
193
193
  memory: GetProcessMem.new.bytes.to_i,
194
194
  platform: RUBY_PLATFORM,
195
- load: Cachy.cache(:a_load, expires_in: 5 * 60) { Usagewatch.uw_load.to_f },
195
+ load: settings.cache.get(:load, lifetime: 5 * 60) { Usagewatch.uw_load.to_f },
196
196
  threads: "#{Thread.list.select { |t| t.status == 'run' }.count}/#{Thread.list.count}",
197
197
  wallets: total_wallets,
198
198
  remotes: settings.remotes.all.count,
@@ -390,6 +390,7 @@ in #{Age.new(@start, limit: 1)}")
390
390
  Thread.list.map do |t|
391
391
  [
392
392
  "#{t.name}: status=#{t.status}; alive=#{t.alive?}",
393
+ 'Vars: ' + t.thread_variables.map { |v| "#{v}=\"#{t.thread_variable_get(v)}\"" }.join('; '),
393
394
  t.backtrace.nil? ? 'NO BACKTRACE' : " #{t.backtrace.join("\n ")}"
394
395
  ].join("\n")
395
396
  end
@@ -427,14 +428,20 @@ in #{Age.new(@start, limit: 1)}")
427
428
  yield header
428
429
  end
429
430
 
431
+ # @todo #513:30min This method is temporarily disabled since it
432
+ # takes a lot of time (when the amount of wallets is big, like 40K). However,
433
+ # we must find a way to count them somehow faster.
430
434
  def total_wallets
431
- Cachy.cache(:a_wallets, expires_in: 5 * 60) { settings.wallets.all.count }
435
+ return 256 if settings.network == Wallet::MAIN_NETWORK
436
+ settings.wallets.all.count
432
437
  end
433
438
 
434
439
  def score
435
- best = Cachy.cache(:a_score, expires_in: 60) { settings.farm.best }
436
- raise 'Score is empty, there is something wrong with the Farm!' if best.empty?
437
- best[0]
440
+ settings.cache.get(:score, lifetime: settings.network == Wallet::MAIN_NETWORK ? 60 : 1) do
441
+ b = settings.farm.best
442
+ raise 'Score is empty, there is something wrong with the Farm!' if b.empty?
443
+ b[0]
444
+ end
438
445
  end
439
446
 
440
447
  def copy_of(id)
@@ -69,6 +69,7 @@ module Zold
69
69
  if @remotes.all.empty?
70
70
  @log.info("There are no remotes, won\'t spread #{id}")
71
71
  else
72
+ Thread.current.thread_variable_set(:wallet, id.to_s)
72
73
  Push.new(wallets: @wallets, remotes: @remotes, log: @log).run(
73
74
  ['push', "--ignore-node=#{@address}", id.to_s] +
74
75
  (@ignore_score_weakeness ? ['--ignore-score-weakness'] : [])
data/lib/zold/version.rb CHANGED
@@ -25,6 +25,6 @@
25
25
  # Copyright:: Copyright (c) 2018 Yegor Bugayenko
26
26
  # License:: MIT
27
27
  module Zold
28
- VERSION = '0.16.4'
28
+ VERSION = '0.16.5'
29
29
  PROTOCOL = 2
30
30
  end
@@ -109,6 +109,19 @@ class FrontTest < Minitest::Test
109
109
  end
110
110
  end
111
111
 
112
+ def test_increments_score
113
+ FakeNode.new(log: test_log).run(['--threads=1', '--strength=1', '--no-metronome']) do |port|
114
+ 3.times do |i|
115
+ assert_equal_wait(true) do
116
+ response = Zold::Http.new(uri: "http://localhost:#{port}/", score: nil).get
117
+ assert_equal('200', response.code, response.body)
118
+ score = Zold::Score.parse_json(Zold::JsonPage.new(response.body).to_hash['score'])
119
+ score.value >= i
120
+ end
121
+ end
122
+ end
123
+ end
124
+
112
125
  def test_renders_wallet_pages
113
126
  FakeHome.new(log: test_log).run do |home|
114
127
  FakeNode.new(log: test_log).run(['--ignore-score-weakness', '--standalone']) do |port|
data/test/test__helper.rb CHANGED
@@ -24,7 +24,6 @@ gem 'openssl'
24
24
  require 'openssl'
25
25
  require 'minitest/autorun'
26
26
  require 'concurrent'
27
- require 'moneta'
28
27
 
29
28
  STDOUT.sync = true
30
29
 
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright (c) 2018 Yegor Bugayenko
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the 'Software'), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in all
13
+ # copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ # SOFTWARE.
22
+
23
+ require 'minitest/autorun'
24
+ require 'threads'
25
+ require_relative '../lib/zold/cache'
26
+
27
+ # Cache test.
28
+ # Author:: Yegor Bugayenko (yegor256@gmail.com)
29
+ # Copyright:: Copyright (c) 2018 Yegor Bugayenko
30
+ # License:: MIT
31
+ class TestCache < Minitest::Test
32
+ def test_caches
33
+ cache = Zold::Cache.new
34
+ first = cache.get(:hey, lifetime: 5) { Random.rand }
35
+ second = cache.get(:hey) { Random.rand }
36
+ assert(first == second)
37
+ end
38
+
39
+ def test_caches_and_expires
40
+ cache = Zold::Cache.new
41
+ first = cache.get(:hey, lifetime: 0.01) { Random.rand }
42
+ sleep 0.1
43
+ second = cache.get(:hey) { Random.rand }
44
+ assert(first != second)
45
+ end
46
+
47
+ def test_caches_in_threads
48
+ cache = Zold::Cache.new
49
+ Threads.new(10).assert(100) do
50
+ cache.get(:hey, lifetime: 0.0001) { Random.rand }
51
+ end
52
+ end
53
+ end
data/zold.gemspec CHANGED
@@ -55,7 +55,6 @@ and suggests a different architecture for digital wallet maintenance.'
55
55
  s.rdoc_options = ['--charset=UTF-8']
56
56
  s.extra_rdoc_files = ['README.md', 'LICENSE.txt']
57
57
  s.add_runtime_dependency 'backtrace', '~>0'
58
- s.add_runtime_dependency 'cachy', '~>0'
59
58
  s.add_runtime_dependency 'concurrent-ruby', '~>1.0'
60
59
  s.add_runtime_dependency 'cucumber', '~>3' # has to stay here for Heroku
61
60
  s.add_runtime_dependency 'diffy', '~>3'
@@ -64,7 +63,6 @@ and suggests a different architecture for digital wallet maintenance.'
64
63
  s.add_runtime_dependency 'futex', '~>0'
65
64
  s.add_runtime_dependency 'get_process_mem', '~>0'
66
65
  s.add_runtime_dependency 'json', '~>2'
67
- s.add_runtime_dependency 'moneta', '~>1'
68
66
  s.add_runtime_dependency 'openssl', '~>2'
69
67
  s.add_runtime_dependency 'posix-spawn', '~>0.3'
70
68
  s.add_runtime_dependency 'rainbow', '~>3'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: zold
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.16.4
4
+ version: 0.16.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yegor Bugayenko
@@ -24,20 +24,6 @@ dependencies:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
- - !ruby/object:Gem::Dependency
28
- name: cachy
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - "~>"
32
- - !ruby/object:Gem::Version
33
- version: '0'
34
- type: :runtime
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - "~>"
39
- - !ruby/object:Gem::Version
40
- version: '0'
41
27
  - !ruby/object:Gem::Dependency
42
28
  name: concurrent-ruby
43
29
  requirement: !ruby/object:Gem::Requirement
@@ -150,20 +136,6 @@ dependencies:
150
136
  - - "~>"
151
137
  - !ruby/object:Gem::Version
152
138
  version: '2'
153
- - !ruby/object:Gem::Dependency
154
- name: moneta
155
- requirement: !ruby/object:Gem::Requirement
156
- requirements:
157
- - - "~>"
158
- - !ruby/object:Gem::Version
159
- version: '1'
160
- type: :runtime
161
- prerelease: false
162
- version_requirements: !ruby/object:Gem::Requirement
163
- requirements:
164
- - - "~>"
165
- - !ruby/object:Gem::Version
166
- version: '1'
167
139
  - !ruby/object:Gem::Dependency
168
140
  name: openssl
169
141
  requirement: !ruby/object:Gem::Requirement
@@ -544,6 +516,7 @@ files:
544
516
  - lib/zold.rb
545
517
  - lib/zold/age.rb
546
518
  - lib/zold/amount.rb
519
+ - lib/zold/cache.rb
547
520
  - lib/zold/cached_wallets.rb
548
521
  - lib/zold/commands/alias.rb
549
522
  - lib/zold/commands/args.rb
@@ -646,6 +619,7 @@ files:
646
619
  - test/test__helper.rb
647
620
  - test/test_age.rb
648
621
  - test/test_amount.rb
622
+ - test/test_cache.rb
649
623
  - test/test_cached_wallets.rb
650
624
  - test/test_copies.rb
651
625
  - test/test_dir_items.rb
@@ -746,6 +720,7 @@ test_files:
746
720
  - test/test__helper.rb
747
721
  - test/test_age.rb
748
722
  - test/test_amount.rb
723
+ - test/test_cache.rb
749
724
  - test/test_cached_wallets.rb
750
725
  - test/test_copies.rb
751
726
  - test/test_dir_items.rb