Earlier quoted context omitted.
You should prefer RWF_SYNC in case the write involves changes to the file metadata (For example, most append operations will alter the file size).
Agreed, when metadata changes are involved then RWF_SYNC must be used. RWF_DSYNC is sufficient and faster when data is overwritten without metadata changes to the file.
Async I/O on Linux in databases
91–100 of 100 posts
Re: Async I/O on Linux in databases
#92While restoring: 1. Ignore all intents 2. Use only different operations with corresponding intents.
I think this article introduces so much chaos that it’s like many „almost” helpful info on io_uring and finally hurts the tech. io_uring IMHO lacks clean and simple examples and here we again have some bad-explained theories instead of meat.
Re: Async I/O on Linux in databases
#93Earlier quoted context omitted.
Sorry, that was a typo in my comment (now edited). "Now" was meant to be "more" i.e. "perhaps [io_uring] has more control [than sync APIs]?" Byte range is support is interesting but also present in the Linux sync API: https://man7.org/linux/man-pages/man2/sync_file_range.2.html I meant more like, perhaps it's possible to concurrently queue fsync for different writes in a way that isn't possible with the sync API. Fro…
You can insert synchronization OPs (i.e. barriers) in the queue to guarantee in-order execution.
Re: Async I/O on Linux in databases
#94Earlier quoted context omitted.
> As I said, I don't know anything about fsync in io_uring. Maybe that has now control? io_uring fsync has byte range support: https://man7.org/linux/man-pages/man2/io_uring_enter.2.html#...
Sorry, that was a typo in my comment (now edited). "Now" was meant to be "more" i.e. "perhaps [io_uring] has more control [than sync APIs]?" Byte range is support is interesting but also present in the Linux sync API: https://man7.org/linux/man-pages/man2/sync_file_range.2.html I meant more like, perhaps it's possible to concurrently queue fsync for different writes in a way that isn't possible with the sync API. Fro…
Unfortunately, I think sync_file_range() provides much weaker guarantees than byte-range fsync() and even byte-range fdatasync().
As I understand it from historical behaviour and documentation, sync_file_range() doesn't push durability barriers down the underlying storage devices, nor does it ensure that all metadata needed to access the written pages is itself written and made durable, for example when writing to a hole in a sparse file, to the end-hole created by enlarging a file with ftruncate(), or to fallocate'd pages.
As a result, that means sync_file_range() can only be used as a performance tweak, and not for any durability guarantees that fdatasync() / fsync() are used for.
I'd be delighted to find this has improved since I last looked, but that's what I recall about sync_file_range().
Re: Async I/O on Linux in databases
#95Earlier quoted context omitted.
Reading through the article it’s explained in the recovery process. He reads the intent log entries and the completion entries and only applies them if they both exist. So there is no guarantee that operations are committed by virtue of not being acknowledged to the application (asynchronous) the recovery replay will be consistent. I could see it would be problematic for any data where the order of operations is impo…
There's not even a guarantee that the intent log flushes to disk before the completion log. You can get completions entries in the completion log that were lost in the intent log. So, no, there's no guarantee of consistent recovery. You'd be better off with a single log.
Re: Async I/O on Linux in databases
#96Earlier quoted context omitted.
Postgres claims to have some kind of commit batching, but I couldn't figure out how to turn it on. I wanted to scrub a table by processing each row, but without holding locks, so I wanted to commit every few hundred rows, but with only ACI and not D, since I could just run the process again. I don't think Postgres supports this feature. It also seemed to be calling fsync much more than once per transaction.
Looking through the options listed under "Non-Durable Settings", [1] I guess synchronous_commit = off fits the bill? [1]: https://www.postgresql.org/docs/current/non-durability.html
https://www.postgresql.org/docs/current/runtime-config-wal.h...
Don't use synchronous_commit = off is durability ~= 0 (i.e. "I hope the write made it to disk")
Re: Async I/O on Linux in databases
#97The gains are from batching and doing work in-between. io_uring does "batching at a distance", and the DB can write to memory and perform operations in between. When io_uring checks the queues (intent/operation), it will find more than one operation, and do them all at once.
You don't lose durability with this setup -- you just do more speculative work (if you got the worst possible crash at the worst possible time), and if a bunch of things completed (because io_uring did them all at once) you get more confirmations you can send back faster.
Latency MIGHT suffer, but throughput would (and does) increase.
Re: Async I/O on Linux in databases
#98Earlier quoted context omitted.
Agreed, when metadata changes are involved then RWF_SYNC must be used. RWF_DSYNC is sufficient and faster when data is overwritten without metadata changes to the file.
No that’s incorrect. File size changes caused by append are covered by fdatasync in terms of durability guarantees.
Edit: POSIX 1003.1-2017 defines fdatasync(2) behavior in 3.384 Synchronized I/O Data Integrity Completion, where it says "For write, when the operation has been completed or diagnosed if unsuccessful. The write is complete only when the data specified in the write request is successfully transferred and all file system information required to retrieve the data is successfully transferred".
So I think POSIX does guarantee that a write at the end of the file with O_DSYNC/followed by fdatasync(2) (and therefore, Linux RWF_DSYNC) is sufficient. Thank you for pointing out that RWF_DSYNC is sufficient for appends, vlovich123!
Re: Async I/O on Linux in databases
#99Earlier quoted context omitted.
Well, there already is slightly more fine gained control: in the sync version, you can perhaps call sync write() a few times before calling fsync() once i.e. basically batch up a few writes. That does have the disadvantage that you can't easily queue new writes while waiting for the previous ones. Perhaps you could use calls to write() in another thread while the first one is waiting for fsync() for the previous batc…
Postgres claims to have some kind of commit batching, but I couldn't figure out how to turn it on. I wanted to scrub a table by processing each row, but without holding locks, so I wanted to commit every few hundred rows, but with only ACI and not D, since I could just run the process again. I don't think Postgres supports this feature. It also seemed to be calling fsync much more than once per transaction.
If it's called many more times than once per transaction the likely reason is that wal_buffers is sized small. Whenever generated WAL exceeds wal_buffers, postgres flushes the WAL, so it does not have to reopen the file later. At that point you already gotten most benefits from batching too.
Edit: A second reason is that data pages need to be written out due to cache pressure or such, and that requires the WAL to be flushed first.
Re: Async I/O on Linux in databases
#100Earlier quoted context omitted.
Maybe I don’t understand what you’re trying to do, but you can directly control how frequently commits occur. BEGIN INSERT … —- batch of N size COMMIT AND CHAIN INSERT …
Chance of Postgres commit mapping 1:1 onto posix fsync or equivalent: slim.