Страницы

Поиск по вопросам

суббота, 14 декабря 2019 г.

C#: Файловая транзакция

#c_sharp #net #windows #файловая_система #файлы


Существуют ли в C# средства, которые позволяют делать файловые транзакции?

Например, при копировании файлов вылетает ошибка и все откатывается.
    


Ответы

Ответ 1



Родных средств для этого в C# нет, т.к. для полноценной реализации файловых транзакций, необходимо поддержка на уровне файловой системы и операционной системы. В Microsoft пробовали сделать что-то подобное, однако проект не взлетел. Теоретически, можно попробовать задействовать для подобных целей какую-нибудь систему резервного копирования или реализовать функционал резервирования и восстановления состояния директории самостоятельно. Предполагаемый порядок действий в таком случае: Создаем копию состояния изменяемой директории в архив. Производим необходимые изменения. Если произошла ошибка - откат, восстанавливаем состояние директории из архива. Удаляем архив. Предполагаемые проблемы: Что делать, если возникла ошибка при создании архива для отката? Считаем транзакцию не начатой? Выполняем изменения с риском испортить данные без возможности отката? Что делать, если после ошибки при изменении, возникла ошибка при откате? Что делать, если не достаточно дискового пространства для выполнения всех указанных действий, т.к. при создании архива для отката мы удваиваем используемый объем диска. Да, некоторые файлы хорошо сжимаются, но далеко не все. Плюс, используя сжатие, мы существенно увеличим время создания архива, и выполнение отката, если в нем возникнет необходимость, и добавим еще одно потенциально проблемное место в алгоритм. Не стоит забывать про права доступа к файлам и каталогам. Но это уже отдельная история, тоже довольно запутанная и не имеющая простого решения в общем случае. UPD: По мотивам комментария VladD: Если допустимо в рамках решаемой задачи, можно принять следующее соглашение: По аналогии с базами данных, есть некая рабочая директория для которой реализуется механизм транзакций. В этой дирректории заведомо все правильно, права доступа есть на все операции и т.д. Это можно обеспечить например с помощью инсталятора программы. Любое вмешательство в настройки директории - целенаправленная диверсия. Тогда часть описанных и не описанных выше проблем устраняется, однако остается проблема "электрик Вася", который не вовремя выключил электричество, но попробуем обойти и ее. Рассуждения чисто теоретические, на практике не реализовывал, о недостатках пишите в комментарии. Создаем новую папку со служебным именем. Все операции в рамках транзакции производим в ней. В эту папку первым шагом кладем текстовый файл с планом транзакции, простой список необходимых операций или готовых для выполнения команд. Это позволит проверить что уже сделано, и возобновить работу после вмешательства "электрика Васи". Выполняем транзакцию согласно плану. Если все успешно, переименовываем созданную папку в ChangedDirName-New и перемещаем ее в нужное место. Перемещение в рамках одного физического диска выполняется мгновенно. Переименовываем папку которую должны были менять в рамках транзакции во что-то типа ChangedDirName-Old. Это позволит вернуть все в исходное состояние простым переименованием. Если все успешно, переименовываем ChangedDirName-New в оригинальный ChangedDirName. Если все успешно, удаляем (или архивируем на память) ChangedDirName-Old и удаляем из ChangedDirName план транзакции. Если что-то пошло не так: ошибка при создании папки транзакции - аварийно завершаем транзакцию исключением. ошибка при создании плана транзакции - аварийно завершаем транзакцию исключением, и удаляем папку транзакции. ошибка при выполнении операций транзакции - аварийно завершаем транзакцию исключением, и удаляем папку транзакции. непредвиденное прерывание транзакции (пришел "электрик Вася") - сверяем состояние папки транзакции с планом и продолжаем начатое. Плюсы: изменяемая папка доступна другим частям программы все время выполнения транзакции в неизменном виде. замена папки описанным способом происходит с максимальной, для целевой файловой системы, скоростью. восстановление после сбоя, если вдруг "электрик Вася" окажется снайпером и выключит ток между переименованиями, выполняется простым переименованием, и может быть автоматизировано, если структура папок постоянна. Минусы: много места, и сжатие здесь не спасет в виду отсутствия такового. абсолютно уверен что есть еще не мало, но оставлю на суд критиков.\ По желанию сообщества, первый предложенный вариант может быть удален или оставлен для истории. "электрик Вася" является вымышленным персонажем, все совпадения случайны! =) UPD2 Вспомнил о способе сформировать новую папку из существующих файлов не удваивая их количество. В *NIX системах существует штуковина, которая называется HardLink. Ведет она себя так же, как активная ссылка на объект в .NET, пока есть хоть одна, файл не будет удален. Когда-то давно, обнаружил, что такое есть и в NTFS, только спрятано от простых пользователей. На EnSO практически сразу нашлось решение для создания HardLink-ов. Подробнее тут. Таким образом можно немного изменить предложенные варианты, и заменить реальное копирование файлов, на создание HardLink-ов в папке транзакции, тем самым исключая излишний расход ресурсов, необходимых для копирования. Но, как всегда не без ложки дегтя, этот метод применим только для работы с файлами целиком. Т.е. если нужно частичное изменение файла в транзакции, то все равно придется делать полноценную копию. UPD 3: На просторах сети нашлось реализованное решение файловых транзакций - .NET Transactional File Manager. Проект доступен в виде NuGet-пакета, но последнее обновление было в сентябре 2013. Одно из двух: либо в проекте сделано все возможное, либо он просто заброшен. Второе вероятнее.

Комментариев нет:

Отправить комментарий