Skip to content
quarry Artifact [ed5d7f4ac4]
Login

Artifact [ed5d7f4ac4]

Artifact ed5d7f4ac4878527e1c411e7e9660046dfc498e42a7ccc08eb2e611a57290e81:


package index

import (
	"testing"
	"time"
)

// attachment.head runs on every ticket page that shows a file, and it
// records what it learned in the index. That record must not make the
// page wait for the writer: a mirror fold of a large tracker holds it
// for seconds, and before this the page sat behind the fold once per
// attachment card. The verdict is readable at once, and lands in the
// table when the writer frees up.
func TestAHeadMemoNeverWaitsForTheWriter(t *testing.T) {
	ix := openIndex(t)
	tx, err := ix.w.Begin()
	if err != nil {
		t.Fatal(err)
	}
	const held = 2 * time.Second
	released := make(chan struct{})
	go func() {
		time.Sleep(held)
		tx.Rollback()
		close(released)
	}()
	want := AttachmentHead{Size: 9, Kind: "text", Lines: 1, Text: "nine byte"}
	start := time.Now()
	ix.RememberAttachmentHead("blob1", want)
	if el := time.Since(start); el > held/4 {
		t.Fatalf("FAIL: remembering a verdict waited %v on a held writer", el.Round(time.Millisecond))
	}
	got, ok, err := ix.AttachmentHeadFor("blob1")
	if err != nil || !ok || got != want {
		t.Fatalf("FAIL: a verdict remembered behind a held writer read back ok=%v err=%v %+v", ok, err, got)
	}
	if el := time.Since(start); el > held/4 {
		t.Fatalf("FAIL: reading the verdict back waited %v on a held writer", el.Round(time.Millisecond))
	}
	<-released
	deadline := time.Now().Add(5 * time.Second)
	for {
		var n int
		if err := ix.db.QueryRow(`SELECT count(*) FROM attachment_head WHERE src = 'blob1'`).Scan(&n); err != nil {
			t.Fatal(err)
		}
		if n == 1 {
			break
		}
		if time.Now().After(deadline) {
			t.Fatal("FAIL: the verdict never reached the table once the writer was free")
		}
		time.Sleep(10 * time.Millisecond)
	}
	t.Log("ok: a head verdict is remembered without waiting on the writer, and written once it is free")
}