Принудительная запись файла на диск

В настоящее время я внедряю схему буферизации ping / pong для безопасной записи файла на диск. Я'используя C ++ / Boost на компьютере с Linux / CentOS. Сейчас я'м, столкнувшись с проблемой, чтобы заставить фактическую запись файла на диск. Возможно ли это сделать независимо от всех политик кэширования файловой системы (ext3 / ext4) / пользовательских правил SO / контроллера RAID / контроллера жесткого диска?

Лучше ли использовать обычную файловую систему fread () / fwrite (), c ++ ostream или boost?

мы слышали, что простое удаление файла (fflush ()) нене гарантирует фактическую запись

Ответы на вопрос(3)

FSYNC() /fdatasync() Принудительно (Примечание 1) данные на хранилище. Те требуют файлового дескриптора, как указано, например, открыть().man-страница linux иметь больше специфической информации для Linux, особенно о разнице fsync и fdatasync.

Если вы неДля непосредственного использования файловых дескрипторов многие абстракции будут содержать внутренние буферы, находящиеся в вашем процессе.

например если вы используете ФАЙЛ *, сначала вы должны удалить данные из вашего приложения.

//... open and write data to a FILE *myfile
fflush(myfile);
fsync(fileno(myfile));
Примечание 1. Эти вызовы заставляют ОС гарантировать, что любые данные в любом кеше ОС записываются на диск, и диск подтверждает этот факт. Многие жесткие диски лгут ОС по этому поводу и могут помещать данные в кэш-память на диске.
 nos13 нояб. 2012 г., 12:03
@G_G Когда тыСделайте с FILE *, чтобы закрыть файл, затем используйте fclose ()
 Gianluca Ghettini13 нояб. 2012 г., 11:47
как насчет fclose ()? нам это нужно, верно?
 Gianluca Ghettini13 нояб. 2012 г., 12:09
извините, я имею в виду при использовании непосредственно файловых дескрипторов; нам нужен явный вызов close (fd)?
 nos14 нояб. 2012 г., 10:32
@G_G Если вы используете FILE *, используйте fclose. Если вы используете файловые дескрипторы, используйте close (). Если ты'вытащив файловый дескриптор из FILE *, у вас все еще есть FILE *, поэтому используйте fclose (который также закроет файловый дескриптор)
Решение Вопроса

: flush (для IOStream) для принудительной отправки вашей программы в ОС.

POSIX имеет

sync (2), чтобы попросить запланировать запись своих буферов, но может вернуться до того, как запись будет завершена (Linux ожидает, что данные будут отправлены на аппаратное обеспечение, прежде чем вернуться).

fsync (2), который гарантированно ожидает отправки данных на оборудование, но нуждается в дескрипторе файла (вы можете получить его из FILE * с помощью fileno (3), я не знаю ни одного стандартного способа получить его из IOStream).

O_SYNC как флаг для открытия (2).

Во всех случаях аппаратное обеспечение может иметь этоs собственные буферы (но если он имеет контроль над ними, хорошая реализация попытается также сбросить их и ISTR, что некоторые диски используют конденсаторы, чтобы они могли сбросить все, что происходит с питанием), и сетевые файловые системы имеют свои собственные предостережения ,

 AProgrammer13 нояб. 2012 г., 10:50
@JoachimPileborg, этоТо, что я намеревался обозначить слишком кратким (f) потоком, япрояснил.
 James Kanze13 нояб. 2012 г., 11:00
sync заставляет системуграфик записи на диск. Это неблокировать, пока они не произошли. Для обеспечения целостности транзакций вам необходимоopen файл сO_SYNCили используйтеfsync (что требует знания файлового дескриптора).
 rubenvb13 нояб. 2012 г., 11:00
@G_G тогда тыне повезло. Решение определенно будет зависеть от ОС, и я считаю, что большинство ОС нене имеют гарантий даже для соответствующих системных вызовов низкого уровня.
 AProgrammer13 нояб. 2012 г., 11:07
@JamesKanze, упс, я посвятил памяти гарантированный подарок для Linux.
 Gianluca Ghettini13 нояб. 2012 г., 11:21
ПРИМЕЧАНИЕ: файл представляет собой небольшой снимок (менее 1 КБ) некоторых важных данных, которые система должна сохранить в случае полного сбоя питания. Система использует его, чтобы восстановитьстатус после такого отключения питания. Данные отбираются и записываются на диск каждую секунду, поэтому не обязательно, чтобы каждая запись выполнялась, но, по крайней мере, она выполняется каждые X секунд с помощью команды let 'скажем, 90% уверенности.
 James Kanze13 нояб. 2012 г., 12:21
Re your edit: Posix гарантирует целостность транзакций дляfsync и еслиO_SYNC флаг используется. Но на практике этоЕдинственная теория. Системадолжен принимать во внимание любую аппаратную буферизацию, насколько это возможно, и хорошо разработанное оборудование сделает это возможным, но не все оборудование разработано правильно. Что касается удаленных файловых систем ... Выправильно предупредить.
 Gianluca Ghettini13 нояб. 2012 г., 10:49
благодарю вас! поэтому я должен сначала принудительно принудить мою программу к файловой системе (fflush / flush), а затем заставить SO зафиксировать на контроллере диска (синхронизация). Можете ли вы показать мне какой-нибудь проверочный код?
 rubenvb13 нояб. 2012 г., 10:52
Я чувствую себя обязанным указать, что ни один из них не гарантирует, что данные физически записываются на диск. Он вполне может присутствовать только в кеше жесткого диска или в других мистических местах внутри вашего компьютера.
 Some programmer dude13 нояб. 2012 г., 10:47
А для потоков C ++ есть манипуляторstd::flush вместо .fflush
 Gianluca Ghettini13 нояб. 2012 г., 10:57
@rubenvb: этоЭто точно моя забота. К сожалению, отключение записи-кэша на RAID-контроллере не вариант из-за большой потери производительности. Более того, решение должно быть только программным.
 James Kanze13 нояб. 2012 г., 12:14
@ AProgrammer Я не знаюне вижу где этоГарантируется даже в Linux. Согласно man-странице для Linux, текущее поведение - ждать (начиная с версии 1.3.20), но это указано в разделе "ошибки», что говорит о том, что это может измениться. (Приходится ждатьвсе выдающиеся записи до конца, вероятно, сделают это очень медленно.)

Придется использовать какой-то системный ввод-вывод, напримерopen сO_SYNC флаг под Unix, а затем.write

Обратите внимание, что это частично подразумевается тем фактом, чтоostream (и в С,FILE*) буферизируются. Если вы нене знаю точно, когда что-то записывается на диск, тогда это неНе имеет смысла настаивать на транзакционной целостности записи. (Это нене слишком сложно спроектироватьstreambuf которыйтолько пишет, когда вы делаете явный сброс, однако.)

РЕДАКТИРОВАТЬ:

В качестве простого примера:

class SynchronizedStreambuf : public std::streambuf
{
    int myFd;
    std::vector<char> myBuffer;

protected:
    virtual int overflow( int ch );
    virtual int sync();

public:
    SynchronizedStreambuf( std::string const& filename );
    ~SynchronizedStreambuf();
};

int SynchronizedStreambuf::overflow( int ch )
{
    if ( myFd == -1 ) {
        return traits_type::eof();
    } else if ( ch == traits_type::eof() ) {
        return sync() == -1 ? traits_type::eof() : 0;
    } else {
        myBuffer.push_back( ch );
        size_t nextPos = myBuffer.size();
        myBuffer.resize( 1000 );
        setp( &myBuffer[0] + nextPos, &myBuffer[0] + myBuffer.size() );
        return ch;
    }
}

int SynchronizedStreambuf::sync()
{
    size_t toWrite = pptr() - &myBuffer[0];
    int result = (toWrite == 0 || write( myFd, &myBuffer[0], toWrite ) == toWrite ? 0 : -1);
    if ( result == -1 ) {
        close( myFd );
        setp( NULL, NULL );
        myFd = -1;
    } else {
        setp( &myBuffer[0], &myBuffer[0] + myBuffer.size() );
    }
    return result;
}

SynchronizedStreambuf::SynchronizedStreambuf( std::string const& filename )
    : myFd( open( filename.c_str(), O_WRONLY | O_CREAT | O_SYNC, 0664 ) )
{
}

SynchronizedStreambuf::~SynchronizedStreambuf()
{
    sync();
    close( myFd );
}
</char>

(Это было только поверхностно проверено, но основная идея есть.)

Ваш ответ на вопрос