Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SQLite C++ 'database is locked' when multiple processes access db in readonly mode

I have an sqlite database that doesn't change.

Multiple processes that open a database connection each in SQLITE_OPEN_READONLY mode using sqlite3_open_v2. Each process is single threaded

The connections are made from an MSVC project using the official C/C++ Interface's single amalgamated C source file.

According to the SQLite FAQ multiple processes running SELECTs is fine

Each process after opening the database creates 4 prepared SELECT statements each with 2 bindable values.

Over the course of the execution the statements (one at a time) have the following called on them repeatedly as required

  • sqlite3_bind_int
  • sqlite3_bind_int
  • sqlite3_step (while SQLITE_ROW is returned)
  • sqlite3_column_int (while there was a row)
  • sqlite3_reset

The prepared statements are reused so finalize isn't called on each of them until near the end of the program. Finally the database is closed at the very end of execution.

The problem is any of these operations can fail with error code = 5: 'database is locked'

Error code 5 is SQLITE_BUSY and the website states that

"indicates a conflict with a separate database connection, probably in a separate process"

The rest of the internet seems to agree that multiple READONLY connections is fine. I've gone over and over the source and can't see that anything is wrong (I can't post it here sadly, I know, not helpful)

So I'm turning it to you guys, what could I possibly be missing?

EDIT 1: Database is on a local drive, File system is NTFS, OS is Windows 7.

EDIT 2: Wrapping all sqlite3 calls in infinite loops that check if SQLITE_BUSY was returned and then remake the call alleviates the problem. I don't consider this a fix but if that truly is the right thing to do then I'll do that.

like image 951
dten Avatar asked Oct 31 '22 15:10

dten


1 Answers

So the working answer I have used is to wrap all the calls to sqlite in functions that loop that function while SQLITE_BUSY is returned. There doesn't seem to be a simple alternative.

const int bindInt(sqlite3_stmt* stmt, int parameterIndex, int value)
{
    int ret;
    do
        ret = sqlite3_bind_int(stmt, parameterIndex, value);
    while (ret == SQLITE_BUSY)
    return ret;
}
like image 61
dten Avatar answered Nov 15 '22 04:11

dten