Я занимаюсь разработкой автономных систем управления и анализа для тяжелой промышленности. Использую язык C (C99-C11). Очень беспокоит вопрос повреждения файлов и файловых систем, использующихся в Windows (Embedded, CE и пр.) при внезапном обесточивании или при жестком прерывании рабочего процесса/потока, например из-за исключения.
Хотелось бы разобраться в этом вопросе, достойной литературы по этой теме найти не удалось. Посоветуйте что-нибудь, желательно не на английском языке. Или, может быть, кто-нибудь сможет упрощенно объяснить следующее:
Ясное дело, если мы открыли файл и пишем в него, и в этот момент происходит отключение питание, или возникает фатальное исключение в одном из потоков процесса, то операция прерывается на полпути. Это практически гарантированно приводит к повреждению файла/файловой системы в том районе, где происходит работа.
Но ведь даже если мы не работаем с файлом, а в этот момент отключается питание, файл может быть поврежден из-за того, что ОС в фоновом режиме занимается дефрагментацией/индексацией. Это так?
Есть ли гарантия, что после возврата управления в программу после функций fclose()
или fwrite()
данные гарантированно корректно занесены на носитель?
Например, ситуация:
Я предполагал защитить файл критической секцией, и использовать эту же критическую секцию для инициации аварийного завершения. Тогда, предположительно, после того как работа с файлом закончится, критическая секция освободится, и второй поток сможет в нее зайти и вызвать abort()
или аналогичную функцию планируемого жесткого прерывания процесса.
Проблема на мой взгляд в том, что даже после того, как мы сделали fopen()
+ fwrite()
+ fclose()
, нет гарантий, что файл корректно сохранен, а не гуляет где-то в буферах, которые связаны с нашим процессом.
И как контролируется процесс переноса данных из внутреннего промежуточного буфера-кэша жесткого диска на сам носитель?
Например, файл записан и закрыт, и даже процесс, который все это делал, уже закрыт. Но данные частично или полностью еще находятся во внутреннем буфере-кэше накопителя. Если в этот момент произойдет обрыв питания, то данные, я почти уверен, будут повреждены или уничтожены.
Как ОС отслеживает перед своим завершением факт того, что данные из буфера накопителя записаны окончательно?
Но ведь даже если мы не работаем с файлом, а в этот момент отключается питание, файл может быть поврежден из-за того, что ОС в фоновом режиме занимается дефрагментацией/индексацией. Это так?
Во-первых, сомневаюсь, что драйвер самостоятельно будет дефрагментировать что-либо (хотя и не буду утверждать обратное), а отсутствие насущности проблемы фрагментации объясняется в первую очередь грамотными алгоритмами выбора блоков для хранения файлов.
А критические, неустранимые ошибки ФС в таких случаях — это практически невероятный сценарий (скажем, внезапный отказ HDD — куда более вероятен). Но повреждения данных (файлов) с которыми велась активная работа в момент отказа — штатная ситуация.
2) Есть ли гарантия, что после возврата управления в программу после функций fclose() или fwrite() данные гарантированно корректно занесены на носитель?
Нет.
fwrite ()
гарантирует только занесение данных в пользовательский буфер, но не гарантирует, что эти данные будут переданы ОС. Чтобы принудительно сбросить пользовательский буфер есть функция fflush ()
. При скоропостижной кончине процесса данные могут быть потеряны.fclose ()
и fflush ()
сбрасывают пользовательский буфер, но не гарантируют, что ОС передаст данные на носитель. Если процесс умрёт после их возврата, то изменения не потеряются, но они могут быть потеряны в случае внезапного отключения питания.3) И как контролируется процесс переноса данных из внутреннего промежуточного буфера-кэша жесткого диска на сам носитель?
fsync ()
. Он гарантирует, что вернёт управление (само собой без ошибки) только после того как данные физически попадут на диск и переживут внезапный отказ системы. В Win API аналогом FlushFileBuffers ()
, согласно документации он сбрасывает системные буферы, но, гарантирует ли сброс буферов самого HDD или нет, я не знаю.Как ОС отслеживает перед своим завершением факт того, что данные из буфера накопителя записаны окончательно?
Просто посылает определённую команду HDD. Например, в ATA она так и называется, FLUSH CACHE
, опкод E7h
. (здесь должен быть ещё десяток оговорок, которые должны быть интересны только разработчикам драйверов)
FILE_FLAG_NO_BUFFERING
при вызове функции CreateFile()
. Способ имеет два минуса
FlushFileBuffers()
FILE_FLAG_WRITE_THROUGH
, но не все устройства этот флаг поддерживаютЕще один способ решения проблемы, это писать не в оригинальный файл, а в его копию. А после завершения записи вызывать функцию ReplaceFile()
и заменять исходный файл.
В одной системе у меня используется два идентичных файла данных и к каждому файлу в отдельном файле лежит контрольная сумма. Запись файлов идет в такой последовательности:
По старту системы я считываю основной файл и проверяю его контрольную сумму. Если совпало — работаем. Если нет — эту пару удаляем и проверяем копию.
А вообще все упирается в ценность спасаемых данных. В одной системе мы легко можем потерять базу, восстановить ее из чистого бэкапа и работать. А в другой не спасли ни упсы ни рейды. Экскаватор во дворе зацепил силовой кабель и серверная погибла. Правда в саппорте (вроде тогда еще Dell) сказали ничего не трогать, через неделю приехали специалисты и данные подняли.
Кофе для программистов: как напиток влияет на продуктивность кодеров?
Рекламные вывески: как привлечь внимание и увеличить продажи
Стратегії та тренди в SMM - Технології, що формують майбутнє сьогодні
Выделенный сервер, что это, для чего нужен и какие характеристики важны?
Современные решения для бизнеса: как облачные и виртуальные технологии меняют рынок
Есть программа на c++, которая генерирует зашифрованное сообщение и выводит в файл и консольПрограмма на c# должна эти данные выводить на winforms
В WM_PAINT рисуется Rectangle (GDI+)Как изменить толщину края Rectangle когда курсор наведен на него и вернуть обратно когда нет? Изначально толщину задаю...