-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Possible solutions to the concurrency problems #1179
Comments
Where did you hear that? |
I mean when you want to write to the database from more than one goroutine. See docs:
Although, I've seen issues that people sometimes have problems with reading too, like in this comment. |
Unfortunately, the README is a little misleading. This library is already safe for concurrent use. However, there are a few caveats that need to be acknowledged. SQLite will support any number of concurrent reads under any mode. It does not support a concurrent read and write to the same database file under the default rollback journal mode, but this is supported under WAL mode. It does not support concurrent writes to the same database file under any mode. It is generally recommended to use WAL. Please note that "does not support" means that it will perform these operations serially, with a wait/retry period defined by your busy handler (or the You may have come across some suggestions to use shared cache mode to avoid If your code is going to read and write to the database as part of the same operation, you must use a single transaction for the whole thing. Otherwise, because of how Whenever you start a transaction that might write to the database, always use My general recommendation is to have two connection pools (i.e., |
Thanks a lot for this detailed explanation. Currently I don't know much about the technical details of SQLite. But using this I now know what to look for. So, it's very helpful and could actually be part of the documentation, or linked to from the docs or the FAQ I've mentioned. 👍
Yes, this is really a big confusing part because I expect every RDBMS to work that way (at least to some extend) because of ACID. I will close this issue now because my original intent doesn't really make any sense now. |
Thank you so much! It's a very helpful recommendation. Do I also need to set both connection pools to WAL mode? @rittneje |
@shivabohemian I would generally recommend using WAL when possible, but you don't have to. Please note that a read-only connection will not be able to convert the database to WAL mode, so be sure to open the read-write connection first. (This also means there is little point in attempting to set the journal mode to WAL via the read-only connections.) Also note that since |
Got it. Thank you for your notes and it's very useful. |
Is it possible / recommended to do the following with multiple single-tenant dbs:
@rittneje Is there a clear explanation why this error is happening? Under which scenarios does it happen? Can the issue be circumvented? |
Shared cache mode is not recommended for use at all. As far as SQLITE_LOCKED goes, see https://www.sqlite.org/unlock_notify.html for details. Note this requires building your application with the sqlite_unlock_notify build tag, which I would recommend against doing. |
Why would shared cache be an issue with read-only connections? |
Could Lets call this hypothetical package |
A driver needs to implement the database/sql/driver APIs, which underpin |
Another issue with that is there is no way in general to handle any non-transactional access. For example, suppose the application code calls |
I see, I was not aware that you can use the Query statement to perform an update. This fact seems to preclude any attempt to multiplex multi-reader/single-writer connections automatically behind a single It seems that optimal usage of SQLite in Go significantly more complicated than the default/typical usage of |
I am aware that this library can cause problems when being used in different goroutines. These days I was thinking about how this could be solved. I think a good idea would be to use a dedicated goroutine that handles all database related work. It would be similar to a task queue since you could send a query to execute into it and wait for a result to come back, but with support for a single task runner only.
Since channels have a limited capacity a direct connection wouldn't work because the channel can overflow pretty easily. So the idea is to use a task quere separate from the actual worker. Like this:
I'm currently not very experienced with using goroutines and channels, so I've found a possible implementation here: https://reintech.io/blog/implementing-distributed-task-queue-go
But it contains a very curious piece of code:
If you're interested
The second
case
seems to wait untiltq.tasks
contains an item that can be sent totq.dequeue
. According to a Go developer I know this behavior is not well defined in the language spec and might break or change in a future release. So, I'm keeping my fingers from that for now.So, my questions are: a) does anybody know how to implement this or how to improve the implementation above? And b) (that's why I'm opening an issue here) where is the best place for this? It could be done in the individual projects. But since this seems to be a big problem amongst many users couldn't it be part of
go-sqlite3
itself (maybe as a public wrapper or helper function or as an internal implementation detail)? Or maybe a separate wrapper/helper library? In the case of this being custom code could a solution like this be added to the documentation (or linked to one) so everyone working with concurrency has an easier starting point?What do you think about this in general? Are there problems to this approach I don't see yet?
The text was updated successfully, but these errors were encountered: