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 }