in internal/gitaly/storage/wal/reference_recorder.go [110:252]
func (r *ReferenceRecorder) RecordReferenceUpdates(ctx context.Context, refTX git.ReferenceUpdates) error {
if len(refTX) == 0 {
return nil
}
creations := reftree.New()
deletions := reftree.New()
defaultBranchUpdated := false
preImagePaths := map[string]struct{}{}
for reference, update := range refTX {
if reference.String() == "HEAD" {
defaultBranchUpdated = true
continue
}
tree := creations
if update.NewOID == r.zeroOID {
tree = deletions
}
if err := tree.InsertReference(reference.String()); err != nil {
return fmt.Errorf("insert into tree: %w", err)
}
for component, remainder, haveMore := "", reference.String(), true; haveMore; {
var newComponent string
newComponent, remainder, haveMore = strings.Cut(remainder, "/")
component = filepath.Join(component, newComponent)
if !r.preImage.Contains(component) {
// The path did not exist before applying the transaction.
// None of its children exist either.
break
}
preImagePaths[component] = struct{}{}
}
}
// Record default branch updates
if defaultBranchUpdated {
targetRelativePath := filepath.Join(r.relativePath, "HEAD")
r.entry.operations.removeDirectoryEntry(targetRelativePath)
fileID, err := r.entry.stageFile(filepath.Join(r.snapshotRoot, targetRelativePath))
if err != nil {
return fmt.Errorf("stage file: %w", err)
}
r.entry.operations.createHardLink(fileID, targetRelativePath, false)
}
// Record creations
if err := creations.WalkPreOrder(func(path string, isDir bool) error {
targetRelativePath := filepath.Join(r.relativePath, path)
if isDir {
if _, ok := preImagePaths[path]; ok {
// The directory existed already in the pre-image and doesn't need to be recreated.
return nil
}
r.entry.operations.createDirectory(targetRelativePath)
if err := r.preImage.InsertNode(path, false, isDir); err != nil {
return fmt.Errorf("insert created directory node: %w", err)
}
return nil
}
if _, ok := preImagePaths[path]; ok {
// The file already existed in the pre-image. This means the file has been updated
// and we should remove the previous file before we can link the updated one in place.
r.entry.operations.removeDirectoryEntry(targetRelativePath)
if err := r.preImage.RemoveNode(path); err != nil {
return fmt.Errorf("remove node: %w", err)
}
}
fileID, err := r.entry.stageFile(filepath.Join(r.snapshotRoot, r.relativePath, path))
if err != nil {
return fmt.Errorf("stage file: %w", err)
}
r.entry.operations.createHardLink(fileID, targetRelativePath, false)
if err := r.preImage.InsertNode(path, false, isDir); err != nil {
return fmt.Errorf("insert created file node: %w", err)
}
return nil
}); err != nil {
return fmt.Errorf("walk creations pre-order: %w", err)
}
// Check if the deletion created directories. This can happen if Git has special cased a directory
// to not be deleted, such as 'refs/heads', 'refs/tags' and 'refs/remotes'. Git may create the
// directory to create a lock and leave it in place after the transaction.
if err := deletions.WalkPreOrder(func(path string, isDir bool) error {
info, err := os.Stat(filepath.Join(r.snapshotRoot, r.relativePath, path))
if err != nil && !errors.Is(err, fs.ErrNotExist) {
return fmt.Errorf("stat for dir permissions: %w", err)
}
if _, ok := preImagePaths[path]; info != nil && !ok {
r.entry.operations.createDirectory(filepath.Join(r.relativePath, path))
if err := r.preImage.InsertNode(path, false, isDir); err != nil {
return fmt.Errorf("insert node: %w", err)
}
}
return nil
}); err != nil {
return fmt.Errorf("walk deletion directory creations pre-order: %w", err)
}
// Walk down from the leaves of reference deletions towards the root.
if err := deletions.WalkPostOrder(func(path string, isDir bool) error {
if _, ok := preImagePaths[path]; !ok {
// If the path did not exist in the pre-image, no need to check further. The reference deletion
// was targeting a reference in the packed-refs file, and not in the loose reference hierarchy.
return nil
}
if _, err := os.Stat(filepath.Join(r.snapshotRoot, r.relativePath, path)); err != nil {
if !errors.Is(err, fs.ErrNotExist) {
return fmt.Errorf("stat for deletion: %w", err)
}
// The path doesn't exist in the post-image after the transaction was applied.
r.entry.operations.removeDirectoryEntry(filepath.Join(r.relativePath, path))
if err := r.preImage.RemoveNode(path); err != nil {
return fmt.Errorf("remove node: %w", err)
}
return nil
}
// The path existed. Continue checking other paths whether they've been removed or not.
return nil
}); err != nil {
return fmt.Errorf("walk deletions post-order: %w", err)
}
return nil
}