Skip to content
go-libfossil Artifact [d134d9668c]
Login

Artifact [d134d9668c]

Artifact d134d9668c7c5e41444cd9db08b5c4f2d392505dcea1e2d1188109d299c86f24:


package content

import (
	"context"
	"encoding/binary"
	"fmt"

	"github.com/danmestas/go-libfossil/db"
)

// The metadata-only pass must prove total stored bytes first: substr(BLOB) can
// materialize the entire value inside SQLite even though it returns six bytes.
// Charge those reads separately from later full driver-payload reads.
func referencePrefixes(
	ctx context.Context, q db.Querier, blobs []referenceBlob,
	budget ReferenceBudget, work *ReferenceWork,
) error {
	var inflated int64
	for i := range blobs {
		if err := ctx.Err(); err != nil {
			return err
		}
		b := &blobs[i]
		if b.unreadable {
			continue
		}
		if b.stored > budget.StoredBytes-work.PrefixBytes {
			return fmt.Errorf("sparse preparation: prefix byte budget exceeded")
		}
		work.PrefixReads++
		work.PrefixBytes += b.stored
		var prefix []byte
		err := q.QueryRow(`SELECT substr(content,1,6) FROM blob WHERE rid=?
			AND typeof(content)='blob' AND length(content)=?`, b.rid, b.stored).Scan(&prefix)
		if err != nil {
			return err
		}
		b.unreadable = len(prefix) != 6
		if !b.unreadable {
			b.unreadable = prefix[4]&15 != 8 || prefix[4]>>4 > 7 ||
				binary.BigEndian.Uint16(prefix[4:])%31 != 0
		}
		if b.unreadable {
			continue
		}
		b.inflated = int64(binary.BigEndian.Uint32(prefix[:4]))
		if b.inflated > budget.InflatedBytes-inflated {
			return fmt.Errorf("sparse preparation: inflation budget exceeded")
		}
		inflated += b.inflated
	}
	return nil
}