Skip to content

Commit 9cff42b

Browse files
authored
Merge pull request #456 from fractaledmind/fix-busy_handler_timeout-tests
busy_handler_timeout pt2
2 parents 21db633 + 75893cd commit 9cff42b

2 files changed

Lines changed: 57 additions & 0 deletions

File tree

lib/sqlite3/database.rb

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -695,6 +695,25 @@ def readonly?
695695
@readonly
696696
end
697697

698+
# Sets a #busy_handler that releases the GVL between retries,
699+
# but only retries up to the indicated number of +milliseconds+.
700+
# This is an alternative to #busy_timeout, which holds the GVL
701+
# while SQLite sleeps and retries.
702+
def busy_handler_timeout=( milliseconds )
703+
timeout_seconds = milliseconds.fdiv(1000)
704+
705+
busy_handler do |count|
706+
now = Process.clock_gettime(Process::CLOCK_MONOTONIC)
707+
if count.zero?
708+
@timeout_deadline = now + timeout_seconds
709+
elsif now > @timeout_deadline
710+
next false
711+
else
712+
sleep(0.001)
713+
end
714+
end
715+
end
716+
698717
# A helper class for dealing with custom functions (see #create_function,
699718
# #create_aggregate, and #create_aggregate_handler). It encapsulates the
700719
# opaque function object that represents the current invocation. It also

test/test_integration_pending.rb

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,4 +74,42 @@ def test_busy_timeout
7474

7575
assert_operator time.real * 1000, :>=, 1000
7676
end
77+
78+
def test_busy_handler_timeout_releases_gvl
79+
work = []
80+
81+
Thread.new do
82+
while true
83+
sleep 0.1
84+
work << '.'
85+
end
86+
end
87+
sleep 1
88+
89+
@db.busy_handler_timeout = 1000
90+
busy = Mutex.new
91+
busy.lock
92+
93+
t = Thread.new do
94+
begin
95+
db2 = SQLite3::Database.open( "test.db" )
96+
db2.transaction( :exclusive ) do
97+
busy.lock
98+
end
99+
ensure
100+
db2.close if db2
101+
end
102+
end
103+
sleep 1
104+
105+
assert_raises( SQLite3::BusyException ) do
106+
work << '|'
107+
@db.execute "insert into foo (b) values ( 'from 2' )"
108+
end
109+
110+
busy.unlock
111+
t.join
112+
113+
assert work.size - work.find_index('|') > 3
114+
end
77115
end

0 commit comments

Comments
 (0)