В настоящее время я реализую схему буферизации ping / pong для безопасной записи файла на диск. Я использую C ++ / Boost на машине Linux / CentOS. Теперь я столкнулся с проблемой принудительной записи файла на диск. Возможно ли это сделать независимо от всех политик кэширования файловой системы (ext3 / ext4) / пользовательских правил SO / контроллера RAID / контроллера жесткого диска?
Лучше всего использовать обычную файловую систему fread () / fwrite (), c ++ ostream или boost?
Я слышал, что простое удаление файла (fflush ()) не гарантирует фактическую запись
fflush (для FILE *), std :: flush (для IOStream) для принудительной отправки вашей программы в ОС.
POSIX имеет
sync (2), чтобы попросить запланировать запись своих буферов, но может вернуться до того, как запись будет завершена (Linux ожидает, что данные будут отправлены на оборудование, прежде чем вернуться).
fsync (2), который гарантированно ожидает отправки данных на оборудование, но нуждается в дескрипторе файла (вы можете получить его из FILE * с помощью fileno (3), я не знаю ни одного стандартного способа получить его из IOStream).
O_SYNC как флаг для открытия (2).
Во всех случаях аппаратное обеспечение может иметь свои собственные буферы (но если оно имеет контроль над ним, хорошая реализация попытается также сбросить их и ISTR, что некоторые диски используют конденсаторы, чтобы они могли сбросить все, что происходит с питанием) и сетевые файловые системы имеют свои собственные предостережения.
Ты можешь использовать FSYNC() /fdatasync() Принудительно (Примечание 1) данные на хранение.
Те требуют файлового дескриптора, как указано, например, открыть().
man-страница linux иметь больше специфической информации для Linux, особенно о разнице fsync и fdatasync.
Если вы не используете дескрипторы файлов напрямую, многие абстракции будут содержать внутренние буферы, находящиеся в вашем процессе.
например если вы используете ФАЙЛ *, сначала вы должны удалить данные из вашего приложения.
//... open and write data to a FILE *myfile
fflush(myfile);
fsync(fileno(myfile));
Не в стандартном C ++. Вам придется использовать какую-то конкретную систему
IO, как open
с O_SYNC
флаг под Unix, а затем write
,
Обратите внимание, что это частично подразумевается тем фактом, что ostream
(И в
C, 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 );
}
(Это было только поверхностно проверено, но основная идея есть.)