4.7. Форсирование записи данных на диск

4.7. Форсирование записи данных на диск

Ранее мы описали флаги O_DSYNC, O_RSYNC и O_SYNC для open(). Мы отметили, что использование этих флагов может замедлить программу, поскольку write() не возвращается до тех пор, пока все данные не будут записаны на физический носитель.

Со слегка более высоким уровнем риска мы можем сами испечь свое пирожное и съесть его. Это осуществляется путем открытия файла без указания флагов O_xSYNC, но с последующим использованием одного из следующих двух системных вызовов в любой момент, когда это необходимо для безопасного перемещения данных на физический носитель:

#include <unistd.h>

int fsync(int fd); /* POSIX FSC */

int fdatasync(int fd); /* POSIX SIO */

Системный вызов fdatasync() подобен O_DSYNC: он форсирует запись данных на конечное физическое устройство. Системный вызов fsync() подобен O_SYNC, форсируя запись на физическое устройство не только данных файла, но и вспомогательных данных. Вызов fsync() более переносим; он существовал в мире Unix в течение более продолжительного времени, и вероятность его наличия среди широкого ряда систем больше.

Можно использовать эти вызовы с указателями файлов <stdio.h>, вызвав сначала fflush(), а затем fileno() для получения дескриптора нижележащего файла. Вот функция fpsync(), которая может использоваться для заключения обеих операций в один вызов. Она возвращает в случае успеха 0:

/* fpsync --- синхронизация переменной stdio FILE* */

int fpsync(FILE *fp) {

 if (fp == NULL || fflush(fp) == EOF || fsync(fileno(fp)) < 0)

  return -1;

 return 0;

}

Технически оба этих вызова являются расширениями базового стандарта POSIX: fsync() в расширении «Синхронизация файлов» (FSC), a fdatasync() в расширении «Синхронизированный ввод и вывод». Тем не менее, можно без проблем использовать их в системе GNU/Linux