@@ -251,6 +251,57 @@ dom_wait_active(struct dynamic_domain *dom)
251
251
DBG (NULL , dom , "wait-active ret %d" , ret );
252
252
}
253
253
254
+ /* find a healthy dynamic_ref with the least connections */
255
+ static struct dynamic_ref *
256
+ dom_find_leastconn (VRT_CTX , struct dynamic_domain * dom )
257
+ {
258
+ struct dynamic_ref * next , * start , * best_next ;
259
+ unsigned most_connections_available ;
260
+
261
+ CHECK_OBJ_NOTNULL (ctx , VRT_CTX_MAGIC );
262
+ CHECK_OBJ_NOTNULL (dom , DYNAMIC_DOMAIN_MAGIC );
263
+
264
+ dom_wait_active (dom );
265
+
266
+ if (dom -> status > DYNAMIC_ST_ACTIVE )
267
+ return (NULL );
268
+
269
+ next = dom -> current ;
270
+ start = next ;
271
+ best_next = next ;
272
+ most_connections_available = 0 ;
273
+
274
+ do {
275
+ CHECK_OBJ_ORNULL (next , DYNAMIC_REF_MAGIC );
276
+ if (next != NULL )
277
+ next = VTAILQ_NEXT (next , list );
278
+ if (next == NULL )
279
+ next = VTAILQ_FIRST (& dom -> refs );
280
+ if (next == NULL )
281
+ break ;
282
+
283
+ if (next -> dir != creating && next -> dir != NULL && VRT_Healthy (ctx , next -> dir , NULL )) {
284
+ if (VALID_OBJ ((struct backend * )next -> dir -> priv , BACKEND_MAGIC )) {
285
+ struct backend * be ;
286
+ unsigned connections_available ;
287
+
288
+ CAST_OBJ_NOTNULL (be , next -> dir -> priv , BACKEND_MAGIC );
289
+ connections_available = be -> max_connections > 0 ? be -> max_connections - be -> n_conn : - be -> n_conn ;
290
+ if (connections_available > most_connections_available ) {
291
+ best_next = next ;
292
+ most_connections_available = connections_available ;
293
+ }
294
+ }
295
+ }
296
+ } while (next != start );
297
+
298
+ if (best_next != NULL ) {
299
+ return best_next ;
300
+ } else {
301
+ return NULL ;
302
+ }
303
+ }
304
+
254
305
/* find a healthy dynamic_ref */
255
306
static struct dynamic_ref *
256
307
dom_find (VRT_CTX , struct dynamic_domain * dom , struct dynamic_ref * start ,
@@ -330,7 +381,7 @@ static VCL_BACKEND v_matchproto_(vdi_resolve_f)
330
381
dom_resolve (VRT_CTX , VCL_BACKEND d )
331
382
{
332
383
struct dynamic_domain * dom ;
333
- struct dynamic_ref * r ;
384
+ struct dynamic_ref * r = NULL ;
334
385
VCL_BACKEND n = NULL ;
335
386
336
387
CHECK_OBJ_NOTNULL (ctx , VRT_CTX_MAGIC );
@@ -348,7 +399,12 @@ dom_resolve(VRT_CTX, VCL_BACKEND d)
348
399
dynamic_gc_expired (dom -> obj );
349
400
350
401
Lck_Lock (& dom -> mtx );
351
- r = dom_find (ctx , dom , dom -> current , NULL , NULL , 1 );
402
+ if (dom -> obj -> algorithm == LEAST ) {
403
+ r = dom_find_leastconn (ctx , dom );
404
+ }
405
+ if (r == NULL ) {
406
+ r = dom_find (ctx , dom , dom -> current , NULL , NULL , 1 );
407
+ }
352
408
dom -> current = r ;
353
409
if (r != NULL )
354
410
VRT_Assign_Backend (& n , r -> dir );
@@ -1306,6 +1362,18 @@ dynamic_ttl_parse(const char *s)
1306
1362
INCOMPL ();
1307
1363
}
1308
1364
1365
+ static inline enum dynamic_algorithm_e
1366
+ dynamic_algorithm_parse (const char * algorithm_s )
1367
+ {
1368
+ switch (algorithm_s [0 ]) {
1369
+ case 'R' : return RR ; break ;
1370
+ case 'L' : return LEAST ; break ;
1371
+ default : INCOMPL ();
1372
+ }
1373
+ INCOMPL ();
1374
+ NEEDLESS (return (0 ));
1375
+ }
1376
+
1309
1377
1310
1378
VCL_VOID v_matchproto_ ()
1311
1379
vmod_director__init (VRT_CTX ,
@@ -1329,7 +1397,8 @@ vmod_director__init(VRT_CTX,
1329
1397
VCL_DURATION retry_after ,
1330
1398
VCL_BACKEND via ,
1331
1399
VCL_INT keep ,
1332
- VCL_STRING authority )
1400
+ VCL_STRING authority ,
1401
+ VCL_ENUM algorithm_arg )
1333
1402
{
1334
1403
struct vmod_dynamic_director * obj ;
1335
1404
@@ -1402,6 +1471,7 @@ vmod_director__init(VRT_CTX,
1402
1471
obj -> max_connections = (unsigned )max_connections ;
1403
1472
obj -> proxy_header = (unsigned )proxy_header ;
1404
1473
obj -> ttl_from = dynamic_ttl_parse (ttl_from_arg );
1474
+ obj -> algorithm = dynamic_algorithm_parse (algorithm_arg );
1405
1475
obj -> keep = (unsigned )keep ;
1406
1476
1407
1477
if (resolver != NULL ) {
0 commit comments