Обеспечение сброса файла при создании файла во внешнем процессе (Win32) - PullRequest
1 голос
/ 29 ноября 2009

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

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

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

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

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

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

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

Есть идеи?


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Ответы [ 3 ]

3 голосов
/ 29 ноября 2009

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

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

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

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

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

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

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

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

2 голосов
/ 29 ноября 2009

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

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

0 голосов
/ 30 ноября 2009

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

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

...