Skip to content
go-libfossil Artifact [9b848c9f29]
Login

Artifact [9b848c9f29]

Artifact 9b848c9f29c6d5207d876d870250bf00a28fa2342427767f7962d5a6cc4aa256:


package manifest

import (
	"context"
	"fmt"

	"github.com/danmestas/go-libfossil/db"
	"github.com/danmestas/go-libfossil/internal/content"
	"github.com/danmestas/go-libfossil/internal/deck"
	libfossil "github.com/danmestas/go-libfossil/internal/fsltype"
	"github.com/danmestas/go-libfossil/internal/repo"
)

// LinkRequiredArtifacts derives only the operation's verified retained closure.
// Unlike opportunistic dephantomization, a database failure is fatal to the
// caller's enclosing recovery transaction. Legitimate unavailable outside files
// retain the ordinary deferred-checkin representation for later synchronization.
func LinkRequiredArtifacts(
	ctx context.Context, r *repo.Repo, cache *content.Cache, rids []libfossil.FslID,
) (int, error) {
	if ctx == nil || r == nil || cache == nil {
		panic("manifest.LinkRequiredArtifacts: nil context, repo or verified cache")
	}
	if len(rids) > 1<<14 {
		return 0, fmt.Errorf("sparse required content: crosslink closure limit exceeded")
	}
	linked := 0
	err := r.WithTx(func(tx *db.Tx) error {
		if err := prepareCrosslinkTables(tx); err != nil {
			return err
		}
		guard, schedule := newCheckinDeferralGuard(), newBatchSchedule()
		guard.cache, guard.awaitFiles = cache, true
		for _, rid := range rids {
			if err := ctx.Err(); err != nil {
				return err
			}
			data, err := cache.Expand(tx, rid)
			if err != nil {
				return err
			}
			d, err := deck.Parse(data)
			if err != nil || !isArtifact(d) {
				continue
			}
			replayed, err := parsedArtifactReplayed(tx, rid, d)
			if err != nil {
				return err
			}
			if replayed {
				continue
			}
			if d.Type == deck.Checkin {
				deferred, err := guard.shouldDefer(tx, "RequiredContent", rid, d)
				if err != nil {
					return err
				}
				if deferred {
					continue
				}
			}
			handled, err := linkArtifact(tx, rid, d, cache, schedule)
			if err != nil {
				return fmt.Errorf("sparse required content: crosslink rid=%d: %w", rid, err)
			}
			if handled {
				linked++
			}
		}
		return repairOnTx(tx, schedule)
	})
	if err != nil {
		return 0, err
	}
	return linked, nil
}