Skip to content

Fix Database Locking Issues#607

Open
fk0815 wants to merge 4 commits into
Nachtzuster:mainfrom
fk0815:main
Open

Fix Database Locking Issues#607
fk0815 wants to merge 4 commits into
Nachtzuster:mainfrom
fk0815:main

Conversation

@fk0815
Copy link
Copy Markdown

@fk0815 fk0815 commented Apr 19, 2026

Fix Database Locking Issues

Related Discussion: #323

This pull request addresses the "Database busy. database is locked" errors that occur when reloading pages while detections are being processed in the background.

Changes Included

  1. Fix database connection leak in common.php (9b901b0)

• Fixed get_db() function that was creating new connections on every call
• Changed from broken global variable to static variable
• Ensures only one connection per PHP request

  1. Enable WAL mode in Python reporting (2d86b93)

• Added PRAGMA journal_mode=WAL to allow concurrent reads during writes
• Set PRAGMA synchronous=NORMAL for better performance
• Critical for applications with frequent writes and reads

  1. Implement batch inserts (abb03ad)

• Added write_detections_to_db() function for batch transactions
• Groups all detections from a file into single transaction
• Reduces lock duration and improves concurrency

  1. Increase busy timeout (ded7eed)

• Increased timeout from 1s to 5s in all PHP scripts
• Gives web interface more time to wait for write operations
• Reduces "database is busy" errors

This PR has been crated with the help of mistral vibe AI.

Frank Kunz added 4 commits April 15, 2026 20:22
The get_db() function was creating a new database connection on every call
due to incorrect variable scoping. This caused connection leaks that led to
'Database busy. database is locked' errors when reloading pages.

Changed from using a global variable (which wasn't working due to missing
global keyword) to a static variable that maintains state within the function
scope. This ensures only one connection is created per request, preventing
connection accumulation and permanent locks.
…writes

WAL (Write-Ahead Logging) mode allows SQLite readers to continue reading
data even while a write transaction is in progress. This is critical for
applications like BirdNET-Pi where the analysis script frequently writes
detections while the web interface reads from the database.

This change enables WAL mode and sets synchronous=NORMAL for better
performance while maintaining data safety.
Instead of creating a separate transaction for each detection, this change
batches all detections from a single audio file into one transaction.

This significantly reduces the number of write operations and exclusive
locks on the database, allowing the web interface to read more reliably
during analysis.

The batch function write_detections_to_db() handles multiple detections
in a single BEGIN/COMMIT transaction, minimizing lock duration.
The 1-second busy timeout was too short for scenarios where the Python
analysis script holds write locks while processing multiple detections.

Increasing to 5 seconds gives the web interface more time to wait for
write operations to complete before showing 'database is busy' errors.

This change affects all PHP scripts that access the database:
- common.php (get_db and ImageProvider)
- history.php
- overview.php
- play.php
- species_tools.php
- todays_detections.php
- weekly_report.php
@etiennedm
Copy link
Copy Markdown

Can someone review this? I can't comment on the PHP, especially the seemingly wrong implementation of the DB connection singleton.

On the Python side of things, it does make sense to batch detection insertion, and it's looking fine.

I've been actually running this for a few hours now, stress testing the UI in parallel, and can't reproduce a locked database.

To test it, add the remote to your local git repo and run the update script:

git remote add locked-db-fix https://github.com/fk0815/BirdNET-Pi.git
./scripts/update_birdnet.sh -r locked-db-fix -b main

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants