Update upstream source from tag 'upstream/1.20.1'
Update to upstream version '1.20.1'
with Debian dir fe456cc95fe6c0b8576ba49d4f373b51dc1f1f29
Hideki Yamane
3 years ago
0 | name: CI | |
1 | on: | |
2 | push: | |
3 | branches: [master] | |
4 | pull_request: | |
5 | branches: [master] | |
6 | jobs: | |
7 | test: | |
8 | runs-on: ubuntu-latest | |
9 | services: | |
10 | mysql: | |
11 | image: mysql | |
12 | strategy: | |
13 | matrix: | |
14 | ruby: [ '2.5', '2.6', '2.7' ] | |
15 | name: ${{ matrix.ruby }} rake ${{ matrix.task }} | |
16 | steps: | |
17 | - uses: actions/checkout@v2 | |
18 | - uses: ruby/setup-ruby@v1 | |
19 | with: | |
20 | ruby-version: ${{ matrix.ruby }} | |
21 | bundler-cache: true # runs 'bundle install' and caches installed gems automatically | |
22 | - run: bundle exec rake |
0 | language: ruby | |
1 | dist: precise | |
2 | branches: | |
3 | only: master | |
4 | rvm: | |
5 | - 2.2 | |
6 | - 2.3 | |
7 | - 2.4 | |
8 | - 2.5 | |
9 | - 2.6 | |
10 | ||
11 | matrix: | |
12 | include: | |
13 | - rvm: 2.6 | |
14 | env: RUBYOPT="--jit" | |
15 | allow_failures: | |
16 | - env: RUBYOPT="--jit" | |
17 | ||
18 | before_install: ruby -e "File.write('Gemfile.lock', File.read('Gemfile.lock').split('BUNDLED WITH').first)" |
3 | 3 | gem 'bump' |
4 | 4 | gem 'rake' |
5 | 5 | gem 'rspec' |
6 | gem 'activerecord', "~>4.2.8" | |
6 | gem 'activerecord', "~> 6.0" | |
7 | 7 | gem 'ruby-progressbar' |
8 | 8 | gem 'rspec-rerun' |
9 | 9 | gem 'rspec-legacy_formatters' |
10 | 10 | |
11 | gem 'mysql2', :group => :mysql | |
11 | gem 'mysql2', group: :mysql | |
12 | 12 | gem 'sqlite3' |
0 | 0 | PATH |
1 | 1 | remote: . |
2 | 2 | specs: |
3 | parallel (1.19.1) | |
3 | parallel (1.20.1) | |
4 | 4 | |
5 | 5 | GEM |
6 | 6 | remote: https://rubygems.org/ |
7 | 7 | specs: |
8 | activemodel (4.2.8) | |
9 | activesupport (= 4.2.8) | |
10 | builder (~> 3.1) | |
11 | activerecord (4.2.8) | |
12 | activemodel (= 4.2.8) | |
13 | activesupport (= 4.2.8) | |
14 | arel (~> 6.0) | |
15 | activesupport (4.2.8) | |
16 | i18n (~> 0.7) | |
8 | activemodel (6.0.3.1) | |
9 | activesupport (= 6.0.3.1) | |
10 | activerecord (6.0.3.1) | |
11 | activemodel (= 6.0.3.1) | |
12 | activesupport (= 6.0.3.1) | |
13 | activesupport (6.0.3.1) | |
14 | concurrent-ruby (~> 1.0, >= 1.0.2) | |
15 | i18n (>= 0.7, < 2) | |
17 | 16 | minitest (~> 5.1) |
18 | thread_safe (~> 0.3, >= 0.3.4) | |
19 | 17 | tzinfo (~> 1.1) |
20 | arel (6.0.4) | |
21 | builder (3.2.3) | |
18 | zeitwerk (~> 2.2, >= 2.2.2) | |
22 | 19 | bump (0.5.3) |
20 | concurrent-ruby (1.1.6) | |
23 | 21 | diff-lcs (1.3) |
24 | i18n (0.8.1) | |
25 | minitest (5.10.1) | |
26 | mysql2 (0.5.2) | |
27 | rake (12.0.0) | |
22 | i18n (1.8.3) | |
23 | concurrent-ruby (~> 1.0) | |
24 | minitest (5.14.1) | |
25 | mysql2 (0.5.3) | |
26 | rake (13.0.1) | |
28 | 27 | rspec (3.6.0) |
29 | 28 | rspec-core (~> 3.6.0) |
30 | 29 | rspec-expectations (~> 3.6.0) |
43 | 42 | rspec (~> 3.0) |
44 | 43 | rspec-support (3.6.0) |
45 | 44 | ruby-progressbar (1.8.1) |
46 | sqlite3 (1.3.13) | |
45 | sqlite3 (1.4.2) | |
47 | 46 | thread_safe (0.3.6) |
48 | 47 | thread_safe (0.3.6-java) |
49 | tzinfo (1.2.3) | |
48 | tzinfo (1.2.7) | |
50 | 49 | thread_safe (~> 0.1) |
50 | zeitwerk (2.3.0) | |
51 | 51 | |
52 | 52 | PLATFORMS |
53 | 53 | java |
54 | 54 | ruby |
55 | 55 | |
56 | 56 | DEPENDENCIES |
57 | activerecord (~> 4.2.8) | |
57 | activerecord (~> 6.0) | |
58 | 58 | bump |
59 | 59 | mysql2 |
60 | 60 | parallel! |
66 | 66 | sqlite3 |
67 | 67 | |
68 | 68 | BUNDLED WITH |
69 | 2.0.1 | |
69 | 2.1.4 |
42 | 42 | Parallel.each( -> { items.pop || Parallel::Stop }) { |number| ... } |
43 | 43 | ``` |
44 | 44 | |
45 | You can also call `any?` or `all?`, which work the same way as `Array#any?` and `Array#all?`. | |
45 | Also supports `any?` or `all?` | |
46 | 46 | |
47 | 47 | ```Ruby |
48 | 48 | Parallel.any?([1,2,3,4,5,6,7]) { |number| number == 4 } |
51 | 51 | Parallel.all?([1,2,nil,4,5]) { |number| number != nil } |
52 | 52 | # => false |
53 | 53 | ``` |
54 | ||
55 | 54 | |
56 | 55 | Processes/Threads are workers, they grab the next piece of work when they finish. |
57 | 56 | |
69 | 68 | |
70 | 69 | ### ActiveRecord |
71 | 70 | |
72 | Try any of those to get working parallel AR | |
71 | #### Connection Lost | |
72 | ||
73 | - Multithreading needs connection pooling, forks need reconnects | |
74 | - Adjust connection pool size in `config/database.yml` when multithreading | |
73 | 75 | |
74 | 76 | ```Ruby |
75 | 77 | # reproducibly fixes things (spec/cases/map_with_ar.rb) |
92 | 94 | end |
93 | 95 | ``` |
94 | 96 | |
97 | #### NameError: uninitialized constant | |
98 | ||
99 | A race happens when ActiveRecord models are autoloaded inside parallel threads | |
100 | in environments that lazy-load, like development, test, or migrations. | |
101 | ||
102 | To fix, autoloaded classes before the parallel block with either `require '<modelname>'` or `ModelName.class`. | |
103 | ||
95 | 104 | ### Break |
96 | 105 | |
97 | 106 | ```Ruby |
98 | Parallel.map(User.all) do |user| | |
107 | Parallel.map([1, 2, 3]) do |i| | |
99 | 108 | raise Parallel::Break # -> stops after all current items are finished |
100 | 109 | end |
110 | ``` | |
111 | ||
112 | ```Ruby | |
113 | Parallel.map([1, 2, 3]) { |i| raise Parallel::Break, i if i == 2 } == 2 | |
101 | 114 | ``` |
102 | 115 | |
103 | 116 | ### Kill |
0 | -----BEGIN CERTIFICATE----- | |
1 | MIIDcDCCAligAwIBAgIBATANBgkqhkiG9w0BAQUFADA/MRAwDgYDVQQDDAdtaWNo | |
2 | YWVsMRcwFQYKCZImiZPyLGQBGRYHZ3Jvc3NlcjESMBAGCgmSJomT8ixkARkWAml0 | |
3 | MB4XDTE0MDIwNDIwMjk0MVoXDTE1MDIwNDIwMjk0MVowPzEQMA4GA1UEAwwHbWlj | |
4 | aGFlbDEXMBUGCgmSJomT8ixkARkWB2dyb3NzZXIxEjAQBgoJkiaJk/IsZAEZFgJp | |
5 | dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMorXo/hgbUq97+kII9H | |
6 | MsQcLdC/7wQ1ZP2OshVHPkeP0qH8MBHGg6eYisOX2ubNagF9YTCZWnhrdKrwpLOO | |
7 | cPLaZbjUjljJ3cQR3B8Yn1veV5IhG86QseTBjymzJWsLpqJ1UZGpfB9tXcsFtuxO | |
8 | 6vHvcIHdzvc/OUkICttLbH+1qb6rsHUceqh+JrH4GrsJ5H4hAfIdyS2XMK7YRKbh | |
9 | h+IBu6dFWJJByzFsYmV1PDXln3UBmgAt65cmCu4qPfThioCGDzbSJrGDGLmw/pFX | |
10 | FPpVCm1zgYSb1v6Qnf3cgXa2f2wYGm17+zAVyIDpwryFru9yF/jJxE38z/DRsd9R | |
11 | /88CAwEAAaN3MHUwCQYDVR0TBAIwADALBgNVHQ8EBAMCBLAwHQYDVR0OBBYEFLIj | |
12 | Z1x7SnjGGHK+MiVZkFjjS/iMMB0GA1UdEQQWMBSBEm1pY2hhZWxAZ3Jvc3Nlci5p | |
13 | dDAdBgNVHRIEFjAUgRJtaWNoYWVsQGdyb3NzZXIuaXQwDQYJKoZIhvcNAQEFBQAD | |
14 | ggEBAExBcUWfGuamYn+IddOA0Ws8jUKwB14RXoZRDrTiTAlMm3Bkg2OKyxS3uJXa | |
15 | 6Z+LwFiZwVYk62yHXqNzEJycQk4SEmY+xDWLj0p7X6qEeU4QZKwR1TwJ5z3PTrZ6 | |
16 | irJgM3q7NIBRvmTzRaAghWcQn+Eyr5YLOfMksjVBMUMnzh5/ZDgq53LphgJbGwvz | |
17 | ScJAgfNclLHnjk9q1mT1s0e1FPWbiAL3siBIR5HpH8qtSEiivTf2ntciebOqS93f | |
18 | F5etKHZg0j3eHO31/i2HnswY04lqGImUu6aM5EnijFTB7PPW2KwKKM4+kKDYFdlw | |
19 | /0WV1Ng2/Y6qsHwmqGg2VlYj2h4= | |
20 | -----END CERTIFICATE----- |
2 | 2 | require 'parallel/processor_count' |
3 | 3 | |
4 | 4 | module Parallel |
5 | extend Parallel::ProcessorCount | |
5 | extend ProcessorCount | |
6 | ||
7 | Stop = Object.new.freeze | |
6 | 8 | |
7 | 9 | class DeadWorker < StandardError |
8 | 10 | end |
9 | 11 | |
10 | 12 | class Break < StandardError |
11 | end | |
12 | ||
13 | class Kill < StandardError | |
13 | attr_reader :value | |
14 | def initialize(value = nil) | |
15 | @value = value | |
16 | end | |
17 | end | |
18 | ||
19 | class Kill < Break | |
14 | 20 | end |
15 | 21 | |
16 | 22 | class UndumpableException < StandardError |
20 | 26 | @backtrace = original.backtrace |
21 | 27 | end |
22 | 28 | end |
23 | ||
24 | Stop = Object.new.freeze | |
25 | 29 | |
26 | 30 | class ExceptionWrapper |
27 | 31 | attr_reader :exception |
101 | 105 | item, index = @mutex.synchronize do |
102 | 106 | return if @stopped |
103 | 107 | item = @lambda.call |
104 | @stopped = (item == Parallel::Stop) | |
108 | @stopped = (item == Stop) | |
105 | 109 | return if @stopped |
106 | 110 | [item, @index += 1] |
107 | 111 | end |
200 | 204 | |
201 | 205 | class << self |
202 | 206 | def in_threads(options={:count => 2}) |
207 | threads = [] | |
208 | count, _ = extract_count_from_options(options) | |
209 | ||
203 | 210 | Thread.handle_interrupt(Exception => :never) do |
204 | 211 | begin |
205 | threads = [] | |
206 | count, _ = extract_count_from_options(options) | |
207 | count.times do |i| | |
208 | threads << Thread.new { yield(i) } | |
209 | end | |
210 | 212 | Thread.handle_interrupt(Exception => :immediate) do |
213 | count.times do |i| | |
214 | threads << Thread.new { yield(i) } | |
215 | end | |
211 | 216 | threads.map(&:value) |
212 | 217 | end |
213 | 218 | ensure |
228 | 233 | |
229 | 234 | def any?(*args, &block) |
230 | 235 | raise "You must provide a block when calling #any?" if block.nil? |
231 | !each(*args) { |*a| raise Parallel::Kill if block.call(*a) } | |
236 | !each(*args) { |*a| raise Kill if block.call(*a) } | |
232 | 237 | end |
233 | 238 | |
234 | 239 | def all?(*args, &block) |
235 | 240 | raise "You must provide a block when calling #all?" if block.nil? |
236 | !!each(*args) { |*a| raise Parallel::Kill unless block.call(*a) } | |
241 | !!each(*args) { |*a| raise Kill unless block.call(*a) } | |
237 | 242 | end |
238 | 243 | |
239 | 244 | def each_with_index(array, options={}, &block) |
268 | 273 | options[:return_results] = (options[:preserve_results] != false || !!options[:finish]) |
269 | 274 | add_progress_bar!(job_factory, options) |
270 | 275 | |
271 | results = if size == 0 | |
272 | work_direct(job_factory, options, &block) | |
273 | elsif method == :in_threads | |
274 | work_in_threads(job_factory, options.merge(:count => size), &block) | |
275 | else | |
276 | work_in_processes(job_factory, options.merge(:count => size), &block) | |
277 | end | |
278 | if results | |
279 | options[:return_results] ? results : source | |
280 | end | |
276 | result = | |
277 | if size == 0 | |
278 | work_direct(job_factory, options, &block) | |
279 | elsif method == :in_threads | |
280 | work_in_threads(job_factory, options.merge(:count => size), &block) | |
281 | else | |
282 | work_in_processes(job_factory, options.merge(:count => size), &block) | |
283 | end | |
284 | ||
285 | return result.value if result.is_a?(Break) | |
286 | raise result if result.is_a?(Exception) | |
287 | options[:return_results] ? result : source | |
281 | 288 | end |
282 | 289 | |
283 | 290 | def map_with_index(array, options={}, &block) |
338 | 345 | rescue |
339 | 346 | exception = $! |
340 | 347 | end |
341 | handle_exception(exception, results) | |
348 | exception || results | |
342 | 349 | ensure |
343 | 350 | self.worker_number = nil |
344 | 351 | end |
365 | 372 | end |
366 | 373 | end |
367 | 374 | |
368 | handle_exception(exception, results) | |
375 | exception || results | |
369 | 376 | end |
370 | 377 | |
371 | 378 | def work_in_processes(job_factory, options, &blk) |
399 | 406 | results_mutex.synchronize { results[index] = result } # arrays are not threads safe on jRuby |
400 | 407 | rescue StandardError => e |
401 | 408 | exception = e |
402 | if Parallel::Kill === exception | |
409 | if Kill === exception | |
403 | 410 | (workers - [worker]).each do |w| |
404 | 411 | w.thread.kill if w.thread |
405 | 412 | UserInterruptHandler.kill(w.pid) |
412 | 419 | end |
413 | 420 | end |
414 | 421 | end |
415 | ||
416 | handle_exception(exception, results) | |
422 | exception || results | |
417 | 423 | end |
418 | 424 | |
419 | 425 | def replace_worker(job_factory, workers, i, options, blk) |
482 | 488 | end |
483 | 489 | end |
484 | 490 | |
485 | def handle_exception(exception, results) | |
486 | return nil if [Parallel::Break, Parallel::Kill].include? exception.class | |
487 | raise exception if exception | |
488 | results | |
489 | end | |
490 | ||
491 | 491 | # options is either a Integer or a Hash with :count |
492 | 492 | def extract_count_from_options(options) |
493 | 493 | if options.is_a?(Hash) |
14 | 14 | } |
15 | 15 | s.files = `git ls-files lib MIT-LICENSE.txt`.split("\n") |
16 | 16 | s.license = "MIT" |
17 | s.required_ruby_version = '>= 2.2' | |
17 | s.required_ruby_version = '>= 2.4' | |
18 | 18 | end |
0 | 0 | require './spec/cases/helper' |
1 | ||
2 | results = Parallel.map(Array.new(20), :in_processes => 20) do | |
3 | `lsof | grep pipe | wc -l`.to_i | |
4 | end | |
5 | puts results.max | |
1 | count = ->(*) { `lsof | grep pipe | wc -l`.to_i } | |
2 | start = count.() | |
3 | results = Parallel.map(Array.new(20), :in_processes => 20, &count) | |
4 | puts results.max - start |
0 | 0 | require './spec/cases/helper' |
1 | 1 | require "active_record" |
2 | 2 | require "sqlite3" |
3 | require "tempfile" | |
3 | 4 | STDOUT.sync = true |
4 | 5 | in_worker_type = "in_#{ENV.fetch('WORKER_TYPE')}".to_sym |
5 | 6 | |
6 | Tempfile.open("db") do |temp| | |
7 | ||
7 | Tempfile.create("db") do |temp| | |
8 | 8 | ActiveRecord::Schema.verbose = false |
9 | 9 | ActiveRecord::Base.establish_connection( |
10 | 10 | :adapter => "sqlite3", |
0 | 0 | require './spec/cases/helper' |
1 | 1 | require "active_record" |
2 | 2 | |
3 | Tempfile.open("xxx") do |f| | |
4 | database = "parallel_with_ar_test" | |
5 | `mysql #{database} -e '' || mysql -e 'create database #{database}'` | |
3 | database = "parallel_with_ar_test" | |
4 | `mysql #{database} -e '' || mysql -e 'create database #{database}'` | |
6 | 5 | |
7 | ActiveRecord::Schema.verbose = false | |
8 | ActiveRecord::Base.establish_connection( | |
9 | :adapter => "mysql2", | |
10 | :database => database | |
11 | ) | |
6 | ActiveRecord::Schema.verbose = false | |
7 | ActiveRecord::Base.establish_connection( | |
8 | :adapter => "mysql2", | |
9 | :database => database | |
10 | ) | |
12 | 11 | |
13 | class User < ActiveRecord::Base | |
14 | end | |
12 | class User < ActiveRecord::Base | |
13 | end | |
15 | 14 | |
16 | # create tables | |
17 | unless User.table_exists? | |
18 | ActiveRecord::Schema.define(:version => 1) do | |
19 | create_table :users do |t| | |
20 | t.string :name | |
21 | end | |
15 | # create tables | |
16 | unless User.table_exists? | |
17 | ActiveRecord::Schema.define(:version => 1) do | |
18 | create_table :users do |t| | |
19 | t.string :name | |
22 | 20 | end |
23 | 21 | end |
22 | end | |
24 | 23 | |
25 | User.delete_all | |
24 | User.delete_all | |
26 | 25 | |
27 | User.create!(:name => "X") | |
26 | User.create!(:name => "X") | |
28 | 27 | |
29 | Parallel.map(1..8) do |i| | |
30 | User.create!(:name => i) | |
31 | end | |
28 | Parallel.map(1..8) do |i| | |
29 | User.create!(:name => i) | |
30 | end | |
32 | 31 | |
33 | puts "User.count: #{User.count}" | |
32 | puts "User.count: #{User.count}" | |
34 | 33 | |
35 | puts User.connection.reconnect!.inspect | |
34 | puts User.connection.reconnect!.inspect | |
36 | 35 | |
37 | Parallel.map(1..8, :in_threads => 4) do |i| | |
38 | User.create!(:name => i) | |
39 | end | |
36 | Parallel.map(1..8, :in_threads => 4) do |i| | |
37 | User.create!(:name => i) | |
38 | end | |
40 | 39 | |
41 | User.create!(:name => "X") | |
40 | User.create!(:name => "X") | |
42 | 41 | |
43 | puts User.all.map(&:name).sort.join("-") | |
44 | end | |
42 | puts User.all.map(&:name).sort.join("-") |
0 | require './spec/cases/helper' | |
1 | require 'timeout' | |
2 | ||
3 | Parallel.each([1], in_threads: 1) do |i| | |
4 | begin | |
5 | Timeout.timeout(0.1) { sleep 0.2 } | |
6 | rescue Timeout::Error | |
7 | puts "OK" | |
8 | else | |
9 | puts "BROKEN" | |
10 | end | |
11 | end |
7 | 7 | result = Parallel.public_send(method, 1..100, in_worker_type => worker_size) do |x| |
8 | 8 | sleep 0.1 # so all workers get started |
9 | 9 | print x |
10 | raise Parallel::Break if x == 1 | |
10 | raise Parallel::Break, *ARGV if x == 1 | |
11 | 11 | sleep 0.2 # so now no work gets queued before Parallel::Break is raised |
12 | 12 | x |
13 | 13 | end |
178 | 178 | end |
179 | 179 | |
180 | 180 | it 'can handle to high fork rate' do |
181 | unless RbConfig::CONFIG["target_os"] =~ /darwin1/ | |
182 | `ruby spec/cases/parallel_high_fork_rate.rb`.should == 'OK' | |
183 | end | |
181 | next if RbConfig::CONFIG["target_os"].include?("darwin1") # kills macs for some reason | |
182 | `ruby spec/cases/parallel_high_fork_rate.rb`.should == 'OK' | |
184 | 183 | end |
185 | 184 | |
186 | 185 | it 'does not leave processes behind while running' do |
189 | 188 | end |
190 | 189 | |
191 | 190 | it "does not open unnecessary pipes" do |
192 | open_pipes = `lsof | grep pipe | wc -l`.to_i | |
193 | max_pipes = `ruby spec/cases/count_open_pipes.rb`.to_i | |
194 | (max_pipes - open_pipes).should < 400 | |
191 | max = (RbConfig::CONFIG["target_os"].include?("darwin1") ? 10 : 1800) # somehow super bad on CI | |
192 | `ruby spec/cases/count_open_pipes.rb`.to_i.should < max | |
195 | 193 | end |
196 | 194 | end |
197 | 195 | |
211 | 209 | end |
212 | 210 | |
213 | 211 | it "raises when a thread raises" do |
212 | Thread.report_on_exception = false | |
214 | 213 | lambda{ Parallel.in_threads(2){|i| raise "TEST"} }.should raise_error("TEST") |
214 | ensure | |
215 | Thread.report_on_exception = true | |
215 | 216 | end |
216 | 217 | end |
217 | 218 | |
283 | 284 | |
284 | 285 | it "does not call the finish hook when a start hook fails with #{type}" do |
285 | 286 | `METHOD=map WORKER_TYPE=#{type} ruby spec/cases/with_exception_in_start_before_finish.rb 2>&1`.should == '3 called' |
287 | end | |
288 | ||
289 | it "can return from break with #{type}" do | |
290 | `METHOD=map WORKER_TYPE=#{type} ruby spec/cases/with_break.rb hi 2>&1`.should =~ /^\d{4} Parallel::Break raised - result "hi"$/ | |
286 | 291 | end |
287 | 292 | |
288 | 293 | it "sets Parallel.worker_number with 4 #{type}" do |
466 | 471 | out = `ruby spec/cases/map_worker_number_isolation.rb` |
467 | 472 | out.should == "0,1\nOK" |
468 | 473 | end |
474 | ||
475 | it 'can use Timeout' do | |
476 | out = `ruby spec/cases/timeout_in_threads.rb` | |
477 | out.should == "OK\n" | |
478 | end | |
469 | 479 | end |
470 | 480 | |
471 | 481 | describe ".map_with_index" do |