Spec-Zone.ru › Git

multi-pack-index

Каталог объектов Git содержит каталог pack с файлами пакетов (с суффиксом ".pack") и индексами пакетов (с суффиксом ".idx"). Индексы пакетов позволяют искать объекты и переходить к их смещению внутри пакета, но они должны идти в паре с файлами пакетов. Эта связь определяется именами файлов, поскольку индекс пакета отличается от соответствующего файла пакета только суффиксом. Индексы пакетов обеспечивают быстрый поиск в каждом файле пакета, но производительность снижается по мере увеличения числа файлов пакетов: для сокращённых идентификаторов необходимо проверять каждый файл пакета, а вероятность того, что наиболее недавно использовавшийся файл пакета не содержит нужный объект, возрастает. Для некоторых крупных репозиториев перепаковка в один файл пакета невозможна из-за нехватки места или чрезмерно долгого времени перепаковки.

Индекс нескольких пакетов (multi-pack-index, сокращённо MIDX) хранит список объектов и их смещений в нескольких файлах пакетов. Он содержит:

  • Список имён файлов пакетов.

  • Отсортированный список идентификаторов объектов.

  • Список метаданных для i-го идентификатора объекта, включающий:

    • Значение j, указывающее на j-й файл пакета.

    • Смещение объекта внутри j-го файла пакета.

  • Если требуются большие смещения, используется ещё один список больших смещений, аналогичный индексам пакетов версии 2.

    • Необязательный список объектов в порядке псевдопакета (используется с битовыми картами MIDX).

Таким образом, время поиска для любого количества файлов пакетов составляет O(log N).

Подробности реализации

  • MIDX хранится в файле с именем multi-pack-index в каталоге .git/objects/pack. Он может храниться в каталоге пакетов альтернативного репозитория. Он ссылается только на файлы пакетов в этом же каталоге.

  • Для использования файлов MIDX параметр конфигурации core.multiPackIndex должен быть включён (это значение по умолчанию). Если установить для него значение false, Git не будет читать файл MIDX, даже если он существует.

  • Формат файла включает параметры хеш-функции идентификатора объекта, поэтому будущая смена алгоритма хеширования не потребует изменения формата.

  • MIDX хранит только одну запись для каждого идентификатора объекта. Если объект содержится в нескольких файлах пакетов, MIDX выбирает копию из предпочтительного файла пакета, а если такого нет — из файла пакета, изменённого последним.

  • Если в каталоге пакетов есть файлы пакетов, не зарегистрированные в MIDX, они загружаются в список packed_git и кэш packed_git_mru.

  • Индексы пакетов (файлы .idx) остаются в каталоге пакетов, поэтому мы можем удалить файл MIDX, установить для core.midx значение false или выполнить откат на предыдущую версию без потери информации.

  • В формате файла MIDX используется подход на основе блоков (аналогичный файлу commit-graph), позволяющий добавлять необязательные данные.

Инкрементальные индексы нескольких пакетов

По мере увеличения репозиториев становится всё затратнее записывать индекс нескольких пакетов (MIDX), включающий все файлы пакетов. Для этого предусмотрена функция «инкрементальных индексов нескольких пакетов», позволяющая объединять «цепочку» индексов MIDX.

Каждый отдельный компонент цепочки должен содержать лишь небольшое количество файлов пакетов. Добавление нового элемента в цепочку не делает недействительными её предыдущие части, поэтому репозитории могут контролировать время, затрачиваемое на обновление цепочки MIDX, задавая число пакетов в каждом её слое.

Состояние реализации

В настоящее время в функции инкрементальных индексов нескольких пакетов отсутствуют два важных компонента:

  • Возможность перезаписывать более ранние части цепочки MIDX (то есть «уплотнять» некоторую группу соседних слоёв MIDX в один индекс MIDX). Сейчас единственный поддерживаемый способ сократить цепочку MIDX — заново записать всю цепочку, не используя флаг --split.

    Нет фундаментальных ограничений, мешающих реализовать эту функцию. Она не вошла в первоначальную реализацию, чтобы уменьшить её сложность, но будет добавлена позднее.

  • Поддержка битовых карт достижимости. Классическая реализация единого MIDX поддерживает битовые карты достижимости (подробности см. в разделе «обратные индексы multi-pack-index» документа gitformat-pack[5]).

    Как и в предыдущем случае, нет фундаментальных ограничений, мешающих расширить формат инкрементального MIDX для поддержки битовых карт достижимости. Это специально учтено в приведённом ниже проекте, а поддержка битовых карт достижимости будет добавлена в одном из будущих циклов исправлений. Она не вошла в текущую реализацию по той же причине, что и выше.

    Кратко говоря, для поддержки битовых карт достижимости в функции инкрементального MIDX понятие порядка псевдопакета распространяется на каждый слой цепочки инкрементального MIDX, образуя объединённый порядок псевдопакета. Объединение выполняется в том же порядке, что и сама цепочка (другими словами, объединённый порядок псевдопакета для цепочки {$H1, $H2, $H3} будет состоять из порядка псевдопакета для $H1, за которым следует порядок псевдопакета для $H2, а затем — порядок псевдопакета для $H3).

    Затем формат будет расширен так, чтобы каждый слой цепочки инкрементального MIDX мог записывать *.bitmap. Смещения объектов в битовой карте каждого слоя увеличиваются на число объектов в предыдущих слоях цепочки.

Структура файлов

Вместо хранения одного файла multi-pack-index (с необязательными расширениями .rev и .bitmap) в $GIT_DIR/objects/pack, инкрементальные MIDX хранятся в следующей структуре:

$GIT_DIR/objects/pack/multi-pack-index.d/
$GIT_DIR/objects/pack/multi-pack-index.d/multi-pack-index-chain
$GIT_DIR/objects/pack/multi-pack-index.d/multi-pack-index-$H1.midx
$GIT_DIR/objects/pack/multi-pack-index.d/multi-pack-index-$H2.midx
$GIT_DIR/objects/pack/multi-pack-index.d/multi-pack-index-$H3.midx

Файл multi-pack-index-chain содержит упорядоченный список файлов инкрементального MIDX в цепочке. В приведённом выше примере файл multi-pack-index-chain для этой цепочки содержал бы следующие строки:

$H1
$H2
$H3

Файл multi-pack-index-$H1.midx содержит первый слой цепочки индексов нескольких пакетов. Файл multi-pack-index-$H2.midx содержит второй слой цепочки и так далее.

Если присутствуют и инкрементальный, и неинкрементальный MIDX, сначала всегда считывается неинкрементальный MIDX.

Позиции объектов в инкрементальных MIDX

В исходном проекте индекса нескольких пакетов объекты обозначаются их лексикографическими позициями (по идентификаторам объектов) в едином индексе нескольких пакетов репозитория. В проекте инкрементального индекса нескольких пакетов объекты обозначаются их индексами в объединённом лексикографическом порядке компонентов цепочки MIDX.

Если objects_nr() — это функция, возвращающая число объектов в заданном слое MIDX, то индекс объекта с лексикографической позицией i в, например, $H3 определяется следующим образом:

objects_nr($H2) + objects_nr($H1) + i

(В реализации на C это часто вычисляется как i + m->num_objects_in_base.)

Порядок псевдопакета для инкрементальных MIDX

В исходной реализации битовых карт достижимости для нескольких пакетов порядок псевдопакета определялся в gitformat-pack[5] (см. раздел «обратные индексы multi-pack-index») примерно так:

Кратко говоря, псевдопакет MIDX — это объединённый без дубликатов список объектов из пакетов, хранящихся в MIDX, расположенных в порядке пакетов, причём сами пакеты упорядочены по MIDX (сначала идёт предпочтительный пакет).

В проекте инкрементального MIDX это определение расширено и включает объекты из нескольких слоёв цепочки MIDX. Порядок псевдопакета для инкрементальных MIDX определяется объединением порядков псевдопакетов каждого слоя цепочки MIDX в порядке следования слоёв. Формально два объекта o1 и o2 сравниваются следующим образом:

  1. Если o1 находится в более раннем слое цепочки MIDX, чем o2, то o1 располагается перед o2.

  2. Иначе, если o1 и o2 находятся в одном слое MIDX, а у этого слоя MIDX нет базового слоя, то, если один из объектов pack(o1) и pack(o2) является предпочтительным, а другой — нет, предпочтительный объект располагается перед непредпочтительным. Если базовый слой есть (то есть слой MIDX не является первым слоем цепочки), то, если pack(o1) находится раньше в порядке пакетов этого слоя MIDX, o1 располагается перед o2. Аналогично, если раньше находится pack(o2), то верно обратное.

  3. В противном случае o1 и o2 находятся в одном пакете и, следовательно, в одном слое MIDX. Сортируйте o1 и o2 по смещению внутри содержащего их файла пакета.

Обратите внимание, что предпочтительный пакет — это свойство цепочки MIDX, а не отдельных её слоёв. В принципе, можно было бы ввести предпочтительный пакет для каждого слоя, но теперь это менее актуально, поскольку можно повторно использовать объекты из нескольких пакетов в наборе пакетов MIDX.

Битовые карты достижимости и инкрементальные MIDX

Объекты каждого слоя цепочки инкрементального MIDX (а также объекты из предыдущих слоёв той же цепочки MIDX) могут быть представлены в отдельном файле *.bitmap.

Структура файла *.bitmap, относящегося к цепочке инкрементального MIDX, идентична структуре битовой карты неинкрементального MIDX или классической битовой карты одного пакета. Поскольку объекты добавляются в конец порядка псевдопакета инкрементального MIDX (см. выше), при добавлении элементов в конец цепочки MIDX битовую карту можно расширить.

(Примечание: аналогичным образом можно сжать непрерывную последовательность инкрементальных слоёв MIDX и их файлы *.bitmap в один слой и *.bitmap, но эта возможность пока не реализована.)

Используются глобальные позиции объектов в порядке псевдопакета, поэтому в последующих слоях будет, например, m->num_objects_in_base бит 0 в каждой из четырёх битовых карт типов. Это следует из того, что мы записываем записи битовой карты типов только для объектов, присутствующих в слое, которому непосредственно соответствует битовая карта.

Также обратите внимание, что для хранения информации о достижимости интересующих и неинтересующих объектов при запросе достижимости используется только битовая карта, соответствующая последнему слою цепочки инкрементального MIDX. Предыдущие слои битовых карт используются только для поиска битовых карт фиксаций и псевдообъединений из соответствующего слоя, а также битовых карт типов объектов в этом слое.

Чтобы упростить реализацию, битовые карты типов обходятся одновременно, а их результаты объединяются операцией OR, чтобы избежать рекурсивных вызовов внутренних функций битовых карт.

Планы на будущее

  • Если индекс нескольких пакетов будет расширен так, чтобы хранить «стабильный порядок объектов» (функцию Order(hash) = integer, результат которой для заданного хеша остаётся неизменным даже при обновлении индекса нескольких пакетов), битовые карты MIDX можно будет обновлять независимо от MIDX.

  • Файлы пакетов можно помечать как «особые» с помощью пустых файлов с тем же начальным именем, но с суффиксом ".keep" или ".promisor" вместо ".pack". В индекс нескольких пакетов можно добавить необязательный блок данных, содержащий информацию о флагах файлов пакетов. Это позволит задавать новые состояния, например repacked или redeltified, которые помогут обслуживать пакеты в среде с несколькими пакетами. Также может быть полезно упорядочивать файлы пакетов по типу объекта (фиксация, дерево, двоичный объект и т. д.) и использовать эти метаданные для упрощения обслуживания.

Связанные ссылки

[0] https://bugs.chromium.org/p/git/issues/detail?id=6 Задача Chromium: индекс нескольких пакетов (MIDX)

[1] https://lore.kernel.org/git/20180107181459.222909-1-dstolee@microsoft.com/ Более ранний RFC для функции индекса нескольких пакетов

[2] https://lore.kernel.org/git/alpine.DEB.2.20.1803091557510.23109@alexmv-linux/ Записи с саммита участников Git Merge 2018 (включают обсуждение MIDX)

© 2005–2026 Linus Torvalds and others
Licensed under the GNU General Public License version 2.
https://git-scm.com/docs/multi-pack-index

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API