vault 0.18.1 → 0.19.0

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.
@@ -1,181 +0,0 @@
1
- # Copyright (c) HashiCorp, Inc.
2
- # SPDX-License-Identifier: MPL-2.0
3
-
4
- require 'thread'
5
- require 'timeout'
6
-
7
- module Vault; end
8
-
9
- ##
10
- # Raised when you attempt to retrieve a connection from a pool that has been
11
- # shut down.
12
-
13
- class Vault::ConnectionPool::PoolShuttingDownError < RuntimeError; end
14
-
15
- ##
16
- # The TimedStack manages a pool of homogeneous connections (or any resource
17
- # you wish to manage). Connections are created lazily up to a given maximum
18
- # number.
19
-
20
- # Examples:
21
- #
22
- # ts = TimedStack.new(1) { MyConnection.new }
23
- #
24
- # # fetch a connection
25
- # conn = ts.pop
26
- #
27
- # # return a connection
28
- # ts.push conn
29
- #
30
- # conn = ts.pop
31
- # ts.pop timeout: 5
32
- # #=> raises Timeout::Error after 5 seconds
33
-
34
- module Vault
35
- class ConnectionPool::TimedStack
36
-
37
- ##
38
- # Creates a new pool with +size+ connections that are created from the given
39
- # +block+.
40
-
41
- def initialize(size = 0, &block)
42
- @create_block = block
43
- @created = 0
44
- @que = []
45
- @max = size
46
- @mutex = Mutex.new
47
- @resource = ConditionVariable.new
48
- @shutdown_block = nil
49
- end
50
-
51
- ##
52
- # Returns +obj+ to the stack. +options+ is ignored in TimedStack but may be
53
- # used by subclasses that extend TimedStack.
54
-
55
- def push(obj, options = {})
56
- @mutex.synchronize do
57
- if @shutdown_block
58
- @shutdown_block.call(obj)
59
- else
60
- store_connection obj, options
61
- end
62
-
63
- @resource.broadcast
64
- end
65
- end
66
- alias_method :<<, :push
67
-
68
- ##
69
- # Retrieves a connection from the stack. If a connection is available it is
70
- # immediately returned. If no connection is available within the given
71
- # timeout a Timeout::Error is raised.
72
- #
73
- # +:timeout+ is the only checked entry in +options+ and is preferred over
74
- # the +timeout+ argument (which will be removed in a future release). Other
75
- # options may be used by subclasses that extend TimedStack.
76
-
77
- def pop(timeout = 0.5, options = {})
78
- options, timeout = timeout, 0.5 if Hash === timeout
79
- timeout = options.fetch :timeout, timeout
80
-
81
- deadline = Time.now + timeout
82
- @mutex.synchronize do
83
- loop do
84
- raise ConnectionPool::PoolShuttingDownError if @shutdown_block
85
- return fetch_connection(options) if connection_stored?(options)
86
-
87
- connection = try_create(options)
88
- return connection if connection
89
-
90
- to_wait = deadline - Time.now
91
- raise Timeout::Error, "Waited #{timeout} sec" if to_wait <= 0
92
- @resource.wait(@mutex, to_wait)
93
- end
94
- end
95
- end
96
-
97
- ##
98
- # Shuts down the TimedStack which prevents connections from being checked
99
- # out. The +block+ is called once for each connection on the stack.
100
-
101
- def shutdown(&block)
102
- raise ArgumentError, "shutdown must receive a block" unless block_given?
103
-
104
- @mutex.synchronize do
105
- @shutdown_block = block
106
- @resource.broadcast
107
-
108
- shutdown_connections
109
- end
110
- end
111
-
112
- ##
113
- # Returns +true+ if there are no available connections.
114
-
115
- def empty?
116
- (@created - @que.length) >= @max
117
- end
118
-
119
- ##
120
- # The number of connections available on the stack.
121
-
122
- def length
123
- @max - @created + @que.length
124
- end
125
-
126
- private
127
-
128
- ##
129
- # This is an extension point for TimedStack and is called with a mutex.
130
- #
131
- # This method must returns true if a connection is available on the stack.
132
-
133
- def connection_stored?(options = nil)
134
- !@que.empty?
135
- end
136
-
137
- ##
138
- # This is an extension point for TimedStack and is called with a mutex.
139
- #
140
- # This method must return a connection from the stack.
141
-
142
- def fetch_connection(options = nil)
143
- @que.pop
144
- end
145
-
146
- ##
147
- # This is an extension point for TimedStack and is called with a mutex.
148
- #
149
- # This method must shut down all connections on the stack.
150
-
151
- def shutdown_connections(options = nil)
152
- while connection_stored?(options)
153
- conn = fetch_connection(options)
154
- @shutdown_block.call(conn)
155
- end
156
- end
157
-
158
- ##
159
- # This is an extension point for TimedStack and is called with a mutex.
160
- #
161
- # This method must return +obj+ to the stack.
162
-
163
- def store_connection(obj, options = nil)
164
- @que.push obj
165
- end
166
-
167
- ##
168
- # This is an extension point for TimedStack and is called with a mutex.
169
- #
170
- # This method must create a connection if and only if the total number of
171
- # connections allowed has not been met.
172
-
173
- def try_create(options = nil)
174
- unless @created == @max
175
- object = @create_block.call
176
- @created += 1
177
- object
178
- end
179
- end
180
- end
181
- end
@@ -1,8 +0,0 @@
1
- # Copyright (c) HashiCorp, Inc.
2
- # SPDX-License-Identifier: MPL-2.0
3
-
4
- module Vault
5
- class ConnectionPool
6
- VERSION = "2.2.0"
7
- end
8
- end
@@ -1,153 +0,0 @@
1
- # Copyright (c) HashiCorp, Inc.
2
- # SPDX-License-Identifier: MPL-2.0
3
-
4
- require_relative 'connection_pool/version'
5
- require_relative 'connection_pool/timed_stack'
6
-
7
-
8
- # Generic connection pool class for e.g. sharing a limited number of network connections
9
- # among many threads. Note: Connections are lazily created.
10
- #
11
- # Example usage with block (faster):
12
- #
13
- # @pool = ConnectionPool.new { Redis.new }
14
- #
15
- # @pool.with do |redis|
16
- # redis.lpop('my-list') if redis.llen('my-list') > 0
17
- # end
18
- #
19
- # Using optional timeout override (for that single invocation)
20
- #
21
- # @pool.with(:timeout => 2.0) do |redis|
22
- # redis.lpop('my-list') if redis.llen('my-list') > 0
23
- # end
24
- #
25
- # Example usage replacing an existing connection (slower):
26
- #
27
- # $redis = ConnectionPool.wrap { Redis.new }
28
- #
29
- # def do_work
30
- # $redis.lpop('my-list') if $redis.llen('my-list') > 0
31
- # end
32
- #
33
- # Accepts the following options:
34
- # - :size - number of connections to pool, defaults to 5
35
- # - :timeout - amount of time to wait for a connection if none currently available, defaults to 5 seconds
36
- #
37
- module Vault
38
- class ConnectionPool
39
- DEFAULTS = {size: 5, timeout: 5}
40
-
41
- class Error < RuntimeError
42
- end
43
-
44
- def self.wrap(options, &block)
45
- Wrapper.new(options, &block)
46
- end
47
-
48
- def initialize(options = {}, &block)
49
- raise ArgumentError, 'Connection pool requires a block' unless block
50
-
51
- options = DEFAULTS.merge(options)
52
-
53
- @size = options.fetch(:size)
54
- @timeout = options.fetch(:timeout)
55
-
56
- @available = TimedStack.new(@size, &block)
57
- @key = :"current-#{@available.object_id}"
58
- end
59
-
60
- if Thread.respond_to?(:handle_interrupt)
61
-
62
- # MRI
63
- def with(options = {})
64
- Thread.handle_interrupt(Exception => :never) do
65
- conn = checkout(options)
66
- begin
67
- Thread.handle_interrupt(Exception => :immediate) do
68
- yield conn
69
- end
70
- ensure
71
- checkin
72
- end
73
- end
74
- end
75
-
76
- else
77
-
78
- # jruby 1.7.x
79
- def with(options = {})
80
- conn = checkout(options)
81
- begin
82
- yield conn
83
- ensure
84
- checkin
85
- end
86
- end
87
-
88
- end
89
-
90
- def checkout(options = {})
91
- conn = if stack.empty?
92
- timeout = options[:timeout] || @timeout
93
- @available.pop(timeout: timeout)
94
- else
95
- stack.last
96
- end
97
-
98
- stack.push conn
99
- conn
100
- end
101
-
102
- def checkin
103
- conn = pop_connection # mutates stack, must be on its own line
104
- @available.push(conn) if stack.empty?
105
-
106
- nil
107
- end
108
-
109
- def shutdown(&block)
110
- @available.shutdown(&block)
111
- end
112
-
113
- private
114
-
115
- def pop_connection
116
- if stack.empty?
117
- raise ConnectionPool::Error, 'no connections are checked out'
118
- else
119
- stack.pop
120
- end
121
- end
122
-
123
- def stack
124
- ::Thread.current[@key] ||= []
125
- end
126
-
127
- class Wrapper < ::BasicObject
128
- METHODS = [:with, :pool_shutdown]
129
-
130
- def initialize(options = {}, &block)
131
- @pool = ::ConnectionPool.new(options, &block)
132
- end
133
-
134
- def with(&block)
135
- @pool.with(&block)
136
- end
137
-
138
- def pool_shutdown(&block)
139
- @pool.shutdown(&block)
140
- end
141
-
142
- def respond_to?(id, *args)
143
- METHODS.include?(id) || with { |c| c.respond_to?(id, *args) }
144
- end
145
-
146
- def method_missing(name, *args, &block)
147
- with do |connection|
148
- connection.send(name, *args, &block)
149
- end
150
- end
151
- end
152
- end
153
- end