[Feature brainstorm] Unlock-notify or retry logic #1228
Replies: 19 comments
-
Hello. This is a good case. Actually the only sqlite3 call in this code is struct UnlockNotification {
int fired = 0; /* True after unlock event has occurred */
pthread_cond_t cond; /* Condition variable to wait on */
pthread_mutex_t mutex; /* Mutex to protect structure */
};
UnlockNotification unlockNotification;
storage.unlock_notify([](UnlockNotification &unlockNotification){
pthread_mutex_lock(&unlockNotification.mutex);
unlockNotification.fired = 1;
pthread_cond_signal(&unlockNotification.cond);
pthread_mutex_unlock(&unlockNotification.mutex);
}, unlockNotification); And also |
Beta Was this translation helpful? Give feedback.
-
The minor problem here is that When you write it as It would be nice if we can have a tag that goes into the statement execution, for example
or
so that it is overloaded, and doesn't break backward compatibility. |
Beta Was this translation helpful? Give feedback.
-
Actually, on second thoughts, I don't have a problem with a connection-wide unlock-notify setter, although I imagine that eventually there can be a per-statement unlock-notify handler. It has to be clearly documented to avoid confusion, though. After thinking about it for a while longer, my opinion is that all implementations of unlock-waiting (i.e. the one provided in the sqlite3 webpage) will more or less look the same.
I suppose we can take a bool-returning function to allow user-defined options. |
Beta Was this translation helpful? Give feedback.
-
what if this kind of callback can be set right in storage just like storage.unlock_notify_callback = [] {
// do whatever you want
}; and when storage knows that |
Beta Was this translation helpful? Give feedback.
-
@undisputed-seraphim one more question. Can you solve your issue with |
Beta Was this translation helpful? Give feedback.
-
@undisputed-seraphim are you there? |
Beta Was this translation helpful? Give feedback.
-
Sorry, I had a few things to do over the last few days. Busy handler does not solve my problem (it solves another problem though 👍 ) I actually quite like the latest idea you proposed. Let's go with that. (And a new release tag soon!... I hope!) btw you can remove busy_handler from the TODO list now :D |
Beta Was this translation helpful? Give feedback.
-
Ok I see that my idea is not enough. It will be easier to implement it of I know how to reproduce database to return |
Beta Was this translation helpful? Give feedback.
-
SQLITE_BUSY is a conflict between 2 different DB connections, whereas SQLITE_LOCKED is a conflict within the same DB connection. For SQLITE_BUSY it is hard, because the unit test has to create two connections to the same DB on two different processes. Not really familiar with Catch2 to know how to write it. |
Beta Was this translation helpful? Give feedback.
-
Off topic |
Beta Was this translation helpful? Give feedback.
-
Can we simulate it using two threads with two storages?
That looks great. I want to refactor it that way. One problem exists there: you lost |
Beta Was this translation helpful? Give feedback.
-
Yes it will be very soon (in a week). For updates please follow twitter account of this lib https://twitter.com/sqlite_orm |
Beta Was this translation helpful? Give feedback.
-
Sorry for being missing again. I'll be making a series of pull requests for the |
Beta Was this translation helpful? Give feedback.
-
For the past few days I have unsuccessfully tried to simulate a locked database in a unit test. Still trying to figure out how to do it in a non-probabilistic way. |
Beta Was this translation helpful? Give feedback.
-
Some updates from me: I have worked around this issue in my code, so I no longer run into this issue. I no longer need this particular feature. |
Beta Was this translation helpful? Give feedback.
-
How did you do it? I am curious. |
Beta Was this translation helpful? Give feedback.
-
My problem was that I was trying to write to the same table from different threads. All I did was to avoid that be re-organizing the code. I also adjusted my sqlite3 commands so that the query planner does not detect a deadlock, hence the busy timeout is respected (reference) |
Beta Was this translation helpful? Give feedback.
-
@undisputed-seraphim is this issue actual? |
Beta Was this translation helpful? Give feedback.
-
@undisputed-seraphim is this issue actual? |
Beta Was this translation helpful? Give feedback.
-
I need to write to the same database from several threads. Sometimes, the threads encounter SQLITE_LOCKED and a
std::system_error
is thrown, but this is a recoverable issue and I would like to simply retry the step, perhaps with a backoff.As per the sqlite3_unlock_notify page, perhaps it is possible to work the retry logic into this.
Currently, most of the code involving
sqlite3_step()
looks like this:Perhaps it can be changed into something like this.
We set a bool flag in
storage_base
to indicate if we should block onSQLITE_LOCKED
.Where
wait_for_unlock_notify()
is similar to the one described in the page above.However, not all sqlite3 compilations have the
sqlite3_unlock_notify()
function. In that case, we can somehow fall back to a regular blocking loop:Of course,
sleep_for
can be hidden insidewait_for_unlock_notify
(with a better name I guess) and the existence ofsqlite3_unlock_notify
is detected with SFINAE.What do you think?
As for the implementation of unlock_notify object, it can be achieved through
std::condition_variable
andstd::mutex
to keep it cross-platform, instead of relying onpthread
.Beta Was this translation helpful? Give feedback.
All reactions