@@ -74,7 +74,7 @@ func TestAssign_UnlimitedColocatesWholeGroup(t *testing.T) {
7474 replicas := []fwksched.Endpoint {testEndpoint ("pod1" ), testEndpoint ("pod2" ), testEndpoint ("pod3" ), testEndpoint ("pod4" )}
7575 entries := group (8 , []prefixhash.BlockHash {1 , 2 , 3 }, replicas )
7676
77- assign (entries , unlimitedPerReplica , 0 )
77+ assign (entries , unlimitedPerReplica , 0 , false )
7878
7979 for _ , e := range entries {
8080 assert .Equal (t , "pod1" , assignedName (e ), "all samples of one group must co-locate when k=-1" )
@@ -85,7 +85,7 @@ func TestAssign_CapSpreadsEvenly(t *testing.T) {
8585 replicas := []fwksched.Endpoint {testEndpoint ("pod1" ), testEndpoint ("pod2" ), testEndpoint ("pod3" ), testEndpoint ("pod4" )}
8686 entries := group (8 , []prefixhash.BlockHash {1 , 2 , 3 }, replicas )
8787
88- assign (entries , 2 , 0 )
88+ assign (entries , 2 , 0 , false )
8989
9090 assert .Equal (t , map [string ]int {"pod1" : 2 , "pod2" : 2 , "pod3" : 2 , "pod4" : 2 }, counts (entries ),
9191 "k=2 over 8 samples and 4 replicas must place 2 per replica" )
@@ -95,7 +95,7 @@ func TestAssign_CapFillsBeforeSpilling(t *testing.T) {
9595 replicas := []fwksched.Endpoint {testEndpoint ("pod1" ), testEndpoint ("pod2" ), testEndpoint ("pod3" ), testEndpoint ("pod4" )}
9696 entries := group (8 , []prefixhash.BlockHash {1 , 2 , 3 }, replicas )
9797
98- assign (entries , 4 , 0 )
98+ assign (entries , 4 , 0 , false )
9999
100100 // k=4 fills one replica to 4 before using the next; only two replicas used.
101101 assert .Equal (t , map [string ]int {"pod1" : 4 , "pod2" : 4 }, counts (entries ))
@@ -105,7 +105,7 @@ func TestAssign_SingletonGetsNoAffinity(t *testing.T) {
105105 replicas := []fwksched.Endpoint {testEndpoint ("pod1" ), testEndpoint ("pod2" )}
106106 entries := group (1 , []prefixhash.BlockHash {1 , 2 , 3 }, replicas )
107107
108- assign (entries , unlimitedPerReplica , 0 )
108+ assign (entries , unlimitedPerReplica , 0 , false )
109109
110110 assert .Nil (t , entries [0 ].assigned , "a singleton group has no reuse and must not receive an affinity" )
111111}
@@ -117,7 +117,7 @@ func TestAssign_EmptyPrefixGetsNoAffinity(t *testing.T) {
117117 {hashes : nil , pods : replicas },
118118 }
119119
120- assign (entries , unlimitedPerReplica , 0 )
120+ assign (entries , unlimitedPerReplica , 0 , false )
121121
122122 for _ , e := range entries {
123123 assert .Nil (t , e .assigned , "requests with no prefix must not be grouped" )
@@ -130,7 +130,7 @@ func TestAssign_DistinctGroupsSpreadAcrossReplicas(t *testing.T) {
130130 groupB := group (8 , []prefixhash.BlockHash {9 , 9 , 9 }, replicas )
131131 entries := append (append ([]* entry {}, groupA ... ), groupB ... )
132132
133- assign (entries , unlimitedPerReplica , 0 )
133+ assign (entries , unlimitedPerReplica , 0 , false )
134134
135135 // Each group co-locates, and the second group lands on a different, less
136136 // loaded replica than the first.
@@ -154,7 +154,7 @@ func TestAssign_SharedPrefixFamiliesColocateWithinFairShare(t *testing.T) {
154154 y2 := group (2 , []prefixhash.BlockHash {7 , 8 , 6 }, replicas )
155155 entries := concat (x1 , x2 , y1 , y2 )
156156
157- assign (entries , unlimitedPerReplica , 2 )
157+ assign (entries , unlimitedPerReplica , 2 , false )
158158
159159 // Each family co-locates onto one replica, the two families land on
160160 // different replicas, and the batch stays balanced (4 samples per replica).
@@ -174,7 +174,7 @@ func TestAssign_FairShareSpreadsPrefixSharingGroups(t *testing.T) {
174174 g4 := group (2 , []prefixhash.BlockHash {1 , 2 , 6 }, replicas )
175175 entries := concat (g1 , g2 , g3 , g4 )
176176
177- assign (entries , unlimitedPerReplica , 2 )
177+ assign (entries , unlimitedPerReplica , 2 , false )
178178
179179 assert .Equal (t , map [string ]int {"pod1" : 2 , "pod2" : 2 , "pod3" : 2 , "pod4" : 2 }, counts (entries ),
180180 "the fair-share cap must spread prefix-sharing groups, not stampede them onto one replica" )
@@ -190,7 +190,7 @@ func TestAssign_SingletonAttachesToOverlappingGroup(t *testing.T) {
190190 sy := group (1 , []prefixhash.BlockHash {7 , 8 , 9 }, replicas )
191191 entries := concat (gx , sx , gy , sy )
192192
193- assign (entries , unlimitedPerReplica , 2 )
193+ assign (entries , unlimitedPerReplica , 2 , false )
194194
195195 // The identical group stays whole, and the overlapping singleton attaches to
196196 // the replica holding the group it shares a prefix with.
@@ -206,7 +206,7 @@ func TestAssign_LoneSingletonGetsNoAffinity(t *testing.T) {
206206 lone := group (1 , []prefixhash.BlockHash {5 , 5 , 5 }, replicas ) // overlaps nothing
207207 entries := concat (g , lone )
208208
209- assign (entries , unlimitedPerReplica , 2 )
209+ assign (entries , unlimitedPerReplica , 2 , false )
210210
211211 assert .Nil (t , lone [0 ].assigned , "a request overlapping no other must keep no affinity" )
212212 assert .Equal (t , assignedName (g [0 ]), assignedName (g [1 ]), "the identical group still co-locates" )
@@ -222,7 +222,7 @@ func TestAssign_OverlappingSingletonsColocateWithoutGroups(t *testing.T) {
222222 s4 := group (1 , []prefixhash.BlockHash {1 , 2 , 6 }, replicas )
223223 entries := concat (s1 , s2 , s3 , s4 )
224224
225- assign (entries , unlimitedPerReplica , 2 )
225+ assign (entries , unlimitedPerReplica , 2 , false )
226226
227227 for _ , e := range entries {
228228 assert .NotNil (t , e .assigned , "overlapping singletons receive an affinity even without identical groups" )
@@ -240,7 +240,7 @@ func TestAssign_SharedPrefixBelowThresholdDoesNotColocate(t *testing.T) {
240240 y2 := group (2 , []prefixhash.BlockHash {7 , 8 , 6 }, replicas )
241241 entries := concat (x1 , x2 , y1 , y2 )
242242
243- assign (entries , unlimitedPerReplica , 3 )
243+ assign (entries , unlimitedPerReplica , 3 , false )
244244
245245 // The shared prefix falls short of the threshold, so groups are placed purely
246246 // by load and a family is not kept together.
@@ -257,21 +257,66 @@ func TestAssign_SingleReplicaPlacesEverything(t *testing.T) {
257257 groupB := group (4 , []prefixhash.BlockHash {9 , 9 , 9 }, replicas )
258258 entries := concat (groupA , groupB )
259259
260- assign (entries , unlimitedPerReplica , 2 )
260+ assign (entries , unlimitedPerReplica , 2 , false )
261261
262262 for _ , e := range entries {
263263 assert .Equal (t , "pod1" , assignedName (e ), "with a single replica every request must land on it" )
264264 }
265265}
266266
267+ func TestAssign_BalanceByTokensSpreadsLargePrefix (t * testing.T ) {
268+ replicas := []fwksched.Endpoint {testEndpoint ("pod1" ), testEndpoint ("pod2" )}
269+ // One long-prefix unit and two short-prefix units with distinct prefixes.
270+ // Balancing by request count puts a short unit on the same replica as the long
271+ // one (block-imbalanced); balancing by tokens keeps the long unit alone and
272+ // packs the short ones onto the other replica.
273+ long := group (2 , []prefixhash.BlockHash {1 , 2 , 3 , 4 }, replicas )
274+ short1 := group (2 , []prefixhash.BlockHash {5 }, replicas )
275+ short2 := group (2 , []prefixhash.BlockHash {6 }, replicas )
276+
277+ byReq := concat (long , short1 , short2 )
278+ assign (byReq , unlimitedPerReplica , 0 , false )
279+ assert .Equal (t , assignedName (long [0 ]), assignedName (short2 [0 ]),
280+ "balancing by requests colocates a short unit with the long-prefix unit" )
281+
282+ long = group (2 , []prefixhash.BlockHash {1 , 2 , 3 , 4 }, replicas )
283+ short1 = group (2 , []prefixhash.BlockHash {5 }, replicas )
284+ short2 = group (2 , []prefixhash.BlockHash {6 }, replicas )
285+ byTok := concat (long , short1 , short2 )
286+ assign (byTok , unlimitedPerReplica , 0 , true )
287+ assert .NotEqual (t , assignedName (long [0 ]), assignedName (short1 [0 ]),
288+ "balancing by tokens keeps the long-prefix unit off the replica holding the short ones" )
289+ assert .Equal (t , assignedName (short1 [0 ]), assignedName (short2 [0 ]),
290+ "the short units pack onto one replica under token balancing" )
291+ }
292+
293+ func TestAssign_BalanceByTokensDiscountsSharedPrefix (t * testing.T ) {
294+ replicas := []fwksched.Endpoint {testEndpoint ("pod1" ), testEndpoint ("pod2" )}
295+ // Three units sharing a 9-block leading prefix. Charging each its full 10-block
296+ // prefix would push the third off the shared replica once the fair-share cap is
297+ // hit; discounting the already-prefilled 9 blocks keeps all three colocated so
298+ // the shared prefix is prefilled once.
299+ a1 := group (2 , []prefixhash.BlockHash {1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 }, replicas )
300+ a2 := group (2 , []prefixhash.BlockHash {1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 11 }, replicas )
301+ a3 := group (2 , []prefixhash.BlockHash {1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 12 }, replicas )
302+ entries := concat (a1 , a2 , a3 )
303+
304+ assign (entries , unlimitedPerReplica , 9 , true )
305+
306+ assert .Equal (t , assignedName (a1 [0 ]), assignedName (a2 [0 ]),
307+ "units sharing a prefix colocate when the shared prefill is not double-charged" )
308+ assert .Equal (t , assignedName (a2 [0 ]), assignedName (a3 [0 ]),
309+ "the shared-prefix discount keeps the third unit on the shared replica" )
310+ }
311+
267312func TestAssign_OverflowGuardBalancesBeyondCap (t * testing.T ) {
268313 replicas := []fwksched.Endpoint {testEndpoint ("pod1" ), testEndpoint ("pod2" )}
269314 // One group of 8 with k=2 over 2 replicas: k*replicas = 4 < 8, so the
270315 // per-replica cap cannot hold the whole group. The capLeft overflow guard must
271316 // still place every member and keep the batch balanced.
272317 entries := group (8 , []prefixhash.BlockHash {1 , 2 , 3 }, replicas )
273318
274- assign (entries , 2 , 0 )
319+ assign (entries , 2 , 0 , false )
275320
276321 for _ , e := range entries {
277322 assert .NotNil (t , e .assigned , "the overflow guard must still assign every member" )
0 commit comments