9
9
# DB.block_queries do
10
10
# ds = DB[:table] # No exception
11
11
# ds = ds.where(column: 1) # No exception
12
- # ds.all # Attempts query, exception raised
12
+ # ds.all # Exception raised
13
13
# end
14
14
#
15
15
# To handle concurrency, you can pass a :scope option:
26
26
# # Specific Fiber
27
27
# DB.block_queries(scope: Fiber.current){}
28
28
#
29
+ # Database#block_queries is useful for blocking queries inside
30
+ # the block. However, there may be cases where you want to
31
+ # allow queries in specific places inside a block_queries block.
32
+ # You can use Database#allow_queries for that:
33
+ #
34
+ # DB.block_queries do
35
+ # DB.allow_queries do
36
+ # DB[:table].all # Query allowed
37
+ # end
38
+ #
39
+ # DB[:table].all # Exception raised
40
+ # end
41
+ #
42
+ # When mixing block_queries and allow_queries with scopes, the
43
+ # narrowest scope has priority. So if you are blocking with
44
+ # :thread scope, and allowing with :fiber scope, queries in the
45
+ # current fiber will be allowed, but queries in different fibers of
46
+ # the current thread will be blocked.
47
+ #
29
48
# Note that this should catch all queries executed through the
30
49
# Database instance. Whether it catches queries executed directly
31
50
# on a connection object depends on the adapter in use.
@@ -64,7 +83,18 @@ def log_connection_yield(sql, conn, args=nil)
64
83
# Whether queries are currently blocked.
65
84
def block_queries?
66
85
b = @blocked_query_scopes
67
- Sequel . synchronize { b [ :global ] || b [ Thread . current ] || b [ Fiber . current ] } || false
86
+ b . fetch ( Fiber . current ) do
87
+ b . fetch ( Thread . current ) do
88
+ b . fetch ( :global , false )
89
+ end
90
+ end
91
+ end
92
+
93
+ # Allow queries inside the block. Only useful if they are already blocked
94
+ # for the same scope. Useful for blocking queries generally, and only allowing
95
+ # them in specific places. Takes the same :scope option as #block_queries.
96
+ def allow_queries ( opts = OPTS , &block )
97
+ _allow_or_block_queries ( false , opts , &block )
68
98
end
69
99
70
100
# Reject (raise an BlockedQuery exception) if there is an attempt to execute
@@ -77,44 +107,51 @@ def block_queries?
77
107
# :fiber :: Reject all queries in the current fiber.
78
108
# Thread :: Reject all queries in the given thread.
79
109
# Fiber :: Reject all queries in the given fiber.
80
- def block_queries ( opts = OPTS )
81
- case scope = opts [ :scope ]
82
- when nil
83
- scope = :global
84
- when :global
85
- # nothing
86
- when :thread
87
- scope = Thread . current
88
- when :fiber
89
- scope = Fiber . current
90
- when Thread , Fiber
91
- # nothing
92
- else
93
- raise Sequel ::Error , "invalid scope given to block_queries: #{ scope . inspect } "
94
- end
110
+ def block_queries ( opts = OPTS , &block )
111
+ _allow_or_block_queries ( true , opts , &block )
112
+ end
113
+
114
+ private
95
115
116
+ # Internals of block_queries and allow_queries.
117
+ def _allow_or_block_queries ( value , opts )
118
+ scope = query_blocker_scope ( opts )
96
119
prev_value = nil
97
120
scopes = @blocked_query_scopes
98
121
99
122
begin
100
123
Sequel . synchronize do
101
124
prev_value = scopes [ scope ]
102
- scopes [ scope ] = true
125
+ scopes [ scope ] = value
103
126
end
104
127
105
128
yield
106
129
ensure
107
130
Sequel . synchronize do
108
- if prev_value
109
- scopes [ scope ] = prev_value
110
- else
131
+ if prev_value . nil?
111
132
scopes . delete ( scope )
133
+ else
134
+ scopes [ scope ] = prev_value
112
135
end
113
136
end
114
137
end
115
138
end
116
-
117
- private
139
+
140
+ # The scope for the query block, either :global, or a Thread or Fiber instance.
141
+ def query_blocker_scope ( opts )
142
+ case scope = opts [ :scope ]
143
+ when nil
144
+ :global
145
+ when :global , Thread , Fiber
146
+ scope
147
+ when :thread
148
+ Thread . current
149
+ when :fiber
150
+ Fiber . current
151
+ else
152
+ raise Sequel ::Error , "invalid scope given to block_queries: #{ scope . inspect } "
153
+ end
154
+ end
118
155
119
156
# Raise a BlockQuery exception if queries are currently blocked.
120
157
def check_blocked_queries!
0 commit comments