Обеспечение сброса файла при создании файла во внешнем процессе (Win32)

Windows Win32 C++ вопрос о сбросе файловой активности на диск.

У меня есть внешнее приложение (запущено с использованием CreateProcess), которое создает файлы. то есть, когда он вернется, он создаст файл с некоторым содержанием.

Как я могу убедиться, что файл, созданный процессом, действительно был записан на диск, прежде чем я продолжу?

Под этим я подразумеваю не буферы C++, а действительно очищающий диск (например, FlushFileBuffers).

Помните, что у меня нет доступа к любому файлу HANDLE - все это, конечно, скрыто во внешнем процессе.

Я думаю, я мог бы открыть свой дескриптор для файла и затем использовать FlushFileBuffers, но не ясно, как это будет работать (так как мой дескриптор на самом деле не содержит ничего, что требует очистки).

Наконец, я хочу, чтобы это выполнялось в пользовательском пространстве без прав администратора, поэтому я не могу использовать FlushFileBuffers для всего тома.

Есть идеи?


ОБНОВЛЕНИЕ: Почему я думаю, что это проблема?

Я работаю над приложением резервного копирования данных. По сути, он должен создать несколько файлов, как описано. Затем он должен обновить свою внутреннюю БД (используя встроенную БД SQLite).

У меня недавно была проблема с повреждением данных, возникшая во время синего экрана (причина которого не была связана с моим приложением).

Меня беспокоит целостность приложения во время сбоя системы. И да, я забочусь об этом, потому что это приложение для резервного копирования данных.

Случай использования, который меня беспокоит, таков:

  1. Небольшой файл данных создается с использованием внешнего процесса. Эта запись ожидает записи в кэш ОС на диск.
  2. Я обновляю БД и фиксирую. Это дисковая активность. Эта запись также ожидает в кеше ОС.
  3. Произошел сбой системы.

На мой взгляд, сейчас мы находимся в состоянии потенциальной гонки. Если "1" сбрасывается, а "2" - нет, то все в порядке (поскольку транзакция с БД не была зафиксирована). Если ни то, ни другое не сбрасывается, или оба сбрасываются, мы тоже в порядке.

Насколько я понимаю, записи будут недетерминированными. т.е. я не в курсе, что ОС гарантированно напишет "1" перед "2". (Я ошибся?)

Итак, если "2" сбрасывается, а "1" - нет, то у нас проблема.

Я заметил, что БД была правильно обновлена, но в файле был мусор: последние две трети данных были двоичными "нулями". Теперь, я не знаю, как это выглядит, когда у вас есть часть файла, сброшенная во время синего экрана, но я не удивлюсь, если бы это выглядело так.

Могу ли я гарантировать, что это причина? Нет, я не могу этого гарантировать. Я просто размышляю. Возможно, файл был "естественно" поврежден из-за сбоя диска или из-за синего экрана.

Что касается производительности, то я верю, что могу с этим справиться.

Например, стандартным поведением SQLite является полная очистка файла (с использованием FlushFileBuffers) каждый раз, когда вы совершаете транзакцию. Они совершенно ясно, что если вы этого не сделаете, то во время сбоя системы вы можете иметь поврежденную БД.

Кроме того, я считаю, что могу снизить производительность, только сбрасывая на "контрольных точках". Например, запись 50 файлов, очистка лота и запись в БД.

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

Надеюсь, это объясняет, почему я не хочу этого делать.

3 ответа

Зачем тебе это? ОС будет следить за тем, чтобы данные были сброшены на диск своевременно. Если вы получите к нему доступ, он вернет данные из кеша или с диска, так что это прозрачно для вас.

Если вам нужна безопасность в случае бедствия, вы должны позвонить FlushFileBuffersНапример, путем создания процесса с правами администратора после запуска внешнего процесса. Но это может серьезно повлиять на производительность всей машины.

Ваш единственный вариант - изменить источник другого процесса.

[РЕДАКТИРОВАТЬ] Самое простое решение, вероятно, состоит в том, чтобы скопировать файл в вашем процессе, а затем очистить копию (так как у вас есть дескриптор). Сохраните копию под именем, которое гласит "не зафиксировано в базе данных".

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

Сбросить базу данных на диск.

Переименуйте файл в "Файл был обработан в базу данных". Переименование - это атомарная операция (так бывает или нет).

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

Ну, здесь нет привлекательных вариантов. Не существует документированного способа получить дескриптор файла, который вам нужен из процесса. Хотя есть и недокументированные, заходите туда (через DuplicateHandle) только с тщательным рассмотрением.

Да, вызов FlushFileBuffers для дескриптора тома является документированным способом. Вы можете избежать проблемы с привилегиями, разрешив службе выполнить вызов. Поговорите с ним из своего приложения с помощью одного из стандартных механизмов взаимодействия процессов. Именованный канал, чье имя имеет префикс Global\, вероятно, самый простой способ добиться этого.

Я думаю, что после вашего обновления http://sqlite.org/atomiccommit.html даст вам ответы на ваши вопросы.

Способ, которым SQLite гарантирует, что все записано на диск, работает. Так что это работает и для вас - взгляните на источник.

Другие вопросы по тегам