SQLite Forum

Is write permission required for read-only connections on a WAL database?
Login

Is write permission required for read-only connections on a WAL database?

(1.2) By Gwendal Roué (groue) on 2020-05-05 16:23:46 edited from 1.1 [link] [source]

Hello,

I can't quite figure out, reading https://www.sqlite.org/wal.html, if the sentence below implies that readers must have write permission on some database file or directory:

A long-running read transaction can prevent a checkpointer from making progress

Surely the only communication channel between readers and writers is the file system, isn't it?

To ask the same question in another way, can a unix user with only read permission on a database and its directory open a read-only connection on a WAL database and still expect to be able to be granted with snapshot isolation even if there are concurrent writers?

Thank you very much for your answer,

Gwendal Roué

(2) By Warren Young (wyoung) on 2020-05-05 17:42:36 in reply to 1.2 [source]

You might need to set the SQLITE_OPEN_READONLY flag on the sqlite3_open_v2() call to prevent SQLite from trying to create the -wal and -shm files, which will fail if the reader can't write to the directory holding the DB file.

(5) By Keith Medcalf (kmedcalf) on 2020-05-05 18:00:04 in reply to 2 [link] [source]

A database with a journal mode of WAL must always have a WAL and SHM file when open and in use. The only way to not have them is to change the journal mode to something other than WAL.

(7.1) By Gwendal Roué (groue) on 2020-05-05 18:20:18 edited from 7.0 in reply to 2 [link] [source]

Thank you, I know about SQLITE_OPEN_READONLY. But even though, doesn't a reader have to write something so that it communicates to the writers that checkpointing must not remove from the WAL the data accessed by the reader?

(3) By Simon Slavin (slavin) on 2020-05-05 17:53:15 in reply to 1.2 [link] [source]

Suppose your read-only connection to the database executed a SELECT which returned a thousand rows. You would need to know that another connection to the database didn't change the database part way through the rows being read. So even a read-only connection to the database needs to be able to tell other connections that it is in use.

A WAL database requires two other files to maintain a record of locking and changes. Even if you open the file telling SQLite you need read-only access, SQLite still has to create the -shm and -wal files in the same folder as the database file. So it still needs write permission to that folder.

You might be able to get a result by having another connection create the -shm and -wal files first, then establishing your read-only connection. But that's a hack and I don't know if it will really work.

(8.2) By Gwendal Roué (groue) on 2020-05-05 18:22:29 edited from 8.1 in reply to 3 [link] [source]

You might be able to get a result by having another connection create the -shm and -wal files first, then establishing your read-only connection. But that's a hack and I don't know if it will really work.

Thank you, we're getting closer to an answer to my question.

According to your answer, a reader needs write access to the database, even if it opens a read-only connection, so that it can create the -shm and -wal files.

What I still don't know is: if a read-only connection is opened after -shm and -wal files are created, can it prevent checkpointing if the reader process has no write permission?

I can't find anywhere in the documentation if the WAL journal mode requires the write UNIX permissions or not, even for SQLITE_OPEN_READONLY connecttions.

(4) By Keith Medcalf (kmedcalf) on 2020-05-05 17:56:22 in reply to 1.2 [link] [source]

(NON-WAL) Updating the database file requires EXCLUSIVE access to the database. That means that there must be no readers in order to COMMIT a transaction "write the changes to the database". This is necessarily so because the "database file" must be "static" while it is being read, just as all hell may break loose if you update a memory structure while another thread is writing (mutating) that structure. "mutexes" are used to arbitrate access to "memory structures" and "file locks" are used to arbitrate access to files.

When using WAL, this is relaxed because COMMIT does not write to the database, it writes to a "write-aside" log. That means that a transaction can COMMIT (write its changes to the write-aside file) while a reader is reading the database.

From time to time, however, the changes written to the "write-aside" log must be written (called a checkpoint) into the database file.

However, you cannot write changes that "ought not be seen" by a current reader to the database file. Therefore, a long lasting reader can prevent the "write-aside" updates from being copied to the database.

This is well explained in the referenced documentation of "write-aside logging".

(6.2) By Gwendal Roué (groue) on 2020-05-05 18:22:10 edited from 6.1 in reply to 4 [link] [source]

Therefore, a long lasting reader can prevent the "write-aside" updates from being copied to the database.

Yes, this is abundantly documented.

My question is whether a reader needs write access in order to make this effective.

I can ask the question in a third way, because I really hope that we can get to the point:

Can a process without write UNIX permission to a WAL database file in and directory prevent concurrent writers from checkpointing?

This is a very precise question!

Thank you very much in advance.

(9) By Richard Hipp (drh) on 2020-05-05 18:22:53 in reply to 6.1 [link] [source]

Can a process without write permission to a WAL database file in and directory prevent concurrent writers from checkpointing?

Yes. Read locks can be taken on files to which you do not have write permission.

(11) By Gwendal Roué (groue) on 2020-05-05 18:29:27 in reply to 9 [link] [source]

Yes. Read locks can be taken on files to which you do not have write permission.

Thank you very much for your answer!

That's amazing!

Now this is just for my personal culture: how is it possible? What is the communication channel?

(13) By Gwendal Roué (groue) on 2020-05-05 18:54:45 in reply to 11 [link] [source]

Many thanks to you all. The summary, as far as I understand, is:

  1. YES a read-only process can access a WAL database, without any ill side effects (I still don't know how it works).
  2. BUT such a connection requires that the -wal and -shm files are present before it starts reading.

I can't help but feeling that something is odd with the second sentence, because sqlite3_close_v2 is documented to delete the -wal and -shm files:

[...] so the closing connection runs a checkpoint (while holding SQLITE_LOCK_EXCLUSIVE) and then deletes both the WAL and WAL-index files.

To me, this means that a process without write access HAS NO GUARANTEE it can access a WAL database.

(10) By Keith Medcalf (kmedcalf) on 2020-05-05 18:26:14 in reply to 6.0 [link] [source]

Yes.

The same stability requirements apply when reading the database whether you are confined to only reading, or only reading at the moment in the same way that a "thread" traversing an in-memory structure requires that the structure be unchanging while it is traversing it -- it makes no matter that the "reader" cannot "write".

It is like reading a book. While reading the book, you cannot have something else making changes (adding deleting and renumbering pages). This requirement does not change just because you can or cannot add, remove, or renumber pages. It is inherent in the activity of "coherent reading".

(12.1) By Gwendal Roué (groue) on 2020-05-05 18:33:20 edited from 12.0 in reply to 10 [link] [source]

I see what you mean, but I still wonder how a reader without write permission can communicate writers that their eventual checkpointing operations (particularly SQLITE_CHECKPOINT_TRUNCATE) must fail ???

(14.1) By Keith Medcalf (kmedcalf) on 2020-05-05 20:12:04 edited from 14.0 in reply to 12.1 [link] [source]

That depends on what you mean by "reader without write permissions".

If by that you mean that CREATE/DROP/INSERT/ALTER/DELETE/UPDATE statements are "intercepted with a 'you cannot do that you silly twit` error message" then that is merely an artificial limitation (conceptually similar to having a guard at the paint-store-door that will refuse to sell you pink paint) -- we call that LOGICAL access control because it is not real, it is merely a convention, sort of like DRM or a flag saying "NotEvil". It does not mean that the process does not have PHYSICAL ACTUAL REAL write access, merely that it is LOGICALLY preventing you from having it -- as long as you play along.

A LOGICAL (ie, application level) read-only connection is still required to have PHYSICAL (ie, Operating System level) write-access to the SHM file. YOU are prevented from writing to the database files, however SQLITE itself has no such limitation.

If the Operating System cannot grant write access to the SHM file, then the database must be immutable (no one can change it). If the database is immutable and nonetheless is "mutated", all hell will break loose.

SQLite requires READ/WRITE access to the SHM (wal index) by all processes connecting to a "mutable" database even if the connection is LOGICALLY read-only.

https://sqlite.org/walformat.html particularly the descriptions of the READ_LOCK[N] fields in the SHM (index) file and how they work might be helpful.

(15.1) By Gwendal Roué (groue) on 2020-05-06 04:56:32 edited from 15.0 in reply to 14.1 [link] [source]

That depends on what you mean by "reader without write permissions".

UNIX permission

A LOGICAL (ie, application level) read-only connection is still required to have PHYSICAL (ie, Operating System level) write-access to the SHM file. YOU are prevented from writing to the database files, however SQLITE itself has no such limitation.

This contradicts this message by D. Richard Hipp:

Yes. Read locks can be taken on files to which you do not have write permission.

What am I supposed to conclude?

Look, I'm really looking for the answer for a simple question: is WAL suitable when some readers don't have write permission?

It's a very simple, and very important question.

So far, my answer is NO, the WAL mode is not suitable when some readers don't have write permission, because a WAL database can exist without any -shm and -wal file, making them unusable by such readers.

I think this should be explicitly stated in the "disadvantages" section of https://www.sqlite.org/wal.html.

(16) By Gwendal Roué (groue) on 2020-05-06 05:08:31 in reply to 15.0 [link] [source]

This is my final post in this thread, I'm sorry. I missed this in https://www.sqlite.org/walformat.html#operations_that_require_locks_and_which_locks_those_operations_use

> If the application invokes sqlite3_file_control(SQLITE_FCNTL_PERSIST_WAL) on the database connection prior to closing, then the final checkpoint is still run but the WAL and WAL-index files are not deleted as they normally would be. This leaves the database in a state that allows other processes without write permission on the database, WAL, or WAL-index files to open the database read-only. If the WAL and WAL-index files are missing, then a process that lacks permission to create and initialize those files will not be able to open the database, unless the database is designated as immutable using the immutable query parameter.

Now that's meat to chew on.

(17) By anonymous on 2020-05-06 18:40:08 in reply to 1.2 [link] [source]

Perhaps it could be fixed, so that if the read version is set to 1 and the write version is set to 2, then reading a WAL database is allowed even if the -wal and -shm files are not exist and without creating them, but committing and checkpointing are not allowed unless you first change the read version to 2, and you cannot change the read version from 2 to 1 (while leaving the write version at 2) unless first the database is fully checkpointed and no transactions are active.