celluloid 0.16.0.pre → 0.16.0.pre2

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
  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