Nov 09, 2024 12:35
(для программистов и сочувствующих)
Слетали летом в командировку в Америку, получили много экспериментальных данных разных людей, привезли обратно в Израиль и стали анализировать. Данные занимают примерно два терабайта, уместились на одном SSD-диске. В Америке у партнеров осталась оригинальная копия (странное словосочетание, если задуматься).
Через пару месяцев обнаружили, что данные слегла подпорчены. Там на 99% бинарные файлы, а 1% - большие файлы .CSV с числами, числами, числами внутри. По ряду причин все данные хранятся как обычная большая файловая иерархия (а не, скажем, zip-архивы или база данных).
Код на питоне читает CSV-файлы с помощью библиотеки Pandas, которая подбирает для каждой колонки наиболее узкий тип данных - т.е. если в файле в 3-й колонке везде числа с плавающей точкой, это будет float, а если иногда что-то другое, будет string для всех. Обнаружилось, что в некоторых файлах числовые данные читаются как string, что потом приводит к странным результам, когда с ними делают числовые операции. Когда я стал разбираться, почему так, обнаружил, что мегабайтном файле, целиком состоящем из чисел, записано в одном месте "число" -0.053208=523, и этот знак = все портит. Всего таких испорченных csv-файлов оказалось мало, около 3%. Но я не знал, есть ли подобные ошибки также в бинарных файлах.
Если бы данных было меньше, я бы просто скопировал из Америки. Но копировать 2TB было немного болезненно, и заодно хотелось разобраться, откуда взялась порча и сколько ее. Поэтому я сделал следующее:
- запустил рекурсивный md5sum на все дерево в Америке и дома (10 миллионов файлов)
- скопировал файлы с контрольными суммами в одно место и сравнил, нашел, сколько файлов отличаются по сумме (300 тысяч), сгенерировал список этих файлов
- в Америке сделал zip-архив только с оригиналами испорченных файлов (80GB), скопировал в Израиль, раскрыл
- набросал скрипт, который прошелся по оригиналам, сравнил с испорченными копиями.
Оказалось следующее:
- испорчен примерно один байт из каждых 300 килобайт, т.е. 0.0003% данных
- порча есть в файлах всех типов, и бинарных, и CSV, просто в CSV заметили раньше
- порча всегда одного вида: третий бит с конца становится 1, неважно, был он до того 0 или 1. Т.е. значение байта увеличивается на 4 (или не меняется, если и так этот бит стоял).
- при этом в файлах CSV, состоящих почти целиком из цифр и запятых, происходит следующее. Запятые не меняются, их ASCII-код содержит этот бит. Цифры 0,1,2,3 переходят в 4,5,6,7 и мы эту порчу не заметили. Цифры 4,5,6,7 остаются как есть. И только 8,9 переходят в <,= и это дает вышеописанный эффект в чтении файла из питона. Поэтому только когда очень редкая порча попадает именно на текстовый файл, и в нем на одну из этих двух цифр, получается испорченный файл, который мы замечаем.
На данный момент моя лучшая версия - это плохая память в десктопе или лаптопе, на котором мы копировали все данные с диска-оригинала на диск, который взяли с собой домой. Видимо, сбоит один бит в одном байте памяти. Копировали с помощью Windows-программы robocopy. То, что в длинных последовательностях бинарных файлов одного размера ошибка почти всегда оказывается на одном оффсете от начала файла, косвенно подтверждает это объяснение. Альтернатива - это что какая-то херня происходит в контроллере SSD-диска, кажется маловероятным, но я недостаточно понимаю, как там все устроено. Других вариантов вроде нет.
Урок на будущее: после копирования большого кол-ва данных отдельно проверить, что копия идентична оригиналу, с помощью программы сравнения файлов/директорий.
(Сначала я хотел написать "копировать архивами, даже и без сжатия можно, просто чтобы была контрольная сумма", но если порчу вносит плохой бит в памяти во время *чтения* с диска, то архиватор создаст отличный архив с правильной суммой и плохими данными)
Прикольно.
программирование