Прерываемый алгоритм сортировки на месте - PullRequest
13 голосов
/ 07 сентября 2010

Мне нужно написать программу сортировки на C, и было бы неплохо, если бы файл мог быть отсортирован на месте для экономии места на диске. Данные являются ценными, поэтому я должен убедиться, что в случае прерывания процесса (ctrl-c) файл не будет поврежден. Я могу гарантировать, что шнур питания на машине не будет выдернут.

Дополнительные сведения: файл ~ 40 ГБ, записи 128-битные, машина 64-битная, ОС POSIX

Любые намеки на выполнение этого или заметки в целом?

Спасибо!

Чтобы уточнить: Я ожидаю, что пользователь захочет Ctrl-C процесс. В этом случае я хочу выйти изящно и убедиться, что данные в безопасности. Таким образом, этот вопрос касается обработки прерываний и выбора алгоритма сортировки, который можно быстро свернуть при необходимости.

После (2 года спустя): Просто для потомков я установил обработчик SIGINT, и он отлично работал. Это не защищает меня от сбоя питания, но это риск, с которым я могу справиться. Код в https://code.google.com/p/pawnsbfs/source/browse/trunk/hsort.c и https://code.google.com/p/pawnsbfs/source/browse/trunk/qsort.c

Ответы [ 6 ]

12 голосов
/ 07 сентября 2010

Джерри прав, если вас беспокоит только Ctrl-C, вы можете игнорировать SIGINT в течение некоторого времени. Если вы хотите быть доказательством против процесса смерти в целом, вам нужно какое-то минимальное ведение журнала. Чтобы поменять местами два элемента:

1) Добавить запись в управляющую структуру в конце файла или в отдельный файл, указав, какие два элемента файла вы собираетесь поменять местами, A и B.

2) Скопируйте A в пустое пространство, запишите, что вы сделали, очистите.

3) Скопируйте B поверх A, затем запишите в пустом месте, что вы сделали, очистите

4) Копировать с нуля пространство над B.

5) Удалить запись.

Это O (1) дополнительное пространство для всех практических целей, поэтому оно по-прежнему считается на месте в большинстве определений. В теории при записи индекс равен O (log n), если n может быть сколь угодно большим: в действительности это очень маленький журнал n, и разумное аппаратное / рабочее время ограничивает его до 64.

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

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

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

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

Судя по вашим разъяснениям, вам не понадобятся операции очистки даже при сортировке на месте. Вам нужно пространство памяти в памяти, которое работает таким же образом, и к которому ваш обработчик SIGINT может получить доступ, чтобы обеспечить безопасность данных до выхода , а не восстановление при запуске после аварийного выхода и вам необходимо получить доступ к этой памяти безопасным для сигнала способом (что технически означает использование sig_atomic_t для обозначения внесенных изменений). Тем не менее, вам, вероятно, лучше с сортировкой слиянием, чем с сортировкой по месту.

5 голосов
/ 07 сентября 2010

Установите обработчик для SIGINT, который просто устанавливает флаг «процесс должен скоро завершиться».

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

5 голосов
/ 07 сентября 2010

Компонент защиты от ctrl-c довольно прост: signal(SIGINT, SIG_IGN);.

Что касается самой сортировки, сортировка слиянием обычно работает для внешней сортировки.Основная идея - прочитать как можно больше записей в память, отсортировать их, а затем записать обратно на диск.Безусловно, самый простой способ справиться с этим - записать каждый прогон в отдельный файл на диске.Затем вы объединяете их вместе - читаете первую запись каждого запуска в память и записываете наименьшую из них в исходный файл;прочитайте другую запись из прогона, который предоставил эту запись, и повторяйте, пока не закончите.Последний этап - это единственный раз, когда вы модифицируете исходный файл, так что это единственный раз, когда вам действительно нужно убедиться в прерываниях и тому подобном.

Другая возможность - использовать сортировку выбора.Плохо то, что сама сортировка идет довольно медленно.Хорошим моментом является то, что написать его довольно просто, чтобы пережить практически все, не занимая много дополнительного пространства.Общая идея довольно проста: найдите наименьшую запись в файле и поменяйте ее местами на первое место.Затем найдите наименьшую запись того, что осталось, и поменяйте местами во второе место, и так далее, пока не закончите.Хорошим моментом является то, что ведение журнала тривиально: перед тем, как выполнить своп, вы записываете значения двух записей, которые собираетесь поменять.Поскольку сортировка выполняется от первой записи до последней, единственное, что вам нужно отслеживать, - это сколько записей уже отсортировано в любой момент времени.

3 голосов
/ 07 сентября 2010

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

0 голосов
/ 07 сентября 2010

Предполагая, что 64-битная ОС (вы сказали, что это 64-битная машина, но все еще может работать на 32-битной ОС), вы можете использовать mmap для сопоставления файла с массивом, а затем использовать qsort для массива.

Добавьте обработчик для SIGINT для вызова msync и munmap, чтобы приложение могло реагировать на Ctrl-C без потери данных.

0 голосов
/ 07 сентября 2010

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

...