Некоторые программы копирования файлов любят rsync
и curl
могут возобновлять неудачные операции передачи / копирования.
Отмечая, что может быть много причин этих сбоев, в некоторых случаях программа может выполнить «очистку», а в некоторых случаях - нет.
Когда эти программы возобновляют работу, они, похоже, просто рассчитывают размер файла / данных, которые были успешно переданы, и просто начинают читать следующий байт из источника и добавлять его к фрагменту файла.
например, размер фрагмента файла, «сделавшего его» по назначению, составляет 1378 байт, поэтому они просто начинают чтение с байта 1379 оригинала и добавляют его к фрагменту.
Мой вопрос заключается в том, что, зная, что байты состоят из битов, а не во всех файлах данные сегментированы на куски чистого байтового размера, откуда эти программы знают, что точка, к которой они решили добавить данные, верна?
При записи файла назначения происходит ли какая-либо буферизация или «транзакции», аналогичные базам данных SQL, на уровне программы, ядра или файловой системы, чтобы гарантировать, что только чистые, правильно сформированные байты попадают в базовое блочное устройство?
Или программы предполагают, что последний байт будет потенциально неполным, поэтому они удаляют его в предположении, что он плохой, перезаписывают байт и начинают добавление оттуда?
зная, что не все данные представлены в байтах, эти предположения кажутся неверными.
Когда эти программы «возобновляются», как они узнают, что запускаются в нужном месте?
head -c 20480 /dev/zero | strace -e write tee foo >/dev/null
и ОС будет их буферизовать и отправлять на диск еще большими кусками.fwrite()
?Ответы:
Для ясности - реальная механика более сложна для обеспечения еще большей безопасности - вы можете представить себе операцию записи на диск следующим образом:
Если процесс прерывается в (1), вы ничего не получаете на диске, файл не поврежден и урезан в предыдущем блоке. Вы отправили 5000 байт, только 4096 находятся на диске, вы перезапустите передачу со смещением 4096.
Если в (2), ничего не происходит, кроме как в памяти. То же, что (1). Если в (3) данные записываются, но никто не помнит об этом . Вы отправили 9000 байт, 4096 записано, 4096 записано и потеряно , остальное просто потеряно. Передача возобновляется по смещению 4096.
Если в (4) данные должны были быть зафиксированы на диске. Следующие байты в потоке могут быть потеряны. Вы отправили 9000 байт, 8192 записаны, остальное потеряно, передача возобновляется со смещением 8192.
Это упрощенный вариант. Например, каждая «логическая» запись на этапах 3-4 не является «атомарной», но порождает другую последовательность (нумероваем ее как № 5), в результате чего блок подразделяется на подблоки, подходящие для устройства назначения (например, жесткого диска) ) отправляется на хост-контроллер устройства, который также имеет механизм кэширования , и, наконец, сохраняется на магнитном диске. Эта подпоследовательность не всегда полностью находится под контролем системы, поэтому отправка данных на жесткий диск не является гарантией того, что они действительно были записаны и могут быть прочитаны обратно.
Некоторые файловые системы реализуют журналирование , чтобы гарантировать, что наиболее уязвимая точка (4) фактически не уязвима, путем записи метаданных в, как вы уже догадались, транзакциях, которые будут работать согласованно независимо от того, что происходит на этапе (5).
Если система получает сброс в середине транзакции, она может возобновить свой путь к ближайшей неповрежденной контрольной точке. Записанные данные все еще теряются, как и в случае (1), но возобновление позаботится об этом. Никакая информация на самом деле не теряется.
источник
fsync
) и контроллер жесткого диска (часто не работающий даже на предположительно «корпоративных» дисках). Безfsync
многих файловых операций, которые интуитивно упорядочены и атомарны, POSIX не гарантирует, что файлы, открытые с помощью,O_APPEND
могут вести себя иначе, чем без и т. Д. На практике наиболее важными ключами для согласованности файлов являются система ядра VFS и дисковый кэш. Все остальное в основном пух.Примечание: я не смотрел на источники
rsync
или любую другую утилиту передачи файлов.Это тривиально написать программу на C, которая переходит в конец файла и получает позицию этого местоположения в байтах.
Обе операции выполняются одним вызовом стандартной библиотечной функции языка Си
lseek()
(lseek(fd, 0, SEEK_END)
возвращает длину файла, открытого для файлового дескриптораfd
, в байтах).Как только это будет сделано для целевого файла, подобный вызов
lseek()
может быть сделан на исходный файл , чтобы перейти в соответствующее положение:lseek(fd, pos, SEEK_SET)
. Передача может затем продолжаться в этой точке, при условии, что более ранняя часть исходного файла была идентифицирована как неизмененная (разные утилиты могут делать это по-разному).Файл может быть фрагментирован на диске, но файловая система обеспечит, чтобы приложение восприняло файл как последовательную последовательность байтов.
Что касается обсуждения в комментариях о битах и байтах: наименьшая единица данных, которая может быть записана на диск, - это байт . Один байт требует, чтобы на диске был размещен хотя бы один блок данных. Размер блока зависит от типа файловой системы и, возможно, также от параметров, используемых администратором при инициализации файловой системы, но обычно он находится между 512 байтами и 4 КиБ. Операции записи могут быть буферизованы ядром, базовой библиотекой C или самим приложением, и фактическая запись на диск может происходить в виде кратных значений соответствующего размера блока в качестве оптимизации.
Невозможно записать отдельные биты в файл, и если операция записи завершится неудачей, она не оставит в файле «наполовину записанные байты».
источник
Это в основном два вопроса, потому что такие программы, как curl и rsync, очень разные.
Для клиентов HTTP, таких как curl, они проверяют размер текущего файла и затем отправляют
Content-Range
заголовок со своим запросом. Сервер либо возобновляет отправку диапазона файла, используя код состояния206
(частичное содержимое) вместо200
(успех), и загрузка возобновляется, либо игнорирует заголовок и начинается с начала, и у HTTP-клиента нет другого выбора, кроме повторной загрузки всего опять таки.Кроме того, сервер может отправлять или не отправлять
Content-Length
заголовок. Возможно, вы заметили, что некоторые загрузки не показывают процент и размер файла. Это загрузки, когда сервер не сообщает клиенту длину, поэтому клиенту известно только количество загруженного файла, но не количество байтов.Использование
Content-Range
заголовка с начальной и конечной позициями используется некоторыми менеджерами загрузки для одновременной загрузки файла из разных источников, что ускоряет передачу, если каждое зеркало само по себе медленнее, чем ваше сетевое соединение.С другой стороны, rsync - это расширенный протокол для инкрементной передачи файлов. Он генерирует контрольные суммы частей файла на стороне сервера и клиента, чтобы определить, какие байты совпадают. Тогда это только отправляет различия. Это означает, что он не может только возобновить загрузку, но даже может загрузить измененные байты, если вы изменили несколько байтов в середине очень большого файла без повторной загрузки файла.
Другой протокол, созданный для возобновления передачи, представляет собой битторрент, где
.torrent
файл содержит список контрольных сумм для блоков из файла, поэтому блоки можно загружать и проверять в произвольном порядке и параллельно из разных источников.Обратите внимание, что rsync и bittorent проверит частичные данные на вашем диске, а возобновление загрузки по HTTP - нет. Поэтому, если вы подозреваете, что частичные данные повреждены, вам необходимо проверить целостность в противном случае, то есть, используя контрольную сумму окончательного файла. Но простое прерывание загрузки или потеря сетевого подключения обычно не приводит к повреждению частичного файла, в то время как может произойти сбой питания во время передачи.
источник
TL; DR: они не могут, если протокол, который они используют, не допускает этого.
Программы не всегда могут возобновить работу с произвольного места: например, HTTP-запросы перезапускаются только в том случае, если сервер поддерживает их, а клиент реализует их: это не универсально, поэтому проверьте документацию вашей программы. Если сервер его поддерживает, программы могут возобновить передачу, просто запросив часть протокола. Обычно вы видите частичные переносы в вашем каталоге загрузки (они обычно помечаются расширением «.partial» или чем-то подобным.)
Если загрузка файла приостановлена или иным образом остановлена, клиент может записать файл на диск и иметь четкое представление о том, где продолжить. Если, с другой стороны, происходит сбой клиента или возникает ошибка записи в файл, клиент должен предположить, что файл поврежден, и начать все сначала. BitTorrent несколько смягчает это, разбивая файлы на «куски» и отслеживая, какие из них были успешно загружены; самое большее, что ему когда-либо придется переделывать, это несколько кусков. Rsync делает что-то подобное.
Как программы узнают, что содержание одинаково? Одним из способов является проверка того, что некоторый идентификатор одинаков между клиентом и сервером. Некоторыми примерами этого могут быть временная метка и размер, но существуют механизмы, которые могут быть специфическими для протокола. Если идентификаторы совпадают, то клиент может предположить, что возобновление будет работать.
Если вы хотите более точную проверку, HTTP и друзья не должны быть вашим первым выбором. Вы захотите использовать протокол, который также имеет контрольную сумму или хэш для всего файла и каждого переданного блока, чтобы вы могли сравнить контрольную сумму загрузки с контрольной суммой компьютера сервера: все, что не соответствует, будет затем повторно загружено. Опять же, BitTorrent является примером такого протокола; При желании rsync может сделать это тоже.
источник
Зависит от протокола, используемого для передачи. Но curl использует http и передает данные последовательно в порядке их появления в файле. Таким образом, curl может возобновиться в зависимости от размера файла частично завершенной передачи. Фактически, вы можете обмануть его, чтобы пропустить первые N байтов, создав файл длиной N (чего угодно) и попросив его обработать этот файл как частично завершенную загрузку (а затем отбросив первые N байтов).
источник