Атомное удаление для большого количества файлов - PullRequest
5 голосов
/ 26 октября 2009

Я пытаюсь удалить 10000+ файлов одновременно, например, атомарно. либо все должны быть удалены сразу, либо все должны оставаться на месте.

Конечно, очевидный ответ - переместить все файлы во временный каталог и рекурсивно удалить его, но это удваивает количество требуемого ввода-вывода.

Сжатие не работает, потому что 1) я не знаю, какие файлы нужно будет удалить, и 2) файлы нужно часто редактировать.

Есть ли что-нибудь, что может помочь снизить стоимость ввода-вывода? Подойдет любая платформа.

РЕДАКТИРОВАТЬ: давайте предположим, что отключение питания может произойти в любое время.

Ответы [ 9 ]

13 голосов
/ 26 октября 2009

Кибби прав: вы ищете транзакцию. Однако вам не нужно зависеть ни от баз данных, ни от специальных функций файловой системы, если вы этого не хотите. Суть сделки заключается в следующем:

  1. Запишите запись в специальный файл (часто называемый «журнал»), в котором перечислены файлы, которые вы собираетесь удалить.
  2. Как только эта запись будет благополучно написана, убедитесь, что ваше приложение работает так же, как если бы файлы были фактически удалены.
  3. Позже начните удалять файлы, указанные в записи транзакции.
  4. После удаления всех файлов удалите запись транзакции.

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

Обратите внимание, что вы не должны идти по этому пути слишком далеко: в противном случае вы начинаете переопределять реальную систему транзакций. Тем не менее, если вам нужно всего лишь несколько простых транзакций, подход по принципу «накатить» может быть приемлемым.

6 голосов
/ 26 октября 2009

В * nix перемещение файлов в пределах одной файловой системы - операция очень дешевая, она работает путем создания жесткой ссылки на новое имя и последующего удаления исходного файла. Он даже не меняет время файла.

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

Вы уверены, что не хотите просто базу данных? Все они имеют встроенные транзакции фиксации и отката.

5 голосов
/ 26 октября 2009

Я думаю, что вы действительно ищете возможность совершить сделку. Поскольку диск может записывать только один сектор за раз, вы можете удалять файлы только по одному за раз. Что вам нужно, это возможность откатить предыдущие удаления, если одно из удалений не произошло успешно. Такие задачи обычно зарезервированы для баз данных. Может ли ваша файловая система выполнять транзакции, зависит от того, какую файловую систему и ОС вы используете. NTFS в Windows Vista поддерживает Транзакционный NTFS . Я не слишком уверен в том, как это работает, но это может быть полезно.

Также для Windows существует нечто, называемое shadow copy , которое в мире Linux называется LVM Snapshot . По сути, это моментальный снимок диска. Вы можете сделать моментальный снимок непосредственно перед выполнением удаления, и, если он окажется неудачным, скопируйте файлы обратно из моментального снимка. Я создал теневые копии с использованием WMI в VBScript, я уверен, что аналогичные API существуют и для C / C ++.

Одна вещь о Shadow Copy и LVM Snapsots. Работа на весь раздел. Таким образом, вы не можете сделать снимок только одного каталога. Однако создание снимка всего диска занимает всего пару секунд. Таким образом, вы бы сделать снимок. Удалите файлы, а затем, в случае неудачи, скопируйте файлы обратно из снимка. Это будет медленно, но в зависимости от того, как часто вы планируете откат, это может быть приемлемо. Другая идея - восстановить весь снимок. Это может или не может быть хорошо, так как это откатит все изменения на всем диске. Не хорошо, если ваша ОС или другие важные файлы находятся там. Если этот раздел содержит только файлы, которые вы хотите удалить, восстановление всего снимка может быть проще и быстрее.

2 голосов
/ 26 октября 2009

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

Когда вы запускаете приложение, оно должно проверить наличие to_be_deleted.log и, если оно есть, воспроизвести удаления в этом файле (игнорируя ошибки "не существует").

2 голосов
/ 26 октября 2009

Вместо перемещения файлов сделайте символические ссылки во временный каталог. Затем, если все в порядке, удалите файлы. Или просто составьте список файлов где-нибудь, а затем удалите их.

1 голос
/ 26 октября 2009

Основной ответ на ваш вопрос - «Нет». Более сложный ответ заключается в том, что для этого требуется поддержка файловой системы, и очень немногие файловые системы имеют такую ​​поддержку. Очевидно, NT имеет транзакционную FS, которая поддерживает это. Вполне возможно, что BtrFS для Linux также будет поддерживать это.

В отсутствие прямой поддержки, я думаю, что вариант hardlink, move, remove - лучшее, что вы получите.

1 голос
/ 26 октября 2009

В Windows Vista или новее Транзакционная NTFS должна делать то, что вам нужно:

HANDLE txn = CreateTransaction(NULL, 0, 0, 0, 0, NULL /* or timeout */, TEXT("Deleting stuff"));
if (txn == INVALID_HANDLE_VALUE) {
  /* explode */
}
if (!DeleteFileTransacted(filename, txn)) {
  RollbackTransaction(txn); // You saw nothing.
  CloseHandle(txn);
  die_horribly();
}
if (!CommitTransaction(txn)) {
  CloseHandle(txn);
  die_horribly();
}
CloseHandle(txn);
1 голос
/ 26 октября 2009

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

Если условие «правильное» для удаления файлов, измените состояние на «удаленное» в слое абстракции и начните фоновое задание, чтобы «действительно» удалить их из файловой системы.

Конечно, это предложение связано с определенными затратами при открытии / закрытии файлов, но экономит некоторые операции ввода-вывода при создании символической ссылки и т. Д.

1 голос
/ 26 октября 2009

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

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

...