Их около 130 миллионов (129923145, точнее, по find . -name "*.*" | wc -l
) картинки на сервере. Их необходимо исключить из дубликатов и упаковать, чтобы заархивировать сжатый файл от самого маленького до самого большого на каждый миллион для дальнейшего использования. (скажем, если это 500 000 уникальных изображений 8 КБ, 600 000 уникальных изображений 16 КБ, 950 000 уникальных изображений 24 КБ, я должен упаковать 500 000 изображений 8 КБ и 500 000 изображений 16 КБ в первый zip-файл, затем упаковать 100 000 изображений 16 КБ и 900 000 изображений 24 КБ во второй файл. , и остальное к третьему), имя файла должно быть сохранено, а лучше сохранить информацию об иерархии.
Сервер оснащен 32 ГБ памяти, 5,5 ТБ на жестком диске (доступно 122 ГБ), процессор выглядит как E5-2680v4, я не знаю, физическая это или виртуальная машина. Я мог бы попросить товарищей по ИТ добавить память до 512 ГБ, но потребуется как минимум одна неделя, чтобы получить одобрение нашего технического директора, специалистов по цепочке поставок, бюджетного комитета и ИТ-отдела, возможно, дополнительное время, чтобы убедить их.
Нет лишнего дискового пространства для использования из-за рейда или чего-то подобного (айтишниками). Это интрасеть без интернета, и я предпочитаю не отправлять файл, чем подавать приложение. Это Ubuntu 16.04, я уверен, что можно использовать vim, python (2 и 3) и оболочку. Я могу только ssh и не могу sudo
.
Мое решение этой проблемы - использовать du -a
чтобы составить список файлов, используя md5sum
для дедупликации, переименование всех файлов с абсолютным путем (заменить /
к __DIVIDER__
) и переместите весь файл в SIZE/MD5/(fileNameWithAbsPath)
, чем выбрать по одному для каждого каталога. Во время этого я встретил "Ошибка индекса H-дерева". Есть ли лучший способ (быстрее, проще и т. Д.) Завершить его и, если возможно, избежать ошибки индекса H-дерева?
Кстати, я шестой по долгу службы. Бывшая пятерка ушла с работы :(
Итак, один из способов обойти ошибку, с которой вы столкнулись, - это разделить размер и md5 на несколько подполей. Что касается размера, вам нужно сначала дополнить его до фиксированного количества цифр.
Итак, допустим, вы создаете имя файла, например:
#size / md5 / name
12345 / aabbccddeeffgghh / foo__DIVIDER__bar__DIVIDER__baz.jpg
Измените его на:
# size /md5 /name
00/00/01/23/45/aa/bb/cc/dd/ee/ff/gg/hh/foo__DIVIDER__bar__DIVIDER__baz.jpg
... и вы ограничили уровень разветвления в любой заданной точке дерева и таким образом избежали рассматриваемой ошибки.
Фактическое создание дерева имен файлов в этом формате может выглядеть примерно так:
inDir=/path/to/tree/with/input/files
while IFS= read -r -d '' name; do
sp=$(stat --format=%010s -- "$name") # sp as short for "size padded"
size_dir=${sp:0:2}/${sp:2:2}/${sp:4:2}/${sp:6:2}/${sp:8:2}
{ read -r md5 _ < <(md5sum "$name") && [[ $md5 ]]; } || continue
md5_left=$md5
while [[ $md5_left ]]; do
md5_dir+="/${md5_left:0:2}"
md5_left=${md5_left:2}
done
sep=/
final_name="${size_dir}${md5_dir}/${name//$sep/__DIVIDER__}"
final_dir="${final_name%/*}"
if [[ -d "$final_dir" ]]; then
# Hardlink new file to existing ones (deduplication)
# Be sure to use an archiver that understands hardlinks (not zip)!
existing_files=( "$final_dir"/* )
if [[ -e "${existing_files[0]}" || -L "${existing_files[0]}" ]]; then
ln -- "${existing_files[0]}" "$final_name"
ln -f -- "$final_name" "$file" # and make our input file a hardlink as well
continue
fi
fi
# if we get here, the continue was not invoked
mkdir -p -- "${final_name%/*}"
ln -- "$name" "$final_name"
done < <(find "$inDir" -printf '%P\0')
Конечно, если у вас могут быть файлы размером более 9 999 999 999 байт, вы захотите добавить больше отступов (возможно, используя %012s
вместо того %010s
, и изменив расчет size_dir
соответственно).