- 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
96 lines
2.2 KiB
Go
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
|
|
}
|