concurrent-ruby-edge 0.2.0.pre3 → 0.2.0.pre4

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: a4d13aad3839f1bfa159af7cc02464800dd062fb
4
- data.tar.gz: 936d530a0a9368d1947339a2d83a6d9f36c979fd
3
+ metadata.gz: 8589b43e4b23f4d4bb73cddf2123b436e0ea90ba
4
+ data.tar.gz: baa80cc8ded0dc8a050ce3a64a933183575584a4
5
5
  SHA512:
6
- metadata.gz: f0fd846fc8ab69642ac313f12e298547ec1958d98c50466ceae1df09df7d047eccea65426fb3c04cb5d4433c933cc73f2ffb60ad81bd4f36a97418c11e58b37d
7
- data.tar.gz: d3a92fbc3ebfb09256ba159b4016c0b0caaa371c762ccfb47d01789a09cd8d906f7052f6fa37f2b5c6d7057aff1561f384fe5e032cf25347663a3e93885b0c41
6
+ metadata.gz: 2c3fbd2d6e8718e62457e39c61bfe95a0da959072af5e05d2162fd12d8aa1aa15137428916766bde9b32f7359f9cab8b21b5883851d5bf432541e1dd531ca719
7
+ data.tar.gz: a538eca680505fb8b3192fb6a1b5dbcdcc63ac757d56b00bca5745256bd01d007f40d50aad0c4db2df6a33f13e42efe7af384595b3998e9e4c0166094fa5635a
data/README.md CHANGED
@@ -49,6 +49,14 @@ MRI 1.9.3, 2.0, 2.1, 2.2, JRuby (1.9 mode), and Rubinius 2.x are supported.
49
49
  This gem should be fully compatible with any interpreter that is compliant with Ruby 1.9.3 or newer.
50
50
  Java 8 is preferred for JRuby but every Java version on which JRuby 9000 runs will be supported.
51
51
 
52
+ ## Thread Safety
53
+
54
+ *Concurrent Ruby makes the strongest thread safety guarantees of any Ruby concurrency library. We are the only library with a published [memory model](https://github.com/ruby-concurrency/concurrent-ruby/blob/master/doc/synchronization.md) which provides consistent behavior and guarantees on all three of the main Ruby interpreters (MRI/CRuby, JRuby, and Rubinius).*
55
+
56
+ Every abstraction in this library is thread safe. Similarly, all are deadlock free and many are fully lock free. Specific thread safety guarantees are documented with each abstraction.
57
+
58
+ It is critical to remember, however, that Ruby is a language of mutable references. *No* concurrency library for Ruby can ever prevent the user from making thread safety mistakes (such as sharing a mutable object between threads and modifying it on both threads) or from creating deadlocks through incorrect use of locks. All the library can do is provide safe abstractions which encourage safe practices. Concurrent Ruby provides more safe concurrency abstractions than any other Ruby library, many of which support the mantra of ["Do not communicate by sharing memory; instead, share memory by communicating"](https://blog.golang.org/share-memory-by-communicating). Concurrent Ruby is also the only Ruby library which provides a full suite of thread safe and immutable variable types and data structures.
59
+
52
60
  ## Features & Documentation
53
61
 
54
62
  We have a roadmap guiding our work toward the [v1.0.0 release](https://github.com/ruby-concurrency/concurrent-ruby/issues/257).
@@ -229,39 +237,6 @@ and load the appropriate C extensions.
229
237
  No gems should depend on `concurrent-ruby-ext`. Doing so will force C extensions on your users.
230
238
  The best practice is to depend on `concurrent-ruby` and let users to decide if they want C extensions.
231
239
 
232
- ### Building
233
-
234
- All published versions of this gem (core, extension, and several platform-specific packages) are compiled,
235
- packaged, tested, and published using an open, [automated process](https://github.com/ruby-concurrency/rake-compiler-dev-box).
236
- This process can also be used to create pre-compiled binaries of the extension gem for virtually
237
- any platform. *Documentation is forthcoming...*
238
-
239
- ```
240
- *MRI only*
241
- bundle exec rake build:native # Build concurrent-ruby-ext-<version>-<platform>.gem into the pkg dir
242
- bundle exec rake compile:extension # Compile extension
243
-
244
- *JRuby only*
245
- bundle exec rake build # Build JRuby-specific core gem (alias for `build:core`)
246
- bundle exec rake build:core # Build concurrent-ruby-<version>-java.gem into the pkg directory
247
-
248
- *All except JRuby*
249
- bundle exec rake build:core # Build concurrent-ruby-<version>.gem into the pkg directory
250
- bundle exec rake build:ext # Build concurrent-ruby-ext-<version>.gem into the pkg directory
251
-
252
- *When Docker IS installed*
253
- bundle exec rake build:windows # Build the windows binary <version> gems per rake-compiler-dock
254
- bundle exec rake build # Build core, extension, and edge gems, including Windows binaries
255
-
256
- *When Docker is NOT installed*
257
- bundle exec rake build # Build core, extension, and edge gems (excluding Windows binaries)
258
-
259
- *All*
260
- bundle exec rake clean # Remove any temporary products
261
- bundle exec rake clobber # Remove any generated file
262
- bundle exec rake compile # Compile all the extensions
263
- ```
264
-
265
240
  ## Maintainers
266
241
 
267
242
  * [Jerry D'Antonio](https://github.com/jdantonio) (creator)
@@ -277,14 +252,6 @@ bundle exec rake compile # Compile all the extensions
277
252
  * [Charles Oliver Nutter](https://github.com/headius) for the `atomic` and `thread_safe` gems
278
253
  * [thedarkone](https://github.com/thedarkone) for the `thread_safe` gem
279
254
 
280
- ## Contributing
281
-
282
- 1. Fork it
283
- 2. Create your feature branch (`git checkout -b my-new-feature`)
284
- 3. Commit your changes (`git commit -am 'Add some feature'`)
285
- 4. Push to the branch (`git push origin my-new-feature`)
286
- 5. Create new Pull Request
287
-
288
255
  ## License and Copyright
289
256
 
290
257
  *Concurrent Ruby* is free software released under the [MIT License](http://www.opensource.org/licenses/MIT).
@@ -8,8 +8,10 @@ module Concurrent
8
8
 
9
9
  # {include:file:doc/channel.md}
10
10
  class Channel
11
+ extend Forwardable
11
12
  include Enumerable
12
13
 
14
+ # NOTE: Move to global IO pool once stable
13
15
  GOROUTINES = Concurrent::CachedThreadPool.new
14
16
  private_constant :GOROUTINES
15
17
 
@@ -32,10 +34,17 @@ module Concurrent
32
34
  end
33
35
  end
34
36
 
37
+ def_delegators :buffer,
38
+ :size, :capacity, :close, :closed?,
39
+ :blocking?, :empty?, :full?
40
+
41
+ alias_method :length, :size
42
+ alias_method :stop, :close
43
+
35
44
  def initialize(opts = {})
36
45
  # undocumented -- for internal use only
37
46
  if opts.is_a? Buffer::Base
38
- @buffer = opts
47
+ self.buffer = opts
39
48
  return
40
49
  end
41
50
 
@@ -45,25 +54,20 @@ module Concurrent
45
54
  if size && buffer == :unbuffered
46
55
  raise ArgumentError.new('unbuffered channels cannot have a size')
47
56
  elsif size.nil? && buffer.nil?
48
- @buffer = BUFFER_TYPES[:unbuffered].new
57
+ self.buffer = BUFFER_TYPES[:unbuffered].new
49
58
  elsif size == 0 && buffer == :buffered
50
- @buffer = BUFFER_TYPES[:unbuffered].new
59
+ self.buffer = BUFFER_TYPES[:unbuffered].new
51
60
  elsif buffer == :unbuffered
52
- @buffer = BUFFER_TYPES[:unbuffered].new
61
+ self.buffer = BUFFER_TYPES[:unbuffered].new
53
62
  elsif size.nil? || size < 1
54
63
  raise ArgumentError.new('size must be at least 1 for this buffer type')
55
64
  else
56
65
  buffer ||= :buffered
57
- @buffer = BUFFER_TYPES[buffer].new(size)
66
+ self.buffer = BUFFER_TYPES[buffer].new(size)
58
67
  end
59
68
 
60
- @validator = opts.fetch(:validator, DEFAULT_VALIDATOR)
61
- end
62
-
63
- def size
64
- @buffer.size
69
+ self.validator = opts.fetch(:validator, DEFAULT_VALIDATOR)
65
70
  end
66
- alias_method :capacity, :size
67
71
 
68
72
  def put(item)
69
73
  return false unless validate(item, false, false)
@@ -129,22 +133,21 @@ module Concurrent
129
133
  item
130
134
  end
131
135
 
136
+ # @example
132
137
  #
133
- # @example
138
+ # jobs = Channel.new
134
139
  #
135
- # jobs = Channel.new
136
- #
137
- # Channel.go do
138
- # loop do
139
- # j, more = jobs.next
140
- # if more
141
- # print "received job #{j}\n"
142
- # else
143
- # print "received all jobs\n"
144
- # break
145
- # end
140
+ # Channel.go do
141
+ # loop do
142
+ # j, more = jobs.next
143
+ # if more
144
+ # print "received job #{j}\n"
145
+ # else
146
+ # print "received all jobs\n"
147
+ # break
146
148
  # end
147
149
  # end
150
+ # end
148
151
  def next
149
152
  item, more = do_next
150
153
  item = nil if item == Buffer::NO_VALUE
@@ -191,11 +194,6 @@ module Concurrent
191
194
  end
192
195
  end
193
196
 
194
- def close
195
- @buffer.close
196
- end
197
- alias_method :stop, :close
198
-
199
197
  class << self
200
198
  def timer(seconds)
201
199
  Channel.new(Buffer::Timer.new(seconds))
@@ -240,10 +238,12 @@ module Concurrent
240
238
 
241
239
  private
242
240
 
241
+ attr_accessor :buffer, :validator
242
+
243
243
  def validate(value, allow_nil, raise_error)
244
244
  if !allow_nil && value.nil?
245
245
  raise_error ? raise(ValidationError.new('nil is not a valid value')) : false
246
- elsif !@validator.call(value)
246
+ elsif !validator.call(value)
247
247
  raise_error ? raise(ValidationError) : false
248
248
  else
249
249
  true
@@ -254,19 +254,19 @@ module Concurrent
254
254
  end
255
255
 
256
256
  def do_put(item)
257
- @buffer.put(item)
257
+ buffer.put(item)
258
258
  end
259
259
 
260
260
  def do_offer(item)
261
- @buffer.offer(item)
261
+ buffer.offer(item)
262
262
  end
263
263
 
264
264
  def do_next
265
- @buffer.next
265
+ buffer.next
266
266
  end
267
267
 
268
268
  def do_poll
269
- @buffer.poll
269
+ buffer.poll
270
270
  end
271
271
  end
272
272
  end
@@ -20,19 +20,26 @@ module Concurrent
20
20
 
21
21
  # @!macro [attach] channel_buffer_size_reader
22
22
  #
23
+ # The number of items currently in the buffer.
24
+ attr_reader :size
25
+
26
+ # @!macro [attach] channel_buffer_capacity_reader
27
+ #
23
28
  # The maximum number of values which can be {#put} onto the buffer
24
29
  # it becomes full.
25
- attr_reader :size
26
- alias_method :capacity, :size
30
+ attr_reader :capacity
27
31
 
28
32
  # @!macro [attach] channel_buffer_initialize
29
33
  #
30
34
  # Creates a new buffer.
31
- def initialize
35
+ def initialize(*args)
32
36
  super()
33
37
  synchronize do
34
38
  @closed = false
35
39
  @size = 0
40
+ @capacity = 0
41
+ @buffer = nil
42
+ ns_initialize(*args)
36
43
  end
37
44
  end
38
45
 
@@ -187,6 +194,12 @@ module Concurrent
187
194
 
188
195
  private
189
196
 
197
+ attr_accessor :buffer
198
+ attr_writer :closed, :capacity, :size
199
+
200
+ def ns_initialize(*args)
201
+ end
202
+
190
203
  # @!macro channel_buffer_closed_question
191
204
  def ns_closed?
192
205
  @closed
@@ -10,20 +10,6 @@ module Concurrent
10
10
  # an item is removed from the buffer, creating spare capacity.
11
11
  class Buffered < Base
12
12
 
13
- # @!macro channel_buffer_initialize
14
- #
15
- # @param [Integer] size the maximum capacity of the buffer; must be
16
- # greater than zero.
17
- # @raise [ArgumentError] when the size is zero (0) or less.
18
- def initialize(size)
19
- raise ArgumentError.new('size must be greater than 0') if size.to_i <= 0
20
- super()
21
- synchronize do
22
- @size = size.to_i
23
- @buffer = []
24
- end
25
- end
26
-
27
13
  # @!macro channel_buffer_empty_question
28
14
  def empty?
29
15
  synchronize { ns_empty? }
@@ -85,7 +71,7 @@ module Concurrent
85
71
  if ns_closed? && ns_empty?
86
72
  return NO_VALUE, false
87
73
  elsif !ns_empty?
88
- item = @buffer.shift
74
+ item = buffer.shift
89
75
  more = !ns_empty? || !ns_closed?
90
76
  return item, more
91
77
  end
@@ -100,26 +86,37 @@ module Concurrent
100
86
  if ns_empty?
101
87
  NO_VALUE
102
88
  else
103
- @buffer.shift
89
+ buffer.shift
104
90
  end
105
91
  end
106
92
  end
107
93
 
108
94
  private
109
95
 
96
+ # @!macro channel_buffer_initialize
97
+ #
98
+ # @param [Integer] size the maximum capacity of the buffer; must be
99
+ # greater than zero.
100
+ # @raise [ArgumentError] when the size is zero (0) or less.
101
+ def ns_initialize(size)
102
+ raise ArgumentError.new('size must be greater than 0') if size.to_i <= 0
103
+ self.capacity = size.to_i
104
+ self.buffer = []
105
+ end
106
+
110
107
  # @!macro channel_buffer_empty_question
111
108
  def ns_empty?
112
- @buffer.length == 0
109
+ buffer.length == 0
113
110
  end
114
111
 
115
112
  # @!macro channel_buffer_full_question
116
113
  def ns_full?
117
- @buffer.length == @size
114
+ buffer.length == capacity
118
115
  end
119
116
 
120
117
  # @!macro channel_buffer_put
121
118
  def ns_put_onto_buffer(item)
122
- @buffer.push(item)
119
+ buffer.push(item)
123
120
  end
124
121
  end
125
122
  end
@@ -45,7 +45,7 @@ module Concurrent
45
45
 
46
46
  # @!macro channel_buffer_put
47
47
  def ns_put_onto_buffer(item)
48
- @buffer.push(item) unless @buffer.size == size
48
+ buffer.push(item) unless buffer.size == capacity
49
49
  end
50
50
  end
51
51
  end
@@ -45,8 +45,8 @@ module Concurrent
45
45
 
46
46
  # @!macro channel_buffer_put
47
47
  def ns_put_onto_buffer(item)
48
- @buffer.shift if @buffer.size == size
49
- @buffer.push(item)
48
+ buffer.shift if buffer.size == capacity
49
+ buffer.push(item)
50
50
  end
51
51
  end
52
52
  end
@@ -8,14 +8,6 @@ module Concurrent
8
8
 
9
9
  class Ticker < Base
10
10
 
11
- def initialize(interval)
12
- super()
13
- synchronize do
14
- @interval = interval.to_f
15
- @next_tick = Concurrent.monotonic_time + interval
16
- end
17
- end
18
-
19
11
  def size() 1; end
20
12
 
21
13
  def empty?() false; end
@@ -63,6 +55,11 @@ module Concurrent
63
55
 
64
56
  private
65
57
 
58
+ def ns_initialize(interval)
59
+ @interval = interval.to_f
60
+ @next_tick = Concurrent.monotonic_time + interval
61
+ end
62
+
66
63
  def do_poll
67
64
  if ns_closed?
68
65
  return nil, false
@@ -8,15 +8,6 @@ module Concurrent
8
8
 
9
9
  class Timer < Base
10
10
 
11
- def initialize(delay)
12
- super()
13
- synchronize do
14
- @tick = Concurrent.monotonic_time + delay.to_f
15
- @closed = false
16
- @empty = false
17
- end
18
- end
19
-
20
11
  def size() 1; end
21
12
 
22
13
  def empty?
@@ -59,13 +50,18 @@ module Concurrent
59
50
 
60
51
  private
61
52
 
53
+ def ns_initialize(delay)
54
+ @tick = Concurrent.monotonic_time + delay.to_f
55
+ @closed = false
56
+ @empty = false
57
+ end
58
+
62
59
  def do_poll
63
60
  synchronize do
64
61
  return :closed, false if ns_closed?
65
62
 
66
63
  if Concurrent.monotonic_time > @tick
67
64
  # only one listener gets notified
68
- @closed = @empty = true
69
65
  return :tick, Concurrent::Channel::Tick.new(@tick)
70
66
  else
71
67
  return :wait, true
@@ -15,19 +15,8 @@ module Concurrent
15
15
  # and the first blocked call will return.
16
16
  class Unbuffered < Base
17
17
 
18
- # @!macro channel_buffer_initialize
19
- def initialize
20
- super
21
- synchronize do
22
- # one will always be empty
23
- @putting = []
24
- @taking = []
25
- @closed = false
26
- end
27
- end
28
-
29
18
  # @!macro channel_buffer_size_reader
30
- #
19
+ #
31
20
  # Always returns zero (0).
32
21
  def size() 0; end
33
22
 
@@ -54,11 +43,11 @@ module Concurrent
54
43
  return false if ns_closed?
55
44
 
56
45
  ref = Concurrent::AtomicReference.new(item)
57
- if @taking.empty?
58
- @putting.push(ref)
46
+ if taking.empty?
47
+ putting.push(ref)
59
48
  else
60
- taking = @taking.shift
61
- taking.value = item
49
+ taken = taking.shift
50
+ taken.value = item
62
51
  ref.value = nil
63
52
  end
64
53
  ref
@@ -78,10 +67,10 @@ module Concurrent
78
67
  # buffer is closed, this method will return `false` immediately.
79
68
  def offer(item)
80
69
  synchronize do
81
- return false if ns_closed? || @taking.empty?
70
+ return false if ns_closed? || taking.empty?
82
71
 
83
- taking = @taking.shift
84
- taking.value = item
72
+ taken = taking.shift
73
+ taken.value = item
85
74
  true
86
75
  end
87
76
  end
@@ -96,15 +85,15 @@ module Concurrent
96
85
  # and this method will return.
97
86
  def take
98
87
  mine = synchronize do
99
- return NO_VALUE if ns_closed? && @putting.empty?
88
+ return NO_VALUE if ns_closed? && putting.empty?
100
89
 
101
90
  ref = Concurrent::AtomicReference.new(nil)
102
- if @putting.empty?
103
- @taking.push(ref)
91
+ if putting.empty?
92
+ taking.push(ref)
104
93
  else
105
- putting = @putting.shift
106
- ref.value = putting.value
107
- putting.value = nil
94
+ put = putting.shift
95
+ ref.value = put.value
96
+ put.value = nil
108
97
  end
109
98
  ref
110
99
  end
@@ -124,11 +113,11 @@ module Concurrent
124
113
  # buffer is closed, this method will return `NO_VALUE` immediately.
125
114
  def poll
126
115
  synchronize do
127
- return NO_VALUE if @putting.empty?
116
+ return NO_VALUE if putting.empty?
128
117
 
129
- putting = @putting.shift
130
- value = putting.value
131
- putting.value = nil
118
+ put = putting.shift
119
+ value = put.value
120
+ put.value = nil
132
121
  value
133
122
  end
134
123
  end
@@ -142,9 +131,22 @@ module Concurrent
142
131
  # @see {#take}
143
132
  def next
144
133
  item = take
145
- more = synchronize { !@putting.empty? }
134
+ more = synchronize { !putting.empty? }
146
135
  return item, more
147
136
  end
137
+
138
+ private
139
+
140
+ attr_accessor :putting, :taking
141
+
142
+ # @!macro channel_buffer_initialize
143
+ def ns_initialize
144
+ # one will always be empty
145
+ self.putting = []
146
+ self.taking = []
147
+ self.closed = false
148
+ self.capacity = 1
149
+ end
148
150
  end
149
151
  end
150
152
  end
@@ -11,7 +11,7 @@ module Concurrent
11
11
  # @api Edge
12
12
  class AtomicMarkableReference < ::Concurrent::Synchronization::Object
13
13
 
14
- private *attr_volatile_with_cas(:reference)
14
+ private(*attr_volatile_with_cas(:reference))
15
15
 
16
16
  # @!macro [attach] atomic_markable_reference_method_initialize
17
17
  def initialize(value = nil, mark = false)
@@ -132,6 +132,7 @@ module Concurrent
132
132
  class Event < Synchronization::LockableObject
133
133
  safe_initialization!
134
134
  include Concern::Deprecation
135
+ include Concern::Logging
135
136
 
136
137
  # @!visibility private
137
138
  class State
@@ -885,6 +886,7 @@ module Concurrent
885
886
  # @!visibility private
886
887
  class AbstractPromise < Synchronization::Object
887
888
  safe_initialization!
889
+ include Concern::Logging
888
890
 
889
891
  def initialize(future)
890
892
  super()
@@ -925,7 +927,10 @@ module Concurrent
925
927
  # @return [Future]
926
928
  def evaluate_to(*args, block)
927
929
  complete_with Future::Success.new(block.call(*args))
928
- rescue => error
930
+ rescue StandardError => error
931
+ complete_with Future::Failed.new(error)
932
+ rescue Exception => error
933
+ log(ERROR, 'Edge::Future', error)
929
934
  complete_with Future::Failed.new(error)
930
935
  end
931
936
  end
@@ -112,7 +112,7 @@ module Concurrent
112
112
  removed = curr.successor_reference.compare_and_set succ, succ, false, true
113
113
 
114
114
  #next_node unless removed
115
- continue unless removed
115
+ next unless removed
116
116
 
117
117
  pred.successor_reference.compare_and_set curr, succ, false, false
118
118
 
@@ -23,7 +23,7 @@ module Concurrent
23
23
 
24
24
  EMPTY = Empty[nil, nil]
25
25
 
26
- private *attr_volatile_with_cas(:head)
26
+ private(*attr_volatile_with_cas(:head))
27
27
 
28
28
  def initialize
29
29
  super(EMPTY)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: concurrent-ruby-edge
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0.pre3
4
+ version: 0.2.0.pre4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jerry D'Antonio
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2015-09-29 00:00:00.000000000 Z
13
+ date: 2015-10-08 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: concurrent-ruby
@@ -18,14 +18,14 @@ dependencies:
18
18
  requirements:
19
19
  - - "~>"
20
20
  - !ruby/object:Gem::Version
21
- version: 1.0.0.pre3
21
+ version: 1.0.0.pre4
22
22
  type: :runtime
23
23
  prerelease: false
24
24
  version_requirements: !ruby/object:Gem::Requirement
25
25
  requirements:
26
26
  - - "~>"
27
27
  - !ruby/object:Gem::Version
28
- version: 1.0.0.pre3
28
+ version: 1.0.0.pre4
29
29
  description: |
30
30
  These features are under active development and may change frequently. They are expected not to
31
31
  keep backward compatibility (there may also lack tests and documentation). Semantic versions will