Files
sm-sitemap-plugin/classes/slots.go
Jakub Zych 3359f1a196 feat: sitemap index and per-type files from a slot table (tracer)
- contract package: Filter, Listing and their types (D-95)
- golem15_sitemap_urls slot table and the new settings columns
- Rebuild over signpost Records, stable slot assignment, rebuild job
- GET /sitemap.xml index and GET /_sitemap/files/{file} from the table
2026-11-04 10:58:05 +01:00

96 lines
2.2 KiB
Go

package classes
import (
"slices"
"time"
)
// Slot is what file numbering needs of one row of the slot table: its
// group, its file number (nil while unnumbered), when it was first seen and
// whether it is listed. A row left out keeps its number: its file keeps the
// hole instead of the later files shifting (D-30, RESEARCH Pitfall 5).
type Slot struct {
ID uint64
Grp string
FileNo *int
FirstSeen time.Time
Listed bool
}
// AssignSlots numbers the rows for files of size addresses and reports
// whether any number changed. Without renumber, a numbered row keeps its
// number and every listed row without one is appended to the last file of
// its group while that file has room (counting the holes of left-out rows),
// then to the next file, oldest first (first seen, then id). With renumber
// (the file size changed), every group's listed rows are numbered again
// from file 1, oldest first, and the left-out rows lose their numbers.
func AssignSlots(rows []*Slot, size int, renumber bool) bool {
if size < 1 {
size = 1
}
groups := map[string][]*Slot{}
var order []string
for _, r := range rows {
if _, ok := groups[r.Grp]; !ok {
order = append(order, r.Grp)
}
groups[r.Grp] = append(groups[r.Grp], r)
}
changed := false
set := func(r *Slot, n *int) {
if (r.FileNo == nil) != (n == nil) || (r.FileNo != nil && *r.FileNo != *n) {
changed = true
}
r.FileNo = n
}
for _, grp := range order {
members := groups[grp]
slices.SortStableFunc(members, func(a, b *Slot) int {
if c := a.FirstSeen.Compare(b.FirstSeen); c != 0 {
return c
}
switch {
case a.ID < b.ID:
return -1
case a.ID > b.ID:
return 1
}
return 0
})
if renumber {
i := 0
for _, r := range members {
if !r.Listed {
set(r, nil)
continue
}
n := i/size + 1
set(r, &n)
i++
}
continue
}
counts := map[int]int{}
last := 0
for _, r := range members {
if r.FileNo == nil {
continue
}
counts[*r.FileNo]++
last = max(last, *r.FileNo)
}
for _, r := range members {
if r.FileNo != nil || !r.Listed {
continue
}
if last == 0 || counts[last] >= size {
last++
}
n := last
set(r, &n)
counts[last]++
}
}
return changed
}