async-pool 0.3.3 → 0.3.4

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: 91d47d29e5bb2e6a93668145c06b432ee26393019cb253d284ffb48cf2c8285b
4
- data.tar.gz: 3b3d98e86aec3e783fa5ed98eb803d0f8efe382c0f4b32d518779c09ca736c2d
3
+ metadata.gz: 53496ca8f02b057c94d8cef37e92f7d14bb3d7062267ea53f363d5ca3c2ee7d4
4
+ data.tar.gz: b59bb3a498bb16b1306eea4b6bcb765efa60a479701f546a3c2b6785ff5203e1
5
5
  SHA512:
6
- metadata.gz: 34260d06050fe9829ddd40c2a29444548707661262e34df4bd956f3f1a37dd34ab7f6a59cb78ae1acc7388951ec3777b52beff1fa8e2bf6426ad46214e724d21
7
- data.tar.gz: f82218caa4733fec59c17ef9aff190e1617aee3049a16629ecfbc15b0c7e6618f1176f9f2bb26e2e67db0388b5f5dc7f164add84efd09f9e49c0776bb36a690d
6
+ metadata.gz: f53063512c044675725eed75b72346644a36c99704bf2f1559692420f7176b88063cb79200d4a24f19f8cd081be224e307a811d91dc8a94923cccb87cf850cc4
7
+ data.tar.gz: 366355082c92722989dd76607f611fd81f520844b8733e15872db4164a146bc2e257e40f316bc87c173a49b65d465e07cccdf459fea242b9c8445841c13f7580
@@ -32,9 +32,13 @@ module Async
32
32
  end
33
33
 
34
34
  def initialize(constructor, limit: nil)
35
+ # All available resources:
35
36
  @resources = {}
36
37
 
38
+ # Resources which may be available to be acquired:
39
+ # This list may contain false positives, or resources which were okay but have since entered a state which is unusuable.
37
40
  @available = []
41
+
38
42
  @notification = Async::Notification.new
39
43
 
40
44
  @limit = limit
@@ -45,7 +49,7 @@ module Async
45
49
  @gardener = nil
46
50
  end
47
51
 
48
- # @attr [Hash<Resource, Integer>] all allocated resources, and their associated usage.
52
+ # @attribute [Hash(Resource, Integer)] all allocated resources, and their associated usage.
49
53
  attr :resources
50
54
 
51
55
  def size
@@ -66,6 +70,11 @@ module Async
66
70
  return false
67
71
  end
68
72
 
73
+ # Whether there are available resources, i.e. whether {#acquire} can reuse an existing resource.
74
+ def available?
75
+ @available.any?
76
+ end
77
+
69
78
  # Wait until a pool resource has been freed.
70
79
  def wait
71
80
  @notification.wait
@@ -119,7 +128,9 @@ module Async
119
128
  unused = []
120
129
 
121
130
  @resources.each do |resource, usage|
122
- unused << resource if usage.zero?
131
+ if usage.zero?
132
+ unused << resource
133
+ end
123
134
  end
124
135
 
125
136
  unused.each do |resource|
@@ -132,6 +143,14 @@ module Async
132
143
  break if @resources.size <= retain
133
144
  end
134
145
 
146
+ # Update availability list:
147
+ @available.clear
148
+ @resources.each do |resource, usage|
149
+ if usage < resource.concurrency and resource.reusable?
150
+ @available << resource
151
+ end
152
+ end
153
+
135
154
  return unused.size
136
155
  end
137
156
 
@@ -170,11 +189,42 @@ module Async
170
189
  end.join(";")
171
190
  end
172
191
 
192
+ def usage
193
+ @resources.count{|resource, usage| usage > 0}
194
+ end
195
+
196
+ def free
197
+ @resources.count{|resource, usage| usage == 0}
198
+ end
199
+
200
+ # @returns [Boolean] Whether the number of available resources is excessive and we should retire some.
201
+ def overflowing?
202
+ if @resources.any?
203
+ (self.free.to_f / @resources.size) > 0.5
204
+ end
205
+ end
206
+
173
207
  def reuse(resource)
174
208
  Async.logger.debug(self) {"Reuse #{resource}"}
209
+ usage = @resources[resource]
210
+
211
+ if usage.zero?
212
+ raise "Trying to reuse unacquired resource: #{resource}!"
213
+ end
214
+
215
+ # We retire resources when adding to the @available list would overflow our pool:
216
+ if usage == 1
217
+ if overflowing?
218
+ return retire(resource)
219
+ end
220
+ end
221
+
222
+ # If the resource was fully utilized, it now becomes available:
223
+ if usage == resource.concurrency
224
+ @available.push(resource)
225
+ end
175
226
 
176
- @resources[resource] -= 1
177
- @available.push(resource)
227
+ @resources[resource] = usage - 1
178
228
 
179
229
  @notification.signal
180
230
  end
@@ -194,6 +244,7 @@ module Async
194
244
  return resource
195
245
  end
196
246
 
247
+ # @returns [Object] A new resource in a "used" state.
197
248
  def create_resource
198
249
  self.start_gardener
199
250
 
@@ -201,18 +252,27 @@ module Async
201
252
  if resource = @constructor.call
202
253
  @resources[resource] = 1
203
254
 
204
- @available.push(resource) if resource.concurrency > 1
255
+ # Make the resource available if it can be used multiple times:
256
+ if resource.concurrency > 1
257
+ @available.push(resource)
258
+ end
205
259
  end
206
260
 
207
261
  return resource
208
262
  end
209
263
 
264
+ # @returns [Object] An existing resource in a "used" state.
210
265
  def available_resource
211
266
  @guard.acquire do
212
267
  while resource = @available.last
213
268
  if usage = @resources[resource] and usage < resource.concurrency
214
269
  if resource.viable?
215
- @resources[resource] += 1
270
+ usage = (@resources[resource] += 1)
271
+
272
+ if usage == resource.concurrency
273
+ # The resource is used up to it's limit:
274
+ @available.pop
275
+ end
216
276
 
217
277
  return resource
218
278
  else
@@ -220,6 +280,7 @@ module Async
220
280
  @available.pop
221
281
  end
222
282
  else
283
+ # The resource has been removed already, so skip it and remove it from the availability list.
223
284
  @available.pop
224
285
  end
225
286
  end
@@ -20,6 +20,6 @@
20
20
 
21
21
  module Async
22
22
  module Pool
23
- VERSION = "0.3.3"
23
+ VERSION = "0.3.4"
24
24
  end
25
25
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: async-pool
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.3
4
+ version: 0.3.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-11-15 00:00:00.000000000 Z
11
+ date: 2021-02-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: async