LINUX.ORG.RU

FILE* для буфферизированного доступа. Дёргать write(2) на каждые несколько записанных байт крайне медленно.
Ну и write(2) когда нужно произвести одну операцию записи на дескриптор

mittorn ★★★★★
()

Первые, чтобы эта libc’шная кривожопая буферизация не мешалась под ногами, и чтобы не пользоваться API придуманным идиотами, например вспоминать какой режим для fopen что значит, и достаточно ли вызвать fflush перед закрытием записываемого файла.

anonymous
()

зависит от задачи. выше уже написали про буферизацию. а иногда и mmap нужно применять, для большей эффективности. если же просто в небольшой файл писать, то достаточно fopen/fwrite/fseek и же с ними. это часть стандарта С. прочие реализации могут зависеть от платформы.

Iron_Bug ★★★★★
()
Последнее исправление: Iron_Bug (всего исправлений: 1)

я обычно FILE. А в целом без разницы, потому что они во-первых конвертируются друг в друга, во-вторых, по-хорошему конечно лучше использовать mmap, если возможно. А еще лучше - dio через какой-нибудь io_uring, а еще лучше - купить специальное железо с поддержкой ZNS :))

Lrrr ★★★★★
()

Из этих двух - сисколлы с fd. Для некоторых частных случаев (печать логов и других append-only потоков данных в файл, или построчное чтение файла) - свои обёртки.

firkax ★★★★★
()
Ответ на: комментарий от mittorn

Дёргать write(2) на каждые несколько записанных байт крайне медленно.

write() гарантирует что данные попадут в page cache ярда. А попадут ли данные физически на диск – зависит от ядра и файловой системы. Даже вызов fsync() / fdatasync() не гарантируют, что данные физически окажутся на диске. К примеру, на ZFS данные попадут в ZIL. Фактически сброс на диск произойдёт позже, в рамках транзакционного commit’а.

iron ★★★★★
()
Ответ на: комментарий от iron

Да, использование сисколов не гарантирует что буфферизации не будет и данные попадут на диск. Но зато гарантирует, переключение в ядро с соответствующим оверхедом. На мелких порциях данных это может понизить производительность в десятки раз и оверхед от аллокации буффера для stdio на фоне этого окажется незначительным.
Ну и не стоит забывать, что stdio - стандартный для си, а вот open/read/write - только в рамках posix и на не-posix системах могут отсутствовать или вести себя иначе (в windows это скорее совместимость с dos, а не posix)

mittorn ★★★★★
()
Последнее исправление: mittorn (всего исправлений: 1)
Ответ на: комментарий от iron

Даже вызов fsync() / fdatasync() не гарантируют

Гарантируют, иначе приложение надёжно записывающее данные сделать было бы принципиально невозможно.

К примеру, на ZFS данные попадут в ZIL

А ZIL где, по-твоему, не на диске?

anonymous
()

90% случаев с FILE *, читать, форматировано писать, перемещаться по файлу, всё что нужно, есть, это просто удобно и не накладно. Дескрипторы, редко, если они изначально явно нужны, или требуется в них «сконвертировать», настолько редко что каждый раз в справку лезу.

LINUX-ORG-RU ★★★★★
()

Юзаем open(), close(), write(), read() на базе int fd. Буфферизацию реализуем своими средствами, так как-то нативнее и кошернее и понятнее. Обычно слой, который хочет записывать в файл, отдаёт уже цепочки блоков по 4 КБ или длиннее, так что проблем нет. Буфферизация в серьёзном приложении всегда какая-то реализована, потому что иначе бы у нас получилась зависимость от библиотеки, которая даёт доступ к файлу. От библиотеки требуется минимум фич - никаких там буферов, а прямой сискол и все довольны. Условно, мы делаем что-то типа MySQL, а там чтение целыми страницами да и записи то же, но обычно более длинными кусками и в самой софтине есть «кеш страниц» и короче всё в страницах меряется и пишется, ничего меньше страницы читать ниоткуда смысла никогда нет. А чаще и десятками мегабайт. Нахрен все эти буферизованые fopen() не уссались нам. Так в целом как-то проще и понятнее жить - не зависишь от буферов в библиотеке, знаешь что их там просто нет. Ну и не факт, что политика «буферирования» внутри libc-шного fread() прям очень оптимальна для твоей приложеньки.

lesopilorama
()
Последнее исправление: lesopilorama (всего исправлений: 3)
Ответ на: комментарий от iron

fsync()

Про эту штуку я привык думать не более чем как про fence, ну типа барьер - никакие write() после fsync() не будут на диске раньше, чем те write() которые были до fsync()… Возможно это правильное понимание.

lesopilorama
()
Ответ на: комментарий от lesopilorama

Про эту штуку я привык думать не более чем как про fence, ну типа барьер - никакие write() после fsync() не будут на диске раньше, чем те write() которые были до fsync()… Возможно это правильное понимание.

Нигде даже намека на такие гарантии не видел.

urxvt ★★★★★
()
Ответ на: комментарий от urxvt

Нигде даже намека на такие гарантии не видел.

Я не думаю что они хоть где-то есть - слишком дорого. А тот кто пишет в те же блоки что другой процесс / поток в это время пытается засинкать - ну что ж, ССЗБ.

bugfixer ★★★★★
()
Ответ на: комментарий от anonymous

Я читал тут

https://www.opennet.ru/man.shtml?topic=fsync&category=2&russian=0

В случае если у жёсткого диска разрешена запись кэша, данные могут фактически не быть сохранены после выполнения fsync/fdatasync.

u5er ★★★
() автор топика
Ответ на: комментарий от urxvt

Нигде даже намека на такие гарантии не видел.

Ну это вообще минимально разумные гарантии. fsync() обычно по-сути ради них и вызывают (в мире движков СУБД, например). Если он прям на диск физически ничего не запишет, то хотя-бы эту гарантию даст, её хватит всем как 640 кб. Чтобы НЕ начинать запись чего-то, что требует наличия уже чего-то другого записанного на диск - ведь fsync() логически вызывают именно ради этого, не для чего-то ещё. Нет, ещё бывает что от fsync() хотят прям типа гарантии «записалось» в банках, чтобы если три разных сервера физически записали что-то, то можно клиенту отвечать что бабло перевелось - но там и железо специальное, где все мамой поклялись, что между fsync и железом есть взаимопонимание. Да и вообще банки строят свои IT-решения скорее вокруг термина «последовательно», а не термина «гарантированно записалось». Ну всмысле, сохранение порядка операций важнее, чем их сохранность. Реальное состояние бабла всё равно подбивают по ночам последовательным перепрочитыванием логов, а не прямо сразу в базе днём во время перевода денег.

lesopilorama
()
Последнее исправление: lesopilorama (всего исправлений: 5)
Ответ на: комментарий от bugfixer

А тот кто пишет в те же блоки что другой процесс / поток в это время пытается засинкать - ну что ж, ССЗБ.

Какие блоки? Блоки диска что-ли физические? Речь вообще не про это. Если в одни и те же блоки диска кто-то пытается писать «параллельно», то это уже дурка по определению, race condition называется и просто психи, тут fsync уже не поможет, только морг

lesopilorama
()
Последнее исправление: lesopilorama (всего исправлений: 1)
Ответ на: комментарий от lesopilorama

У тебя каша в голове. Нельзя никакие надёжные хранилища строить на fsync который «прям на диск физически ничего не запишет». СУБД, к тому моменту когда возвращает клиенту успешный ответ на COMMIT, обязана данные положить в надёжное хранилище, а это только fsync() == 0. Иначе, условно, клиенту вернётся подтверждение что деньги переведены, он отгрузит товар покупателю, а у СУБД мигнёт свет и окажется что никаких денег никуда не поступало. Вот с такими свойствами fsync будет барьером и на нём можно строить гарантии последовательности, но это всего лишь следствие из основного и единственного свойства.

anonymous
()
Ответ на: комментарий от lesopilorama

Если в одни и те же блоки диска кто-то пытается писать «параллельно»,

Почему параллельно? Поток 1 записал что-то, и ушёл в fsync()/fdatasync(). Второй поток в это время начинает писать в те же блоки (офсеты в файле). Race здесь нет, а вот неопределённость что будет на диске на выходе из fsync() - есть.

bugfixer ★★★★★
()
Ответ на: комментарий от anonymous

особо хитрожопые СУБД имеют свои драйвера работы с дисками. первыми в этом деле были Oracle, насколько я помню. сейчас, наверное, есть и другие базы, которые это делают. диски сами по себе тоже могут быть хитрожопыми, со всякими там снимками состояний и прочего.

но так просто вот чтобы на сто процентов гарантировать запись на винт из любого ЯП - это нереально. слишком много слоёв абстракции. сам файл может быть отображён в память, или оказаться оверлеем, например. в общем, много всяких нюансов.

а с переводами денег всё более надёжно: там везде «двойная бухгалтерия», по сути. ведутся квитки подтверждения транзакций на двух сторонах и потом сверяются. чтобы на двух сторонах сразу свет одновременно моргнул - это маловероятно.

Iron_Bug ★★★★★
()
Последнее исправление: Iron_Bug (всего исправлений: 2)
Ответ на: комментарий от Iron_Bug

особо хитрожопые СУБД имеют свои драйвера работы с дисками

Какая разница? Интерфейс с системой и требования к нему всегда одни и те же.

диски сами по себе тоже могут быть хитрожопыми, со всякими там снимками состояний и прочего.

Какая разница? Интерфейс с дисками и интерфейс с ними всегда один и тот же.

anonymous
()
Ответ на: комментарий от anonymous

разница в том, что база подгребает под себя весь путь от получения данных до физической записи на винт. но, конечно, это не поможет от внезапного вырубания сервера. хотя у серверов обычно есть УПСы и прочее на этот случай, чтобы успеть сохранить несохранённое. а у совсем важных серверов есть резервные системы питания.

интерфейс тоже может быть «не один и тот же», если ты лезешь через свой драйвер, например.

Iron_Bug ★★★★★
()
Ответ на: комментарий от anonymous

нормальные
нормальном

Получаешь клоуна за использование этого слова без указания керитериев.

теперь или и почитай нормальные маны на нормальном языке

https://man7.org/linux/man-pages/man2/fsync.2.html
https://man.archlinux.org/man/fsync.2.ru

$ man 2 fsync

...
HISTORY
       POSIX.1-2001, 4.2BSD.

       In Linux 2.2 and earlier, fdatasync() is equivalent to fsync(), and so
       has no performance advantage.

       The fsync() implementations in older kernels and lesser used
       filesystems do not know how to flush disk caches.  In these cases disk
       caches need to be disabled using hdparm(8) or sdparm(8) to guarantee
       safe operation.

       Under AT&T UNIX System V Release 4 fd needs to be opened for writing.
       This is by itself incompatible with the original BSD interface and
       forbidden by POSIX, but nevertheless survives in HP-UX and AIX.
...

Так или иначе, приписка про тонкость с кешем есть во всех манах.

u5er ★★★
() автор топика
Последнее исправление: u5er (всего исправлений: 1)