Назад | Перейти на главную страницу

Как исключить дублирование 130 миллионов файлов и отсортировать их по размеру на относительно ограниченном сервере?

Их около 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 соответственно).