write в буфер фиксированного размера2.1) Периодически флашим его, то есть асинхронно отправляем
write c буффером через io_uring интерфейс (тут также понадобится некоторый кеш блоков, так как мы отдаем владение блоком ядру, но это просто список, стек)2.2) Тут возможна оптимизация, есть два варианта как пользоваться
io_uring сабмитить данные самому через сискол, или завести специальный поток на стороне ядра который будет поллить очередь [3].fsync, мы просто флашим буфер, и хочется сказать "отправляем fsync через io_uring", но нет, ведь ядро, может исполнять запросы в очереди в произвольном порядке, что и делает io_uring действительно быстрым (забавно кстати, что есть некоторые параллели с тем как vulkan отличается от opengl). То есть, если мы просто будем отправлять fsync, то ядро сначала может исполнить его, а затем уже write-ы которые в очереди.3) Что же тогда делать? Ну можно было бы дождаться завершения всех вызовов в очереди, то есть самим по-poll-ить completion queue, но есть решения лучше, давайте просто запушим
nop операцию которая будет с DRAIN флагом, такая операция и будет барьером, который не позволит ядру запустить fsync раньше чем исполнить все write, при этом мы не будем ждать (!)Собственно все, задача решена, самое приятное с точки зрения файлового IO, что все это работает как с буферезованным, так и с нет IO, например никто не мешает использовать
mmap файла для рандомных чтений.Ну и как вишенка на торте, то что помимо правильного API мы получаем самое производительное решение: есть разные бенчмарки, вот например [5]
Пожалуй единственный печальный момент, что даже 5.1 кернел еще далеко не у всех юзеров, как я понимаю enterprise на данный момент это в основном 3-4 кернелы (что конечно пиздец, но спасибо хоть не 2)
Что же с аналогами не из мира linux?
Ну на Windows, довольно быстро сообразили, что тут сделали офигенную штуку и сделали аналог [6], судя по тому, что я видел, разница около косметическая,
io_uring.Из особенностей, помимо мелких отличий, оно более свежее, так что мануалов, багов и тд, наверно больше. А еще, помоему, нет некоторых фичей, но задел под флаги есть [7], так что думаю это только вопрос времени.
В
FreeBSD, macOS, ... ну вы поняли, насколько я знаю аналога нет :(Ну пожалуй стоит заметить, что
kqueue изначально сделан более прямо чем epoll и умеет в fd в отличии от него (epoll всегда возвращает что готов)Как следствие проблема именно файлового IO там вероятно чуть менее остра? Ну а сокращение количества вызовов сисколов (только сейчас задумался как же странно это звучит), и возможность делать асинхронными не только read/write видимо менее критична на их взгляд. Не знаю, вообще macOS закрытая, а FreeBSD полутруп?
Но говоря про последнее, меня очень привлекает в
io_uring именно возможность удешевления сисколов до почти обычных вызовов [8].Может кто знает, я не интересовался такими
io_uring на то, как обычно делают взаимодействие между компонентами в микроядерных ОС?Но ладно, это неважно, важно, как мне кажется, то что по мере добавления поддержки новых сисколов в
io_uring, возможно из Linux-а вынесут к черту большую часть кернел имплемнатции дров? И будет в кернеле не 20+ млн строк, а хотя бы какая-нибудь парочка)Ладно оставим эти влажные фантазии, надеюсь на какую-то активность в комментах, я старался, а
io_uring классныйНу и за рамками обсуждения осталось, то что никто не мешает прикрутить
io_uring к сокетам и посоревноваться с epoll, но учитывая, что последний итак хорошо работает, как по мне это уже не так интересно.