@@ -251,6 +251,57 @@ dom_wait_active(struct dynamic_domain *dom)
251251 DBG (NULL , dom , "wait-active ret %d" , ret );
252252}
253253
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+
254305/* find a healthy dynamic_ref */
255306static struct dynamic_ref *
256307dom_find (VRT_CTX , struct dynamic_domain * dom , struct dynamic_ref * start ,
@@ -330,7 +381,7 @@ static VCL_BACKEND v_matchproto_(vdi_resolve_f)
330381dom_resolve (VRT_CTX , VCL_BACKEND d )
331382{
332383 struct dynamic_domain * dom ;
333- struct dynamic_ref * r ;
384+ struct dynamic_ref * r = NULL ;
334385 VCL_BACKEND n = NULL ;
335386
336387 CHECK_OBJ_NOTNULL (ctx , VRT_CTX_MAGIC );
@@ -348,7 +399,12 @@ dom_resolve(VRT_CTX, VCL_BACKEND d)
348399 dynamic_gc_expired (dom -> obj );
349400
350401 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+ }
352408 dom -> current = r ;
353409 if (r != NULL )
354410 VRT_Assign_Backend (& n , r -> dir );
@@ -1306,6 +1362,18 @@ dynamic_ttl_parse(const char *s)
13061362 INCOMPL ();
13071363}
13081364
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+
13091377
13101378VCL_VOID v_matchproto_ ()
13111379vmod_director__init (VRT_CTX ,
@@ -1329,7 +1397,8 @@ vmod_director__init(VRT_CTX,
13291397 VCL_DURATION retry_after ,
13301398 VCL_BACKEND via ,
13311399 VCL_INT keep ,
1332- VCL_STRING authority )
1400+ VCL_STRING authority ,
1401+ VCL_ENUM algorithm_arg )
13331402{
13341403 struct vmod_dynamic_director * obj ;
13351404
@@ -1402,6 +1471,7 @@ vmod_director__init(VRT_CTX,
14021471 obj -> max_connections = (unsigned )max_connections ;
14031472 obj -> proxy_header = (unsigned )proxy_header ;
14041473 obj -> ttl_from = dynamic_ttl_parse (ttl_from_arg );
1474+ obj -> algorithm = dynamic_algorithm_parse (algorithm_arg );
14051475 obj -> keep = (unsigned )keep ;
14061476
14071477 if (resolver != NULL ) {
0 commit comments