@@ -251,6 +251,54 @@ 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 , * 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 = VTAILQ_FIRST (& dom -> refs );
270+ best_next = NULL ;
271+ most_connections_available = 0 ;
272+
273+ do {
274+ CHECK_OBJ_ORNULL (next , DYNAMIC_REF_MAGIC );
275+ if (next != NULL )
276+ next = VTAILQ_NEXT (next , list );
277+ if (next == NULL )
278+ break ;
279+
280+ if (next -> dir != creating && next -> dir != NULL && VRT_Healthy (ctx , next -> dir , NULL )) {
281+ if (VALID_OBJ ((struct backend * )next -> dir -> priv , BACKEND_MAGIC )) {
282+ struct backend * be ;
283+ unsigned connections_available ;
284+
285+ CAST_OBJ_NOTNULL (be , next -> dir -> priv , BACKEND_MAGIC );
286+ connections_available = be -> max_connections > 0 ? be -> max_connections - be -> n_conn : - be -> n_conn ;
287+ if (connections_available > most_connections_available ) {
288+ best_next = next ;
289+ most_connections_available = connections_available ;
290+ }
291+ }
292+ }
293+ } while (1 );
294+
295+ if (best_next != NULL ) {
296+ return best_next ;
297+ } else {
298+ return NULL ;
299+ }
300+ }
301+
254302/* find a healthy dynamic_ref */
255303static struct dynamic_ref *
256304dom_find (VRT_CTX , struct dynamic_domain * dom , struct dynamic_ref * start ,
@@ -330,7 +378,7 @@ static VCL_BACKEND v_matchproto_(vdi_resolve_f)
330378dom_resolve (VRT_CTX , VCL_BACKEND d )
331379{
332380 struct dynamic_domain * dom ;
333- struct dynamic_ref * r ;
381+ struct dynamic_ref * r = NULL ;
334382 VCL_BACKEND n = NULL ;
335383
336384 CHECK_OBJ_NOTNULL (ctx , VRT_CTX_MAGIC );
@@ -348,7 +396,12 @@ dom_resolve(VRT_CTX, VCL_BACKEND d)
348396 dynamic_gc_expired (dom -> obj );
349397
350398 Lck_Lock (& dom -> mtx );
351- r = dom_find (ctx , dom , dom -> current , NULL , NULL , 1 );
399+ if (dom -> obj -> algorithm == LEAST ) {
400+ r = dom_find_leastconn (ctx , dom );
401+ }
402+ if (r == NULL ) {
403+ r = dom_find (ctx , dom , dom -> current , NULL , NULL , 1 );
404+ }
352405 dom -> current = r ;
353406 if (r != NULL )
354407 VRT_Assign_Backend (& n , r -> dir );
@@ -1306,6 +1359,18 @@ dynamic_ttl_parse(const char *s)
13061359 INCOMPL ();
13071360}
13081361
1362+ static inline enum dynamic_algorithm_e
1363+ dynamic_algorithm_parse (const char * algorithm_s )
1364+ {
1365+ switch (algorithm_s [0 ]) {
1366+ case 'R' : return RR ; break ;
1367+ case 'L' : return LEAST ; break ;
1368+ default : INCOMPL ();
1369+ }
1370+ INCOMPL ();
1371+ NEEDLESS (return (0 ));
1372+ }
1373+
13091374
13101375VCL_VOID v_matchproto_ ()
13111376vmod_director__init (VRT_CTX ,
@@ -1329,7 +1394,8 @@ vmod_director__init(VRT_CTX,
13291394 VCL_DURATION retry_after ,
13301395 VCL_BACKEND via ,
13311396 VCL_INT keep ,
1332- VCL_STRING authority )
1397+ VCL_STRING authority ,
1398+ VCL_ENUM algorithm_arg )
13331399{
13341400 struct vmod_dynamic_director * obj ;
13351401
@@ -1402,6 +1468,7 @@ vmod_director__init(VRT_CTX,
14021468 obj -> max_connections = (unsigned )max_connections ;
14031469 obj -> proxy_header = (unsigned )proxy_header ;
14041470 obj -> ttl_from = dynamic_ttl_parse (ttl_from_arg );
1471+ obj -> algorithm = dynamic_algorithm_parse (algorithm_arg );
14051472 obj -> keep = (unsigned )keep ;
14061473
14071474 if (resolver != NULL ) {
0 commit comments