Zusammenfassung:
Die Pack-Dateien von Git wurden sorgfältig erstellt, um Festplatten-Caches effektiv zu nutzen und "nette" Zugriffsmuster für allgemeine Befehle und zum Lesen kürzlich referenzierter Objekte bereitzustellen.
Das Pack-Dateiformat von Git ist sehr flexibel (siehe Dokumentation / technisch / pack-format.txt oder The Packfile im Git Community Book ). In den Packdateien werden Objekte auf zwei Arten gespeichert: "undeltifiziert" (nehmen Sie die Rohobjektdaten und entleeren Sie sie) oder "deltifiziert" (bilden Sie ein Delta gegen ein anderes Objekt und entleeren Sie dann die resultierenden Delta-Daten). Die in einer Packung gespeicherten Objekte können in beliebiger Reihenfolge vorliegen (sie müssen (nicht unbedingt) nach Objekttyp, Objektname oder einem anderen Attribut sortiert sein), und deltifizierte Objekte können gegen jedes andere geeignete Objekt desselben Typs erstellt werden.
Der Befehl pack-objects von Git verwendet mehrere Heuristiken , um eine hervorragende Referenzlokalität für allgemeine Befehle bereitzustellen . Diese Heuristiken steuern sowohl die Auswahl der Basisobjekte für deltifizierte Objekte als auch die Reihenfolge der Objekte. Jeder Mechanismus ist größtenteils unabhängig, aber sie teilen einige Ziele.
Git bildet zwar lange Ketten von Delta-komprimierten Objekten, aber die Heuristiken versuchen sicherzustellen, dass sich nur „alte“ Objekte am Ende der langen Ketten befinden. Der Delta-Basis-Cache (dessen Größe von der core.deltaBaseCacheLimit
Konfigurationsvariablen gesteuert wird
) wird automatisch verwendet und kann die Anzahl der für Befehle, die eine große Anzahl von Objekten lesen müssen (z git log
-p
. B. ), erforderlichen "Neuerstellungen" erheblich reduzieren .
Delta-Komprimierungsheuristik
Ein typisches Git-Repository speichert eine sehr große Anzahl von Objekten, sodass es nicht alle vernünftigerweise vergleichen kann, um die Paare (und Ketten) zu finden, die die kleinsten Delta-Darstellungen ergeben.
Die Heuristik zur Auswahl der Delta-Basen basiert auf der Idee, dass die guten Delta-Basen unter Objekten mit ähnlichen Dateinamen und Größen gefunden werden. Jeder Objekttyp wird separat verarbeitet (dh ein Objekt eines Typs wird niemals als Delta-Basis für ein Objekt eines anderen Typs verwendet).
Für die Auswahl der Delta-Basis werden die Objekte (hauptsächlich) nach Dateiname und dann nach Größe sortiert. Ein Fenster in diese sortierte Liste wird verwendet, um die Anzahl der Objekte zu begrenzen, die als potenzielle Delta-Basen betrachtet werden. Wenn für ein Objekt unter den Objekten in seinem Fenster keine "gut genug" 1- Delta-Darstellung gefunden wird, wird das Objekt nicht deltakomprimiert.
Die Größe des Fensters wird durch die --window=
Option
git pack-objects
oder die pack.window
Konfigurationsvariable gesteuert . Die maximale Tiefe einer Delta-Kette wird durch die --depth=
Option git pack-objects
oder die pack.depth
Konfigurationsvariable gesteuert . Durch die --aggressive
Option, git gc
sowohl die Fenstergröße als auch die maximale Tiefe erheblich zu vergrößern, wird versucht, eine kleinere Packdatei zu erstellen.
Die Dateinamensortierung fasst die Objekte für Einträge mit identischen Namen (oder zumindest ähnlichen Endungen (z .c
. B. )) zusammen. Die Größensortierung ist vom größten zum kleinsten, sodass Deltas, die Daten entfernen, Deltas vorgezogen werden, die Daten hinzufügen (da Entfernungsdeltas kürzere Darstellungen haben) und die früheren, größeren Objekte (normalerweise neuere) in der Regel mit einfacher Komprimierung dargestellt werden.
1
Was als „gut genug“ eingestuft wird, hängt von der Größe des betreffenden Objekts und seiner potenziellen Delta-Basis sowie von der Tiefe seiner resultierenden Delta-Kette ab.
Heuristik zur Objektbestellung
Objekte werden in den Packdateien in der Reihenfolge "Zuletzt referenziert" gespeichert. Die Objekte, die zur Rekonstruktion des letzten Verlaufs benötigt werden, werden früher im Paket platziert und liegen nahe beieinander. Dies funktioniert normalerweise gut für OS-Festplatten-Caches.
Alle Festschreibungsobjekte werden nach Festschreibungsdatum (zuletzt zuerst) sortiert und zusammen gespeichert. Diese Platzierung und Reihenfolge optimiert die Festplattenzugriffe, die zum Durchlaufen des Verlaufsdiagramms und zum Extrahieren grundlegender Festschreibungsinformationen (z git log
. B. ) erforderlich sind .
Die Baum- und Blob-Objekte werden beginnend mit dem Baum ab dem ersten gespeicherten (letzten) Commit gespeichert. Jeder Baum wird in der Tiefe zuerst verarbeitet, wobei alle Objekte gespeichert werden, die noch nicht gespeichert wurden. Dadurch werden alle Bäume und Blobs, die für die Rekonstruktion des letzten Commits erforderlich sind, an einem Ort zusammengefasst. Alle Bäume und Blobs, die noch nicht gespeichert wurden, aber für spätere Festschreibungen erforderlich sind, werden als Nächstes in der sortierten Festschreibungsreihenfolge gespeichert.
Die endgültige Objektreihenfolge wird durch die Delta-Basisauswahl geringfügig beeinflusst. Wenn ein Objekt für die Delta-Darstellung ausgewählt wird und sein Basisobjekt noch nicht gespeichert wurde, wird sein Basisobjekt unmittelbar vor dem Delta-Objekt selbst gespeichert. Dies verhindert wahrscheinliche Festplatten-Cache-Fehler aufgrund des nichtlinearen Zugriffs, der zum Lesen eines Basisobjekts erforderlich ist, das "natürlich" später in der Pack-Datei gespeichert worden wäre.