sequel 5.101.0 → 5.102.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9de2d20e1483de5f15a285b695d5eab98601c26f1e711e378de1a03331f197a1
4
- data.tar.gz: 4d7df1811d7242dad22f6c9968fb43feecb5a86fd814aa2ba7434bdb44369cb8
3
+ metadata.gz: 92eed5c337b361dfde5b948323fb6a0a22ad89ecb2473c284d9e5b70a5eed8e2
4
+ data.tar.gz: dd07fefb9f3d2821479be092a12b87c6e7b92f5d8d8c314ff656741d31e75531
5
5
  SHA512:
6
- metadata.gz: a9aa7a3bd15f4f35457aace92b68b4734d367273996dc605d80adbe87bca1c945fc484571cad90149e69807980eea2f8b2a6a6fea85a4a0670c10a082a056a03
7
- data.tar.gz: ca5c1eb34d71d16660a0b5eb2b9e5b4c784f06d6e4f89b036f00a62f31b57d564f071b8346bdcb9ebd9cced7bcfbe429e2c50bcda1b8b150d723b1e59105c474
6
+ metadata.gz: ea53c48308a031896491a59e57ca3902a9a3478b8d09d12de6548a927991419054fa8698463c18c18cef9801a9c4629dc299b27df03245272bb2296f79ccdc1c
7
+ data.tar.gz: adfd92660e225f0d67948dfdc4aa57c2c61c1118265908f8b6a26fe23179573aff4195aec759575abea984e46fa5d1b62701b75caa8ce7e78838f6434e208527
@@ -71,7 +71,7 @@ class Sequel::ShardedTimedQueueConnectionPool < Sequel::ConnectionPool
71
71
  while true
72
72
  conn = nil
73
73
  begin
74
- break unless (conn = queue.pop(timeout: 0)) && !conns[conn]
74
+ break unless (conn = available(queue, server)) && !conns[conn]
75
75
  conns[conn] = true
76
76
  yield conn
77
77
  ensure
@@ -95,7 +95,7 @@ class Sequel::ShardedTimedQueueConnectionPool < Sequel::ConnectionPool
95
95
  def disconnect(opts=OPTS)
96
96
  (opts[:server] ? Array(opts[:server]) : sync{@servers.keys}).each do |server|
97
97
  raise Sequel::Error, "invalid server" unless queue = sync{@queues[server]}
98
- while conn = queue.pop(timeout: 0)
98
+ while conn = available(queue, server)
99
99
  disconnect_pool_connection(conn, server)
100
100
  end
101
101
  fill_queue(server)
@@ -167,7 +167,7 @@ class Sequel::ShardedTimedQueueConnectionPool < Sequel::ConnectionPool
167
167
 
168
168
  queue = @queues[server]
169
169
 
170
- while conn = queue.pop(timeout: 0)
170
+ while conn = available(queue, server)
171
171
  @sizes[server] -= 1
172
172
  conns << conn
173
173
  end
@@ -225,6 +225,12 @@ class Sequel::ShardedTimedQueueConnectionPool < Sequel::ConnectionPool
225
225
  conns.each{|conn| disconnect_connection(conn)}
226
226
  end
227
227
 
228
+ # Only for use by extension that need to disconnect a connection inside acquire.
229
+ # Takes the connection and any arguments accepted by acquire.
230
+ def disconnect_acquired_connection(conn, _, server)
231
+ disconnect_pool_connection(conn, server)
232
+ end
233
+
228
234
  # Decrement the current size of the pool for the server when disconnecting connections.
229
235
  #
230
236
  # Calling code should not have the mutex when calling this.
@@ -311,7 +317,7 @@ class Sequel::ShardedTimedQueueConnectionPool < Sequel::ConnectionPool
311
317
  # Calling code should not have the mutex when calling this.
312
318
  def acquire(thread, server)
313
319
  queue = sync{@queues[server]}
314
- if conn = queue.pop(timeout: 0) || try_make_new(server) || queue.pop(timeout: @timeout)
320
+ if conn = available(queue, server) || try_make_new(server) || wait_until_available(queue, server)
315
321
  sync{@allocated[server][thread] = conn}
316
322
  else
317
323
  name = db.opts[:name]
@@ -319,6 +325,19 @@ class Sequel::ShardedTimedQueueConnectionPool < Sequel::ConnectionPool
319
325
  end
320
326
  end
321
327
 
328
+ # Return the next connection in the pool if there is one available. Returns nil
329
+ # if no connection is currently available.
330
+ def available(queue, _server)
331
+ queue.pop(timeout: 0)
332
+ end
333
+
334
+ # Return the next connection in the pool if there is one available. If not, wait
335
+ # until the timeout for a connection to become available. If there is still no
336
+ # available connection, return nil.
337
+ def wait_until_available(queue, _server)
338
+ queue.pop(timeout: @timeout)
339
+ end
340
+
322
341
  # Returns the connection owned by the supplied thread for the given server,
323
342
  # if any. The calling code should NOT already have the mutex before calling this.
324
343
  def owned_connection(thread, server)
@@ -42,7 +42,7 @@ class Sequel::TimedQueueConnectionPool < Sequel::ConnectionPool
42
42
  while true
43
43
  conn = nil
44
44
  begin
45
- break unless (conn = @queue.pop(timeout: 0)) && !conns[conn]
45
+ break unless (conn = available) && !conns[conn]
46
46
  conns[conn] = true
47
47
  yield conn
48
48
  ensure
@@ -59,7 +59,7 @@ class Sequel::TimedQueueConnectionPool < Sequel::ConnectionPool
59
59
  # Once a connection is requested using #hold, the connection pool
60
60
  # creates new connections to the database.
61
61
  def disconnect(opts=OPTS)
62
- while conn = @queue.pop(timeout: 0)
62
+ while conn = available
63
63
  disconnect_connection(conn)
64
64
  end
65
65
  fill_queue
@@ -220,7 +220,7 @@ class Sequel::TimedQueueConnectionPool < Sequel::ConnectionPool
220
220
  #
221
221
  # Calling code should not have the mutex when calling this.
222
222
  def acquire(thread)
223
- if conn = @queue.pop(timeout: 0) || try_make_new || @queue.pop(timeout: @timeout)
223
+ if conn = available || try_make_new || wait_until_available
224
224
  sync{@allocated[thread] = conn}
225
225
  else
226
226
  name = db.opts[:name]
@@ -228,6 +228,19 @@ class Sequel::TimedQueueConnectionPool < Sequel::ConnectionPool
228
228
  end
229
229
  end
230
230
 
231
+ # Return the next connection in the pool if there is one available. Returns nil
232
+ # if no connection is currently available.
233
+ def available
234
+ @queue.pop(timeout: 0)
235
+ end
236
+
237
+ # Return the next connection in the pool if there is one available. If not, wait
238
+ # until the timeout for a connection to become available. If there is still no
239
+ # available connection, return nil.
240
+ def wait_until_available
241
+ @queue.pop(timeout: @timeout)
242
+ end
243
+
231
244
  # Returns the connection owned by the supplied thread,
232
245
  # if any. The calling code should NOT already have the mutex before calling this.
233
246
  def owned_connection(thread)
@@ -131,6 +131,12 @@ class Sequel::ConnectionPool
131
131
  db.disconnect_connection(conn)
132
132
  end
133
133
 
134
+ # Only for use by extension that need to disconnect a connection inside acquire.
135
+ # Takes the connection and any arguments accepted by acquire.
136
+ def disconnect_acquired_connection(conn, *)
137
+ disconnect_connection(conn)
138
+ end
139
+
134
140
  # Whether the given exception is a disconnect exception.
135
141
  def disconnect_error?(exception)
136
142
  exception.is_a?(Sequel::DatabaseDisconnectError) || db.send(:disconnect_error?, exception, OPTS)
@@ -0,0 +1,151 @@
1
+ # frozen-string-literal: true
2
+ #
3
+ # The connection_checkout_event_callback extension modifies a database's
4
+ # connection pool to allow for a checkout event callback. This callback is
5
+ # called with the following arguments:
6
+ #
7
+ # :immediately_available :: Connection immediately available and returned
8
+ # :not_immediately_available :: Connection not immediately available
9
+ # :new_connection :: New connection created and returned
10
+ # Float :: Number of seconds waiting to acquire a connection
11
+ #
12
+ # This is a low-level extension that allows for building telemetry
13
+ # information. It doesn't implement any telemetry reporting itself. The
14
+ # main reason for recording this information is to use it to determine the
15
+ # appropriate size for the connection pool. Having too large a connection
16
+ # pool can waste resources, while having too small a connection pool can
17
+ # result in substantial time to check out a connection. In general, you
18
+ # want to use as small a pool as possible while keeping the time to
19
+ # checkout a connection low.
20
+ #
21
+ # To use the connection checkout event callback, you must first load the
22
+ # extension:
23
+ #
24
+ # DB.extension(:connection_checkout_event_callback)
25
+ #
26
+ # By default, an empty proc is used as the callback so that loading the
27
+ # support doesn't break anything. If you are using the extension, you
28
+ # should set the callback at some point during application startup:
29
+ #
30
+ # DB.pool.on_checkout_event = proc do |event|
31
+ # # ...
32
+ # end
33
+ #
34
+ # When using the sharded connection pool, the callback is also
35
+ # passed a second argument, the requested server shard (generally a
36
+ # symbol), allowing for collection of per-shard telemetry:
37
+ #
38
+ # DB.pool.on_checkout_event = proc do |event, server|
39
+ # # ...
40
+ # end
41
+ #
42
+ # Note that the callback may be called currently by multiple threads.
43
+ # You should use some form of concurrency control inside the callback,
44
+ # such as a mutex or queue.
45
+ #
46
+ # Below is a brief example of usage to determine the percentage of
47
+ # connection requests where a connection was immediately available:
48
+ #
49
+ # mutex = Mutex.new
50
+ # total = immediates = 0
51
+ #
52
+ # DB.pool.on_checkout_event = proc do |event|
53
+ # case event
54
+ # when :immediately_available
55
+ # mutex.synchronize do
56
+ # total += 1
57
+ # immediates += 1
58
+ # end
59
+ # when :not_immediately_available
60
+ # mutex.synchronize do
61
+ # total += 1
62
+ # end
63
+ # end
64
+ # end
65
+ #
66
+ # immediate_percentage = lambda do
67
+ # mutex.synchronize do
68
+ # 100.0 * immediates / total
69
+ # end
70
+ # end
71
+ #
72
+ # Note that this extension only works with the timed_queue
73
+ # and sharded_timed_queue connection pools (the default
74
+ # connection pools when using Ruby 3.2+).
75
+ #
76
+ # Related modules: Sequel::ConnectionCheckoutEventCallbacks::TimedQueue,
77
+ # Sequel::ConnectionCheckoutEventCallbacks::ShardedTimedQueue
78
+
79
+ #
80
+ module Sequel
81
+ module ConnectionCheckoutEventCallbacks
82
+ module TimedQueue
83
+ # The callback that is called with connection checkout events.
84
+ attr_accessor :on_checkout_event
85
+
86
+ private
87
+
88
+ def available
89
+ conn = super
90
+ @on_checkout_event.call(conn ? :immediately_available : :not_immediately_available)
91
+ conn
92
+ end
93
+
94
+ def try_make_new
95
+ conn = super
96
+ @on_checkout_event.call(:new_connection) if conn
97
+ conn
98
+ end
99
+
100
+ def wait_until_available
101
+ timer = Sequel.start_timer
102
+ conn = super
103
+ @on_checkout_event.call(Sequel.elapsed_seconds_since(timer))
104
+ conn
105
+ end
106
+ end
107
+
108
+ module ShardedTimedQueue
109
+ # The callback that is called with connection checkout events.
110
+ attr_accessor :on_checkout_event
111
+
112
+ private
113
+
114
+ def available(queue, server)
115
+ conn = super
116
+ @on_checkout_event.call(conn ? :immediately_available : :not_immediately_available, server)
117
+ conn
118
+ end
119
+
120
+ def try_make_new(server)
121
+ conn = super
122
+ @on_checkout_event.call(:new_connection, server) if conn
123
+ conn
124
+ end
125
+
126
+ def wait_until_available(queue, server)
127
+ timer = Sequel.start_timer
128
+ conn = super
129
+ @on_checkout_event.call(Sequel.elapsed_seconds_since(timer), server)
130
+ conn
131
+ end
132
+ end
133
+ end
134
+
135
+ default_callback = proc{}
136
+
137
+ Database.register_extension(:connection_checkout_event_callback) do |db|
138
+ pool = db.pool
139
+
140
+ case pool.pool_type
141
+ when :timed_queue
142
+ db.pool.extend(ConnectionCheckoutEventCallbacks::TimedQueue)
143
+ when :sharded_timed_queue
144
+ db.pool.extend(ConnectionCheckoutEventCallbacks::ShardedTimedQueue)
145
+ else
146
+ raise Error, "the connection_checkout_event_callback extension is only supported when using a timed_queue connection pool"
147
+ end
148
+
149
+ pool.on_checkout_event ||= default_callback
150
+ end
151
+ end
@@ -91,7 +91,7 @@ module Sequel
91
91
  sync{@allocated.delete(Sequel.current)}
92
92
  end
93
93
 
94
- disconnect_connection(conn)
94
+ disconnect_acquired_connection(conn, *a)
95
95
  redo
96
96
  end
97
97
  end
@@ -118,7 +118,7 @@ module Sequel
118
118
  sync{@allocated.delete(Sequel.current)}
119
119
  end
120
120
 
121
- disconnect_connection(conn)
121
+ disconnect_acquired_connection(conn, *a)
122
122
  redo if valid == false
123
123
  end
124
124
  end
@@ -6,7 +6,7 @@ module Sequel
6
6
 
7
7
  # The minor version of Sequel. Bumped for every non-patch level
8
8
  # release, generally around once a month.
9
- MINOR = 101
9
+ MINOR = 102
10
10
 
11
11
  # The tiny version of Sequel. Usually 0, only bumped for bugfix
12
12
  # releases that fix regressions from previous versions.
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sequel
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.101.0
4
+ version: 5.102.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jeremy Evans
@@ -212,6 +212,7 @@ files:
212
212
  - lib/sequel/extensions/blank.rb
213
213
  - lib/sequel/extensions/caller_logging.rb
214
214
  - lib/sequel/extensions/columns_introspection.rb
215
+ - lib/sequel/extensions/connection_checkout_event_callback.rb
215
216
  - lib/sequel/extensions/connection_expiration.rb
216
217
  - lib/sequel/extensions/connection_validator.rb
217
218
  - lib/sequel/extensions/constant_sql_override.rb