celluloid 0.16.0.pre → 0.16.0.pre2

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
  SHA1:
3
- metadata.gz: 3f9e4bf5d8e26e99c5321bc02c61cafa9de48600
4
- data.tar.gz: b239f25215d8c3ca0c9c27cd3e08954fa62ee35c
3
+ metadata.gz: c9c58eede0a8ebeb315bf6f2fa925e19173dd5e9
4
+ data.tar.gz: 525f0ae4823a55ca1e23bf1ff5b6c8493592551f
5
5
  SHA512:
6
- metadata.gz: be0d373d83500400c1135176382097f8bdffeb378fbce48f95852195975984a626221292ade6182ba84cc5a9ca06fa0849461d28c68e9adea33c129396ab39a3
7
- data.tar.gz: 6f6cd39aec05a5b8f4b461ad88cd6c960a37d5832ca36ee5f633bf0e3229b294fb714668dcf87d843e162749507c301d14d32d2ae2d344c726b3f55346f9e6c8
6
+ metadata.gz: 2ac75588d4accd17305ea04b6329563783db6972262584898e3143bdf6086ba47dc8bcf8c93ad6c7a8b44115c2c718fbcc615219da968ffdfa8a7a5f17b5f908
7
+ data.tar.gz: e1185014388060dcd75a41b583a6df01f7bcbb37e21e1619091e364374cb861a31df7c7110b371887540c2482ff54cfae0cf7a3df534fc188157e220d5f8cd12
data/README.md CHANGED
@@ -170,7 +170,3 @@ License
170
170
 
171
171
  Copyright (c) 2011-2014 Tony Arcieri. Distributed under the MIT License. See
172
172
  LICENSE.txt for further details.
173
-
174
-
175
- [![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/celluloid/celluloid/trend.png)](https://bitdeli.com/free "Bitdeli Badge")
176
-
data/lib/celluloid.rb CHANGED
@@ -7,7 +7,7 @@ module Celluloid
7
7
  # Expose all instance methods as singleton methods
8
8
  extend self
9
9
 
10
- VERSION = '0.16.0.pre'
10
+ VERSION = '0.16.0.pre2'
11
11
 
12
12
  # Linking times out after 5 seconds
13
13
  LINKING_TIMEOUT = 5
@@ -1,3 +1,4 @@
1
+
1
2
  require 'timers'
2
3
 
3
4
  module Celluloid
@@ -112,7 +113,7 @@ module Celluloid
112
113
  @links = Links.new
113
114
  @signals = Signals.new
114
115
  @receivers = Receivers.new
115
- @timers = Timers.new
116
+ @timers = Timers::Group.new
116
117
  @handlers = Handlers.new
117
118
  @running = false
118
119
  @name = nil
@@ -170,31 +171,37 @@ module Celluloid
170
171
  # Perform a linking request with another actor
171
172
  def linking_request(receiver, type)
172
173
  Celluloid.exclusive do
173
- start_time = Time.now
174
+ linking_timeout = Timers::Timeout.new(LINKING_TIMEOUT)
175
+
174
176
  receiver.mailbox << LinkingRequest.new(Actor.current, type)
175
177
  system_events = []
176
178
 
177
- loop do
178
- wait_interval = start_time + LINKING_TIMEOUT - Time.now
179
- message = @mailbox.receive(wait_interval) do |msg|
180
- msg.is_a?(LinkingResponse) &&
181
- msg.actor.mailbox.address == receiver.mailbox.address &&
182
- msg.type == type
179
+ linking_timeout.while_time_remaining do |remaining|
180
+ begin
181
+ message = @mailbox.receive(remaining) do |msg|
182
+ msg.is_a?(LinkingResponse) &&
183
+ msg.actor.mailbox.address == receiver.mailbox.address &&
184
+ msg.type == type
185
+ end
186
+ rescue TimeoutError
187
+ next # IO reactor did something, no message in queue yet.
183
188
  end
184
189
 
185
190
  if message.instance_of? LinkingResponse
186
191
  Celluloid::Probe.actors_linked(self, receiver) if $CELLULOID_MONITORING
192
+
187
193
  # We're done!
188
194
  system_events.each { |ev| @mailbox << ev }
195
+
189
196
  return
190
- elsif message.instance_of? NilClass
191
- raise TimeoutError, "linking timeout of #{LINKING_TIMEOUT} seconds exceeded"
192
- elsif message.instance_of? SystemEvent
197
+ elsif message.is_a? SystemEvent
193
198
  # Queue up pending system events to be processed after we've successfully linked
194
199
  system_events << message
195
- else raise 'wtf'
200
+ else raise "Unexpected message type: #{message.class}. Expected LinkingResponse, NilClass, SystemEvent."
196
201
  end
197
202
  end
203
+
204
+ raise TimeoutError, "linking timeout of #{LINKING_TIMEOUT} seconds exceeded"
198
205
  end
199
206
  end
200
207
 
@@ -10,4 +10,4 @@ module Celluloid
10
10
  Thread.current[:celluloid_chain_id]
11
11
  end
12
12
  end
13
- end
13
+ end
@@ -1,26 +1,33 @@
1
- require 'rbconfig'
2
-
3
1
  module Celluloid
4
2
  module CPUCounter
5
- case RbConfig::CONFIG['host_os'][/^[A-Za-z]+/]
6
- when 'darwin'
7
- @cores = Integer(`/usr/sbin/sysctl hw.ncpu`[/\d+/])
8
- when 'linux'
9
- @cores = if File.exists?("/sys/devices/system/cpu/present")
10
- File.read("/sys/devices/system/cpu/present").split('-').last.to_i+1
11
- else
12
- Dir["/sys/devices/system/cpu/cpu*"].select { |n| n=~/cpu\d+/ }.count
3
+ class << self
4
+ def cores
5
+ @cores ||= count_cores
13
6
  end
14
- when 'mingw', 'mswin'
15
- @cores = Integer(ENV["NUMBER_OF_PROCESSORS"][/\d+/])
16
- when 'freebsd'
17
- @cores = Integer(`sysctl hw.ncpu`[/\d+/])
18
- else
19
- @cores = nil
20
- end
21
7
 
22
- def self.cores; @cores; end
23
- end
24
- end
8
+ private
25
9
 
10
+ def count_cores
11
+ result = from_env || from_sysdev || from_sysctl
12
+ Integer(result.to_s[/\d+/], 10) if result
13
+ end
14
+
15
+ def from_env
16
+ result = ENV['NUMBER_OF_PROCESSORS']
17
+ result if result
18
+ end
26
19
 
20
+ def from_sysdev
21
+ ::IO.read('/sys/devices/system/cpu/present').split('-').last.to_i + 1
22
+ rescue Errno::ENOENT
23
+ result = Dir['/sys/devices/system/cpu/cpu*'].count { |n| n =~ /cpu\d+/ }
24
+ result unless result.zero?
25
+ end
26
+
27
+ def from_sysctl
28
+ result = `sysctl -n hw.ncpu`
29
+ result if $?.success?
30
+ end
31
+ end
32
+ end
33
+ end
@@ -38,24 +38,16 @@ module Celluloid
38
38
 
39
39
  # Receive a message from the Mailbox
40
40
  def receive(timeout = nil, &block)
41
- message = next_message(block)
42
-
43
- until message
44
- if timeout
45
- # TODO: use hitimes/timers instead of Time.now
46
- now = Time.now
47
- wait_until ||= now + timeout
48
- wait_interval = wait_until - now
49
- raise(TimeoutError, "mailbox timeout exceeded", nil) if wait_interval <= 0
50
- else
51
- wait_interval = nil
52
- end
53
-
54
- @reactor.run_once(wait_interval)
55
- message = next_message(block)
41
+ # Get a message if it is available and process it immediately if possible:
42
+ if message = next_message(block)
43
+ return message
56
44
  end
57
45
 
58
- message
46
+ # ... otherwise, run the reactor once, either blocking or will return after the given timeout.
47
+ @reactor.run_once(timeout)
48
+
49
+ # This is a hack to get the main Actor#run loop to recompute the timeout:
50
+ raise TimeoutError
59
51
  rescue IOError
60
52
  raise MailboxShutdown, "mailbox shutdown called during receive"
61
53
  end
@@ -24,7 +24,7 @@ module Celluloid
24
24
  end
25
25
 
26
26
  def __shutdown__
27
- terminators = (@idle + @busy).each do |actor|
27
+ terminators = (@idle + @busy).map do |actor|
28
28
  begin
29
29
  actor.future(:terminate)
30
30
  rescue DeadActorError
@@ -81,6 +81,23 @@ module Celluloid
81
81
  @size
82
82
  end
83
83
 
84
+ def size=(new_size)
85
+ new_size = [0, new_size].max
86
+
87
+ if new_size > size
88
+ delta = new_size - size
89
+ delta.times { @idle << @worker_class.new_link(*@args) }
90
+ else
91
+ (size - new_size).times do
92
+ worker = __provision_worker__
93
+ unlink worker
94
+ @busy.delete worker
95
+ worker.terminate
96
+ end
97
+ end
98
+ @size = new_size
99
+ end
100
+
84
101
  def busy_size
85
102
  @busy.length
86
103
  end
@@ -1,4 +1,5 @@
1
1
  require 'set'
2
+
2
3
  require 'timers'
3
4
 
4
5
  module Celluloid
@@ -6,7 +7,7 @@ module Celluloid
6
7
  class Receivers
7
8
  def initialize
8
9
  @receivers = Set.new
9
- @timers = Timers.new
10
+ @timers = Timers::Group.new
10
11
  end
11
12
 
12
13
  # Receive an asynchronous message
@@ -37,7 +37,7 @@ module Celluloid
37
37
  end
38
38
 
39
39
  def backtrace
40
- "#{self.class} backtrace unavailable. Please try `Celluloid.task_class = Celluloid::TaskThread` if you need backtraces here."
40
+ ["#{self.class} backtrace unavailable. Please try `Celluloid.task_class = Celluloid::TaskThread` if you need backtraces here."]
41
41
  end
42
42
  end
43
43
  end
@@ -2,8 +2,81 @@ require 'spec_helper'
2
2
 
3
3
  describe Celluloid::CPUCounter do
4
4
  describe :cores do
5
- it 'should return an integer' do
6
- Celluloid::CPUCounter.cores.should be_kind_of(Fixnum)
5
+ subject { described_class.cores }
6
+
7
+ let(:num_cores) { 1024 }
8
+
9
+ before do
10
+ described_class.stub(:`) { fail 'backtick stub called' }
11
+ ::IO.stub(:open).and_raise('IO.open stub called!')
12
+ described_class.instance_variable_set('@cores', nil)
13
+ end
14
+
15
+ after { ENV['NUMBER_OF_PROCESSORS'] = nil }
16
+
17
+ context 'from valid env value' do
18
+ before { ENV['NUMBER_OF_PROCESSORS'] = num_cores.to_s }
19
+ it { should eq num_cores }
20
+ end
21
+
22
+ context 'from invalid env value' do
23
+ before { ENV['NUMBER_OF_PROCESSORS'] = '' }
24
+ specify { expect { subject }.to raise_error(ArgumentError) }
25
+ end
26
+
27
+ context 'with no env value' do
28
+ before { ENV['NUMBER_OF_PROCESSORS'] = nil }
29
+
30
+ context 'when /sys/devices/system/cpu/present exists' do
31
+ before do
32
+ ::IO.should_receive(:read).with('/sys/devices/system/cpu/present')
33
+ .and_return("dunno-whatever-#{num_cores - 1}")
34
+ end
35
+ it { should eq num_cores }
36
+ end
37
+
38
+ context 'when /sys/devices/system/cpu/present does NOT exist' do
39
+ before do
40
+ ::IO.should_receive(:read).with('/sys/devices/system/cpu/present')
41
+ .and_raise(Errno::ENOENT)
42
+ end
43
+
44
+ context 'when /sys/devices/system/cpu/cpu* files exist' do
45
+ before do
46
+ cpu_entries = (1..num_cores).map { |n| "cpu#{n}" }
47
+ cpu_entries << 'non-cpu-entry-to-ignore'
48
+ Dir.should_receive(:[]).with('/sys/devices/system/cpu/cpu*')
49
+ .and_return(cpu_entries)
50
+ end
51
+ it { should eq num_cores }
52
+ end
53
+
54
+ context 'when /sys/devices/system/cpu/cpu* files DO NOT exist' do
55
+ before do
56
+ Dir.should_receive(:[]).with('/sys/devices/system/cpu/cpu*')
57
+ .and_return([])
58
+ end
59
+
60
+ context 'when sysctl blows up' do
61
+ before { described_class.stub(:`).and_raise(Errno::EINTR) }
62
+ specify { expect { subject }.to raise_error }
63
+ end
64
+
65
+ context 'when sysctl fails' do
66
+ before { described_class.stub(:`).and_return(`false`) }
67
+ it { should be nil }
68
+ end
69
+
70
+ context 'when sysctl succeeds' do
71
+ before do
72
+ described_class.should_receive(:`).with('sysctl -n hw.ncpu')
73
+ .and_return(num_cores.to_s)
74
+ `true`
75
+ end
76
+ it { should eq num_cores }
77
+ end
78
+ end
79
+ end
7
80
  end
8
81
  end
9
82
  end
@@ -14,11 +14,23 @@ describe "Celluloid.pool", actor_system: :global do
14
14
  end
15
15
  end
16
16
 
17
+ def sleepy_work
18
+ t = Time.now.to_f
19
+ sleep 0.25
20
+ t
21
+ end
22
+
17
23
  def crash
18
24
  raise ExampleError, "zomgcrash"
19
25
  end
20
26
  end
21
27
 
28
+ def test_concurrency_of(pool)
29
+ baseline = Time.now.to_f
30
+ values = 10.times.map { pool.future.sleepy_work }.map(&:value)
31
+ values.select {|t| t - baseline < 0.1 }.length
32
+ end
33
+
22
34
  subject { MyWorker.pool }
23
35
 
24
36
  it "processes work units synchronously" do
@@ -56,4 +68,25 @@ describe "Celluloid.pool", actor_system: :global do
56
68
  end
57
69
  futures.map(&:value)
58
70
  end
71
+
72
+ context "#size=" do
73
+ subject { MyWorker.pool size: 4 }
74
+
75
+ it "should adjust the pool size up", pending: 'flaky' do
76
+ expect(test_concurrency_of(subject)).to eq(4)
77
+
78
+ subject.size = 6
79
+ subject.size.should == 6
80
+
81
+ test_concurrency_of(subject).should == 6
82
+ end
83
+
84
+ it "should adjust the pool size down" do
85
+ test_concurrency_of(subject).should == 4
86
+
87
+ subject.size = 2
88
+ subject.size.should == 2
89
+ test_concurrency_of(subject).should == 2
90
+ end
91
+ end
59
92
  end
@@ -45,8 +45,8 @@ describe Celluloid::StackDump do
45
45
  end
46
46
 
47
47
  describe '#threads' do
48
- it 'should include threads that are not actors' do
49
- subject.threads.size.should == 3
48
+ it 'should include threads that are not actors', pending: 'flaky' do
49
+ expect(subject.threads.size).to eq(3)
50
50
  end
51
51
 
52
52
  it 'should include idle threads' do
@@ -57,8 +57,8 @@ describe Celluloid::StackDump do
57
57
  subject.threads.map(&:thread_id).should include(@active_thread.object_id)
58
58
  end
59
59
 
60
- it 'should have the correct roles' do
61
- subject.threads.map(&:role).should include(nil, :other_thing, :task)
60
+ it 'should have the correct roles', pending: 'flaky' do
61
+ expect(subject.threads.map(&:role)).to include(nil, :other_thing, :task)
62
62
  end
63
63
  end
64
64
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: celluloid
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.16.0.pre
4
+ version: 0.16.0.pre2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tony Arcieri
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-03-29 00:00:00.000000000 Z
11
+ date: 2014-06-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: timers
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 2.0.0
19
+ version: 3.0.0
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: 2.0.0
26
+ version: 3.0.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rake
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -80,6 +80,20 @@ dependencies:
80
80
  - - ">="
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rubocop
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
83
97
  description: Celluloid enables people to build concurrent programs out of concurrent
84
98
  objects just as easily as they build sequential programs out of sequential objects
85
99
  email:
@@ -196,7 +210,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
196
210
  version: 1.3.6
197
211
  requirements: []
198
212
  rubyforge_project:
199
- rubygems_version: 2.2.0
213
+ rubygems_version: 2.2.2
200
214
  signing_key:
201
215
  specification_version: 4
202
216
  summary: Actor-based concurrent object framework for Ruby