From ba5d882ef281450efe10aea60b05976cb533ab92 Mon Sep 17 00:00:00 2001 From: Ophestra Date: Sat, 7 Mar 2026 01:38:11 +0900 Subject: [PATCH] internal/rosa: stream format for cure report This is for efficient cure status retrieval by the package website server. Signed-off-by: Ophestra --- internal/rosa/report.go | 238 +++++++++++++++++++++++++++++++++++ internal/rosa/report_test.go | 57 +++++++++ 2 files changed, 295 insertions(+) create mode 100644 internal/rosa/report.go create mode 100644 internal/rosa/report_test.go diff --git a/internal/rosa/report.go b/internal/rosa/report.go new file mode 100644 index 0000000..c002227 --- /dev/null +++ b/internal/rosa/report.go @@ -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 +} diff --git a/internal/rosa/report_test.go b/internal/rosa/report_test.go new file mode 100644 index 0000000..ca29cf3 --- /dev/null +++ b/internal/rosa/report_test.go @@ -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{})) + } + +}