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

Artifact [9fb2ec9644]

Artifact 9fb2ec96444b0c957d57c5e4e1d6bc5995a1aa55dee921a2a158cc85e289611e:


package content

import (
	"context"
	"fmt"
	"path/filepath"
	"slices"
	"strings"
	"testing"
	"time"

	"github.com/danmestas/go-libfossil/db"
	"github.com/danmestas/go-libfossil/internal/blob"
	"github.com/danmestas/go-libfossil/internal/cone"
	"github.com/danmestas/go-libfossil/internal/deck"
)

// BenchmarkCompactStore measures reclamation on an isolated 256-file, 1 MiB
// store copy. Fixture restoration is outside the timed compaction interval.
func BenchmarkCompactStore(b *testing.B) {
	d, err := db.Open(filepath.Join(b.TempDir(), "compact.fossil"))
	if err != nil {
		b.Fatal(err)
	}
	defer d.Close()
	if err := db.CreateRepoSchema(d); err != nil {
		b.Fatal(err)
	}
	var files []deck.FileCard
	err = d.WithTx(func(tx *db.Tx) error {
		for i := 0; i < 256; i++ {
			prefix := "docs"
			if i < 128 {
				prefix = "src"
			}
			data := []byte(fmt.Sprintf("%04d\n", i) + strings.Repeat("representative file content line\n", 128))
			_, uuid, err := blob.Store(tx, data)
			if err != nil {
				return err
			}
			files = append(files, deck.FileCard{Name: fmt.Sprintf("%s/%04d", prefix, i), UUID: uuid})
		}
		slices.SortFunc(files, func(a, b deck.FileCard) int { return strings.Compare(a.Name, b.Name) })
		data, err := (&deck.Deck{Type: deck.Checkin, D: time.Date(2026, 1, 1, 0, 0, 0, 0, time.UTC), F: files}).Marshal()
		if err != nil {
			return err
		}
		_, _, err = blob.Store(tx, data)
		return err
	})
	if err != nil {
		b.Fatal(err)
	}
	if _, err := d.Exec("CREATE TABLE compact_restore AS SELECT * FROM blob"); err != nil {
		b.Fatal(err)
	}
	c, err := cone.New([]string{"src"}, nil)
	if err != nil {
		b.Fatal(err)
	}
	if err := SetStoreCone(d, c); err != nil {
		b.Fatal(err)
	}
	b.ReportAllocs()
	b.SetBytes(256 * 4096)
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		n, err := CompactStore(context.Background(), d)
		if err != nil || n != 128 {
			b.Fatalf("compact = %d, %v", n, err)
		}
		b.StopTimer()
		err = d.WithTx(func(tx *db.Tx) error {
			if _, err := tx.Exec("UPDATE blob SET size=r.size, content=r.content FROM compact_restore r WHERE blob.rid=r.rid"); err != nil {
				return err
			}
			_, err := tx.Exec("DELETE FROM phantom")
			return err
		})
		if err != nil {
			b.Fatal(err)
		}
		b.StartTimer()
	}
}