@@ -34,30 +34,10 @@ func totalBlocks(hashes [][]prefixhash.BlockHash) int {
3434 return total
3535}
3636
37- // groupKey identifies requests that share an identical prompt prefix. Because
38- // each block hash chains its predecessor, an identical leading hash sequence
39- // means an identical prompt prefix. Requests with no prefix return "" and are
40- // never grouped.
41- func groupKey (hashes [][]prefixhash.BlockHash ) string {
42- if totalBlocks (hashes ) == 0 {
43- return ""
44- }
45- var b strings.Builder
46- var buf [8 ]byte
47- for _ , ph := range hashes {
48- for _ , h := range ph {
49- binary .LittleEndian .PutUint64 (buf [:], uint64 (h ))
50- b .Write (buf [:])
51- }
52- b .WriteByte ('|' )
53- }
54- return b .String ()
55- }
56-
57- // prefixSignature encodes the first n prefix blocks. Two requests with equal
58- // signatures share at least n leading blocks (the chained-hash property), so it
59- // groups requests that overlap on a prefix without being identical.
60- func prefixSignature (hashes [][]prefixhash.BlockHash , n int ) string {
37+ // encodePrefix serializes the first n prefix blocks. Equal results imply an
38+ // equal n-block leading prefix: each block hash chains its predecessor, so an
39+ // equal leading hash sequence means an equal prompt prefix.
40+ func encodePrefix (hashes [][]prefixhash.BlockHash , n int ) string {
6141 var b strings.Builder
6242 var buf [8 ]byte
6343 count := 0
@@ -75,6 +55,16 @@ func prefixSignature(hashes [][]prefixhash.BlockHash, n int) string {
7555 return b .String ()
7656}
7757
58+ // groupKey identifies requests that share an identical prompt prefix. Requests
59+ // with no prefix return "" and are never grouped.
60+ func groupKey (hashes [][]prefixhash.BlockHash ) string {
61+ n := totalBlocks (hashes )
62+ if n == 0 {
63+ return ""
64+ }
65+ return encodePrefix (hashes , n )
66+ }
67+
7868// sharedPrefixKeys returns the group keys whose requests share at least
7969// minColocateBlocks leading blocks with some other request in the batch. It is
8070// the affinity gate for non-identical requests: a lone request that overlaps no
@@ -92,7 +82,7 @@ func sharedPrefixKeys(groups map[string][]*entry, order []string, minColocateBlo
9282 if totalBlocks (hashes ) < minColocateBlocks {
9383 continue
9484 }
95- s := prefixSignature (hashes , minColocateBlocks )
85+ s := encodePrefix (hashes , minColocateBlocks )
9686 keySig [key ] = s
9787 count [s ] += len (groups [key ])
9888 }
@@ -151,25 +141,10 @@ func (b *batchIndex) longestPrefix(hashes [][]prefixhash.BlockHash) map[string]i
151141}
152142
153143// assign steers each batched request to a replica so prompt-sharing requests
154- // co-locate. Pass 1 groups requests by identical prefix (the samples of one
155- // prompt). An identical group of more than one member is always a placeable
156- // unit; a single request becomes placeable only when it shares at least
157- // minColocateBlocks leading blocks with some other request in the batch (so a
158- // lone, distinct request keeps no affinity and is left for other scorers).
159- //
160- // Pass 2 places the units jointly over the whole batch. Identical groups are
161- // placed first - longest-prefix first, kept whole (never split except by an
162- // explicit maxPerReplica cap) - so the proven same-prompt co-location is the firm
163- // structure; prefix-sharing singletons then attach to the established clusters.
164- // Each unit prefers a replica that already holds a unit sharing at least
165- // minColocateBlocks leading blocks AND is still below its fair share of the batch
166- // (total placed samples / replicas); this prefills a shared prefix once across
167- // units without letting many prefix-sharing units stampede onto one replica. With
168- // no eligible match a unit seeds the least-loaded replica. Within a group,
169- // samples fill one replica up to maxPerReplica (k) before spilling to the next
170- // least-loaded replica; k == -1 places the whole group on one replica.
171- // minColocateBlocks == 0 disables inter-unit co-location: only identical groups
172- // are placed and purely load-balanced.
144+ // co-locate. It groups requests by shared prefix, then places the groups jointly
145+ // over the batch (longest-prefix first) so a shared prefix is prefilled once per
146+ // replica rather than scattered. Identical groups are placed before prefix-sharing
147+ // singletons so proven same-prompt co-location anchors the layout.
173148func assign (entries []* entry , k , minColocateBlocks int ) {
174149 groups := map [string ][]* entry {}
175150 order := []string {}
@@ -191,10 +166,6 @@ func assign(entries []*entry, k, minColocateBlocks int) {
191166 return
192167 }
193168
194- // Identical groups are always placed; a singleton is placed only when it
195- // overlaps another request's prefix. Identical groups are placed before
196- // singletons so same-prompt co-location is never displaced by an attaching
197- // singleton.
198169 shared := sharedPrefixKeys (groups , order , minColocateBlocks )
199170 var groupUnits , singleUnits []string
200171 total := 0
@@ -221,10 +192,7 @@ func assign(entries []*entry, k, minColocateBlocks int) {
221192
222193 idx := newBatchIndex ()
223194 load := map [string ]int {} // batch-wide samples assigned per replica
224- for _ , key := range groupUnits {
225- placeGroup (groups [key ], replicas , k , minColocateBlocks , maxShare , idx , load )
226- }
227- for _ , key := range singleUnits {
195+ for _ , key := range append (groupUnits , singleUnits ... ) {
228196 placeGroup (groups [key ], replicas , k , minColocateBlocks , maxShare , idx , load )
229197 }
230198}
@@ -246,10 +214,14 @@ func placeGroup(members []*entry, replicas []fwksched.Endpoint, k, minColocateBl
246214 return
247215 }
248216 hashes := members [0 ].hashes // identical group: any member represents it
249- matches := idx .longestPrefix (hashes )
250217
251- perReplica := map [string ]int {} // samples of THIS group already on a replica
218+ var matches map [string ]int
252219 preferMatch := minColocateBlocks > 0
220+ if preferMatch {
221+ matches = idx .longestPrefix (hashes )
222+ }
223+
224+ perReplica := map [string ]int {} // samples of this group already on a replica
253225 i := 0
254226 for i < len (members ) {
255227 target := pickReplica (replicas , perReplica , k , load , matches , minColocateBlocks , maxShare , preferMatch )
@@ -317,7 +289,7 @@ func pickReplica(replicas []fwksched.Endpoint, perReplica map[string]int, k int,
317289
318290// pickLeastLoaded returns the least batch-loaded replica with capacity for this
319291// group, falling back to the overall least-loaded replica when all are at the
320- // cap. Ties break by running requests then by name for deterministic placement.
292+ // cap.
321293func pickLeastLoaded (replicas []fwksched.Endpoint , perReplica map [string ]int , k int , load map [string ]int ) fwksched.Endpoint {
322294 var best fwksched.Endpoint
323295 var bestName string
0 commit comments