internal/rosa: stream format for cure report
All checks were successful
Test / Create distribution (push) Successful in 59s
Test / Sandbox (push) Successful in 2m37s
Test / Hakurei (push) Successful in 3m40s
Test / ShareFS (push) Successful in 3m46s
Test / Sandbox (race detector) (push) Successful in 4m54s
Test / Hakurei (race detector) (push) Successful in 5m51s
Test / Flake checks (push) Successful in 1m38s
All checks were successful
Test / Create distribution (push) Successful in 59s
Test / Sandbox (push) Successful in 2m37s
Test / Hakurei (push) Successful in 3m40s
Test / ShareFS (push) Successful in 3m46s
Test / Sandbox (race detector) (push) Successful in 4m54s
Test / Hakurei (race detector) (push) Successful in 5m51s
Test / Flake checks (push) Successful in 1m38s
This is for efficient cure status retrieval by the package website server. Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
238
internal/rosa/report.go
Normal file
238
internal/rosa/report.go
Normal file
@@ -0,0 +1,238 @@
|
||||
package rosa
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"runtime"
|
||||
"runtime/debug"
|
||||
"strconv"
|
||||
"sync"
|
||||
"syscall"
|
||||
"unique"
|
||||
"unsafe"
|
||||
|
||||
"hakurei.app/internal/pkg"
|
||||
"hakurei.app/message"
|
||||
)
|
||||
|
||||
// wordSize is the boundary which binary segments are always aligned to.
|
||||
const wordSize = 8
|
||||
|
||||
// padSize returns the padding size for aligning sz.
|
||||
func padSize[T int | int64](sz T) T {
|
||||
return (wordSize - (sz)%wordSize) % wordSize
|
||||
}
|
||||
|
||||
// WriteReport writes a report of all available [PArtifact] to w.
|
||||
func WriteReport(msg message.Msg, w io.Writer, c *pkg.Cache) error {
|
||||
var (
|
||||
zero [wordSize]byte
|
||||
buf [len(pkg.ID{}) + wordSize]byte
|
||||
)
|
||||
for i := range PresetEnd {
|
||||
a := Std.Load(PArtifact(i))
|
||||
if _, ok := a.(pkg.FileArtifact); ok {
|
||||
msg.Verbosef("skipping file artifact %s", artifactsM[i].Name)
|
||||
continue
|
||||
}
|
||||
|
||||
id := c.Ident(a)
|
||||
|
||||
var f *os.File
|
||||
if r, err := c.OpenStatus(a); err != nil {
|
||||
if errors.Is(err, os.ErrNotExist) {
|
||||
msg.Verbosef("artifact %s unavailable", artifactsM[i].Name)
|
||||
continue
|
||||
}
|
||||
return err
|
||||
} else {
|
||||
f = r.(*os.File)
|
||||
}
|
||||
|
||||
msg.Verbosef("writing artifact %s...", artifactsM[i].Name)
|
||||
|
||||
var sz int64
|
||||
if fi, err := f.Stat(); err != nil {
|
||||
_ = f.Close()
|
||||
return err
|
||||
} else {
|
||||
sz = fi.Size()
|
||||
}
|
||||
|
||||
*(*pkg.ID)(buf[:]) = id.Value()
|
||||
binary.LittleEndian.PutUint64(buf[len(pkg.ID{}):], uint64(sz))
|
||||
if _, err := w.Write(buf[:]); err != nil {
|
||||
_ = f.Close()
|
||||
return err
|
||||
}
|
||||
|
||||
if n, err := io.Copy(w, f); err != nil {
|
||||
_ = f.Close()
|
||||
return err
|
||||
} else if n != sz {
|
||||
_ = f.Close()
|
||||
return fmt.Errorf("strange status file copy: %d != %d", n, sz)
|
||||
} else if err = f.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if psz := padSize(sz); psz > 0 {
|
||||
if _, err := w.Write(zero[:psz]); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// existence of status implies cured artifact
|
||||
var n int
|
||||
if pathname, _, err := c.Cure(a); err != nil {
|
||||
return err
|
||||
} else if n, err = pkg.Flatten(
|
||||
os.DirFS(pathname.String()), ".",
|
||||
io.Discard,
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
binary.LittleEndian.PutUint64(buf[:], uint64(n))
|
||||
if _, err := w.Write(buf[:wordSize]); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Report provides efficient access to a report file populated by [WriteReport].
|
||||
type Report struct {
|
||||
// Underlying file, must not be exposed directly.
|
||||
f *os.File
|
||||
// Slice backed by f. Access must be prepared by HandleAccess.
|
||||
data []byte
|
||||
|
||||
// Offsets into data for each identifier.
|
||||
offsets map[unique.Handle[pkg.ID]]int
|
||||
|
||||
// Outcome of a call to Close.
|
||||
closeErr error
|
||||
// Synchronises calls to Close.
|
||||
closeOnce sync.Once
|
||||
}
|
||||
|
||||
// OpenReport opens a file populated by [WriteReport]
|
||||
func OpenReport(pathname string) (rp *Report, err error) {
|
||||
var r Report
|
||||
if r.f, err = os.Open(pathname); err != nil {
|
||||
return
|
||||
}
|
||||
defer func() {
|
||||
if err != nil {
|
||||
_ = r.f.Close()
|
||||
if r.data != nil {
|
||||
_ = syscall.Munmap(r.data)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
var fi os.FileInfo
|
||||
if fi, err = r.f.Stat(); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if r.data, err = syscall.Mmap(
|
||||
int(r.f.Fd()),
|
||||
0,
|
||||
int(fi.Size()),
|
||||
syscall.PROT_READ,
|
||||
syscall.MAP_PRIVATE,
|
||||
); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
defer r.HandleAccess(&err)()
|
||||
|
||||
var offset int
|
||||
r.offsets = make(map[unique.Handle[pkg.ID]]int)
|
||||
for offset < len(r.data) {
|
||||
id := unique.Make((pkg.ID)(r.data[offset:]))
|
||||
offset += len(pkg.ID{})
|
||||
r.offsets[id] = offset
|
||||
offset += int(binary.LittleEndian.Uint64(r.data[offset:])) + wordSize
|
||||
offset += padSize(offset)
|
||||
offset += wordSize
|
||||
}
|
||||
return &r, nil
|
||||
}
|
||||
|
||||
// ReportIOError describes an I/O error while accessing a [Report].
|
||||
type ReportIOError struct {
|
||||
Offset int
|
||||
Err error
|
||||
}
|
||||
|
||||
// Unwrap returns the underlying runtime error.
|
||||
func (e *ReportIOError) Unwrap() error { return e.Err }
|
||||
|
||||
// Error returns a description of the error offset.
|
||||
func (e *ReportIOError) Error() string {
|
||||
return "report I/O error at offset " + strconv.Itoa(e.Offset)
|
||||
}
|
||||
|
||||
// HandleAccess prepares for accessing memory returned by a method of [Report]
|
||||
// and returns a function that must be deferred by the caller.
|
||||
func (r *Report) HandleAccess(errP *error) func() {
|
||||
pof := debug.SetPanicOnFault(true)
|
||||
return func() {
|
||||
debug.SetPanicOnFault(pof)
|
||||
|
||||
v := recover()
|
||||
if v == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err, ok := v.(error); !ok {
|
||||
panic(v)
|
||||
} else if *errP != nil {
|
||||
return
|
||||
} else {
|
||||
*errP = err
|
||||
}
|
||||
|
||||
var runtimeError interface {
|
||||
Addr() uintptr
|
||||
runtime.Error
|
||||
}
|
||||
if errors.As(*errP, &runtimeError) {
|
||||
offset := int(runtimeError.Addr() - uintptr(unsafe.Pointer(unsafe.SliceData(r.data))))
|
||||
// best effort for fragile uintptr
|
||||
if offset >= 0 {
|
||||
*errP = &ReportIOError{offset, *errP}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ArtifactOf returns information of a [pkg.Artifact] corresponding to id.
|
||||
func (r *Report) ArtifactOf(id unique.Handle[pkg.ID]) (status []byte, n int64) {
|
||||
if offset, ok := r.offsets[id]; !ok {
|
||||
n = -1
|
||||
} else {
|
||||
sz := int(binary.LittleEndian.Uint64(r.data[offset:]))
|
||||
offset += wordSize
|
||||
|
||||
status = r.data[offset : offset+sz]
|
||||
offset += sz + padSize(sz)
|
||||
|
||||
n = int64(binary.LittleEndian.Uint64(r.data[offset:]))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Close closes the underlying file and releases all associated resources.
|
||||
func (r *Report) Close() error {
|
||||
r.closeOnce.Do(func() {
|
||||
err := syscall.Munmap(r.data)
|
||||
r.closeErr = errors.Join(err, r.f.Close())
|
||||
})
|
||||
return r.closeErr
|
||||
}
|
||||
57
internal/rosa/report_test.go
Normal file
57
internal/rosa/report_test.go
Normal file
@@ -0,0 +1,57 @@
|
||||
package rosa_test
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
"path"
|
||||
"syscall"
|
||||
"testing"
|
||||
"unique"
|
||||
|
||||
"hakurei.app/internal/pkg"
|
||||
"hakurei.app/internal/rosa"
|
||||
)
|
||||
|
||||
func TestReportZeroLength(t *testing.T) {
|
||||
report := path.Join(t.TempDir(), "report")
|
||||
if err := os.WriteFile(report, nil, 0400); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if _, err := rosa.OpenReport(report); !errors.Is(err, syscall.EINVAL) {
|
||||
t.Fatalf("OpenReport: error = %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestReportSIGSEGV(t *testing.T) {
|
||||
report := path.Join(t.TempDir(), "report")
|
||||
if err := os.WriteFile(report, make([]byte, 64), 0400); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if r, err := rosa.OpenReport(report); err != nil {
|
||||
t.Fatalf("OpenReport: error = %v", err)
|
||||
} else {
|
||||
status, n := r.ArtifactOf(unique.Make(pkg.ID{}))
|
||||
if len(status) != 0 {
|
||||
t.Errorf("ArtifactsOf: status = %#v", status)
|
||||
}
|
||||
if n != 0 {
|
||||
t.Errorf("ArtifactsOf: n = %d", n)
|
||||
}
|
||||
|
||||
if err = r.Close(); err != nil {
|
||||
t.Fatalf("Close: error = %v", err)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
ioErr := err.(*rosa.ReportIOError)
|
||||
if ioErr.Offset != 48 {
|
||||
panic(ioErr)
|
||||
}
|
||||
}()
|
||||
defer r.HandleAccess(&err)()
|
||||
r.ArtifactOf(unique.Make(pkg.ID{}))
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user