func()

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
}