async_resource_pool 0.1.0 → 0.2.0

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: 75133743aeaeab2c6bee303c2d2497055d9d5563e7b4ccebb3bf6cae0660fe13
4
- data.tar.gz: 247147e3ce15590265ac8b9a55d82008c4f031a7d503748e727263b8734384e4
3
+ metadata.gz: 33a430430c05e8d4c974bd33e7ddef4c5c312135837374b0ed5610421347eee4
4
+ data.tar.gz: 8bd7329c95eb067c6338930dfcf577aca8e0738c315c2bc902bb2e8883397812
5
5
  SHA512:
6
- metadata.gz: 5aa8a66212a37bf79160fbcf29f6ca523180512a3a9de16f058db725514aaf2c3dab8ed40605787ccc407feb26c44e90df77b7f079bf8e2ffa36412a44098383
7
- data.tar.gz: 5d844e30908ce0c0a448ab0cc33eb7238acd5079defe643a644544896aab7c004ed662ca969f29198834d87a5976e79c8f4e1425d7b4e73fb89834151b154461
6
+ metadata.gz: 8b54fe315d31d27ea0761ebf54779e4c651ab82386a90b818534b6ae6d08f9d16b9fd5e38fc000326dc81cbbab6ef04719c3deffcde74fa179c9e3bf419ac883
7
+ data.tar.gz: 0c71b6f55af4b0b436ec4b5f7ba227d2d55761922af1249d6075403715697c2628e3bbef06f99562e4502472bc5740b5fc52469bcfc1f8fc194db28588bda595
@@ -10,14 +10,7 @@ rvm:
10
10
  - 2.3
11
11
  - 2.4
12
12
  - 2.5
13
- - jruby-head
14
- - ruby-head
15
- - rbx-3
16
- matrix:
17
- allow_failures:
18
- - rvm: ruby-head
19
- - rvm: jruby-head
20
- - rvm: rbx-3
13
+ - 2.6
21
14
  before_install:
22
15
  - gem update --system
23
- - gem install bundler -v 2.0.1
16
+ - gem install bundler -v 1.7.13
data/README.md CHANGED
@@ -1,5 +1,6 @@
1
1
  # AsyncResourcePool
2
2
 
3
+ [![Gem Version](https://badge.fury.io/rb/async_resource_pool.svg)](https://rubygems.org/gems/async_resource_pool)
3
4
  [![Build Status](https://travis-ci.com/senid231/async_resource_pool.svg?branch=master)](https://travis-ci.com/senid231/async_resource_pool)
4
5
 
5
6
  TODO:
@@ -1,10 +1,11 @@
1
1
 
2
2
  lib = File.expand_path('../lib', __FILE__)
3
3
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'async/resource_pool/version'
4
5
 
5
6
  Gem::Specification.new do |spec|
6
7
  spec.name = 'async_resource_pool'
7
- spec.version = '0.1.0'
8
+ spec.version = Async::ResourcePool::VERSION
8
9
  spec.authors = ['Denis Talakevich']
9
10
  spec.email = ['senid231@gmail.com']
10
11
 
@@ -1,105 +1,8 @@
1
1
  require 'async'
2
+ require 'async/resource_pool/version'
3
+ require 'async/resource_pool/simple'
2
4
 
3
5
  module Async
4
- class ResourcePool
5
- VERSION = '0.1.0'
6
-
7
- class Error < StandardError
8
- end
9
-
10
- class DoesNotOwnError < Error
11
- def initialize
12
- super('current fiber does not own this resource')
13
- end
14
- end
15
-
16
- class AlreadyOwnError < Error
17
- def initialize
18
- super('current fiber already own this resource')
19
- end
20
- end
21
-
22
- class TimeoutError < Error
23
- def initialize(timeout)
24
- super("timeout #{timeout} seconds was elapsed")
25
- end
26
- end
27
-
28
- def initialize(limit)
29
- @limit = limit
30
- @owners = []
31
- @waiters = []
32
- end
33
-
34
- def acquire(timeout = nil)
35
- raise AlreadyOwnError.new if already_acquired?
36
-
37
- unless can_be_acquired?
38
- timeout.nil? ? wait : wait_with_timeout(timeout)
39
- end
40
-
41
- @owners.push(Fiber.current)
42
-
43
- if block_given?
44
- begin
45
- yield
46
- ensure
47
- release
48
- end
49
- end
50
-
51
- nil
52
- end
53
-
54
- def release
55
- raise DoesNotOwnError.new unless already_acquired?
56
- @owners.delete(Fiber.current)
57
- wakeup
58
- end
59
-
60
- def already_acquired?
61
- @owners.include?(Fiber.current)
62
- end
63
-
64
- def can_be_acquired?
65
- @owners.size < @limit
66
- end
67
-
68
- def info
69
- {
70
- waiters: @waiters.size,
71
- owners: @owners.size,
72
- limit: @limit
73
- }
74
- end
75
-
76
- private
77
-
78
- def wakeup
79
- return if @waiters.empty?
80
- fiber = @waiters.shift
81
- fiber.resume if fiber.alive?
82
- end
83
-
84
- def wait
85
- @waiters.push(Fiber.current)
86
- Async::Task.yield
87
- end
88
-
89
- def wait_with_timeout(timeout)
90
- fiber = Fiber.current
91
- @waiters.push(Fiber.current)
92
-
93
- Async::Task.current.with_timeout(timeout) do |timer|
94
- begin
95
- Async::Task.yield
96
- timer.cancel
97
- rescue Async::TimeoutError => _
98
- @waiters.delete(fiber)
99
- raise TimeoutError.new(timeout)
100
- end
101
- end
102
- end
103
-
6
+ module ResourcePool
104
7
  end
105
8
  end
@@ -0,0 +1,26 @@
1
+ module Async
2
+ module ResourcePool
3
+
4
+ class Error < StandardError
5
+ end
6
+
7
+ class DoesNotOwnError < Error
8
+ def initialize
9
+ super('current fiber does not own this resource')
10
+ end
11
+ end
12
+
13
+ class AlreadyOwnError < Error
14
+ def initialize
15
+ super('current fiber already own this resource')
16
+ end
17
+ end
18
+
19
+ class TimeoutError < Error
20
+ def initialize(timeout)
21
+ super("timeout #{timeout} seconds was elapsed")
22
+ end
23
+ end
24
+
25
+ end
26
+ end
@@ -0,0 +1,145 @@
1
+ require 'thread'
2
+ require_relative 'errors'
3
+
4
+ module Async
5
+ module ResourcePool
6
+ class Simple
7
+
8
+ # @param limit [Integer] - max number of acquired resources, must be greater then 0.
9
+ # @param wakeup_strategy [Symbol] - can be :immediately or :next_loop.
10
+ def initialize(limit, wakeup_strategy = :immediately)
11
+ raise ArgumentError, 'limit must be greater than 0' if limit <= 0
12
+ unless [:immediately, :next_loop].include?(wakeup_strategy)
13
+ raise ArgumentError, 'wakeup_strategy must be :immediately or :next_loop'
14
+ end
15
+
16
+ @limit = limit
17
+ @wakeup_strategy = wakeup_strategy
18
+ @owners = []
19
+ @waiters = []
20
+ @thread_mutex = Mutex.new
21
+ end
22
+
23
+ # Acquires resource for current fiber if available otherwise yield to reactor.
24
+ # Will be resumed once resource available.
25
+ # Will raise Async::ResourcePool::TimeoutError if timeout not nil and resource isn't available after timeout.
26
+ # Will raise Async::ResourcePool::AlreadyOwnError if resource already acquired.
27
+ # @param timeout [Integer|Float] - timeout in seconds (default nil).
28
+ def acquire(timeout = nil)
29
+ raise Async::ResourcePool::AlreadyOwnError.new if already_acquired?
30
+
31
+ unless acquire_if_available
32
+ timeout.nil? ? Async::Task.yield : wait_with_timeout(timeout)
33
+ @thread_mutex.synchronize { @owners.push(Fiber.current) }
34
+ end
35
+
36
+ if block_given?
37
+ begin
38
+ yield
39
+ ensure
40
+ release
41
+ end
42
+ end
43
+
44
+ nil
45
+ end
46
+
47
+ # Acquires resource for current fiber if resource available.
48
+ # Will raise Async::ResourcePool::AlreadyOwnError if resource already acquired.
49
+ # @return [True|False] returns true if resource was acquired.
50
+ def try_acquire
51
+ raise Async::ResourcePool::AlreadyOwnError.new if already_acquired?
52
+
53
+ if acquire_if_available
54
+ true
55
+ else
56
+ @waiters.delete(Fiber.current)
57
+ false
58
+ end
59
+ end
60
+
61
+ # Releases resource for current fiber.
62
+ # Will resume first fiber that waits for resource immediately if wakeup_strategy == :immediately
63
+ # Will resume first fiber that waits for resource in next reactor loop if wakeup_strategy == :next_loop
64
+ # Will raise Async::ResourcePool::DoesNotOwnError if fiber does not own resource.
65
+ def release
66
+ raise Async::ResourcePool::DoesNotOwnError.new unless already_acquired?
67
+ @owners.delete(Fiber.current)
68
+ wakeup
69
+ end
70
+
71
+ # @return [True|False] returns true if resource already acquired by fiber
72
+ def already_acquired?
73
+ @owners.include?(Fiber.current)
74
+ end
75
+
76
+ # @return [True|False] returns true if pool has available resource
77
+ def can_be_acquired?
78
+ @owners.size < @limit
79
+ end
80
+
81
+ # @return [Hash] represents current state of resource pool.
82
+ # waiters - how many fibers waits for resource.
83
+ # owners - how many fibers own resource.
84
+ # limit - maximum of resources that can be owned simultaneously.
85
+ def info
86
+ {
87
+ waiters: @waiters.size,
88
+ owners: @owners.size,
89
+ limit: @limit
90
+ }
91
+ end
92
+
93
+ private
94
+
95
+ def wakeup
96
+ return if @waiters.empty?
97
+ fiber = @waiters.shift
98
+ return unless fiber.alive?
99
+
100
+ if @wakeup_strategy == :immediately
101
+ fiber.resume
102
+ else
103
+ Async::Task.current.reactor << fiber
104
+ end
105
+ end
106
+
107
+ def wakeup_fiber(fiber)
108
+ if @wakeup_strategy == :immediately
109
+ fiber.resume
110
+ else
111
+ Async::Task.current.reactor << fiber
112
+ end
113
+ end
114
+
115
+ def acquire_if_available
116
+ fiber = Fiber.current
117
+
118
+ @thread_mutex.synchronize do
119
+ if can_be_acquired?
120
+ @owners.push(fiber)
121
+ true
122
+ else
123
+ @waiters.push(fiber)
124
+ false
125
+ end
126
+ end
127
+ end
128
+
129
+ def wait_with_timeout(timeout)
130
+ fiber = Fiber.current
131
+
132
+ Async::Task.current.with_timeout(timeout) do |timer|
133
+ begin
134
+ Async::Task.yield
135
+ timer.cancel
136
+ rescue Async::TimeoutError => _
137
+ @waiters.delete(fiber)
138
+ raise Async::ResourcePool::TimeoutError.new(timeout)
139
+ end
140
+ end
141
+ end
142
+
143
+ end
144
+ end
145
+ end
@@ -0,0 +1,5 @@
1
+ module Async
2
+ module ResourcePool
3
+ VERSION = '0.2.0'
4
+ end
5
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: async_resource_pool
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Denis Talakevich
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-03-13 00:00:00.000000000 Z
11
+ date: 2019-03-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: async
@@ -85,6 +85,9 @@ files:
85
85
  - bin/console
86
86
  - bin/setup
87
87
  - lib/async/resource_pool.rb
88
+ - lib/async/resource_pool/errors.rb
89
+ - lib/async/resource_pool/simple.rb
90
+ - lib/async/resource_pool/version.rb
88
91
  - lib/async_resource_pool.rb
89
92
  homepage: https://github.com/senid231/async_resource_pool
90
93
  licenses: