Skip to content

Commit

Permalink
SQLite: fix database is locked
Browse files Browse the repository at this point in the history
The default is to retry 10 times with 1s pause in-between.

You can change the number of retries in the config file:

	sqlite:
	  db_path: /var/lib/powerdns/pdns.sqlite3
	  retries: 15

To opt-out, set `sqlite.retries` to an int <= 0.

Fixes: #2
Signed-off-by: Dominik Menke <dom@digineo.de>
  • Loading branch information
dmke committed Jun 29, 2020
1 parent a3d3d8a commit d31210f
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 0 deletions.
9 changes: 9 additions & 0 deletions lib/backend/sqlite.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,15 @@ def initialize(*)
cfg = config.fetch(:sqlite)
@db = SQLite3::Database.new cfg.fetch(:db_path)
@meta = cfg.fetch(:meta, {})

if (n = cfg.fetch(:retries, 10).to_i) && n > 0
@db.busy_handler { |count|
puts "Database is busy, retry #{count+1} of #{n} in 1s"
sleep 1
count < n
}
end

db.foreign_keys = true
prime_database!
prepare_statements!
Expand Down
26 changes: 26 additions & 0 deletions test/integration/sqlite_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -221,4 +221,30 @@ def test_global_metadata
assert_equal expected, meta.fetch("example.com")
assert_equal expected, meta.fetch("example.org")
end

def test_busy_retry
# make DB busy by modifying the DB file in a long running transaction
# TODO: can we simplify this?
t = Thread.new {
SQLite3::Database.new(@db_path.to_s) do |db|
db.transaction {
db.execute "insert into domains(name, type) values ('test-busy.retry', 'MASTER')"
sleep 2
db.execute "delete from domains where name = 'test-busy.retry'"
}
end
}

# pushing changes should wait for the busy database
@on_client.join("zones/example.com.rb").open("a") do |z|
z.puts "", "txt 'foo'"
end
commit!
t.join

# Did we actually caught a busy database? Depending on the accuracy
# of the sleep above and the thread scheduling, @push_output sometimes
# contains a "retry 2 of 10".
assert_includes @push_output, "Database is busy, retry 1 of 10 in 1s"
end
end

0 comments on commit d31210f

Please sign in to comment.