1313 */
1414package io .trino .gateway .ha .router ;
1515
16+ import com .google .common .cache .CacheBuilder ;
17+ import com .google .common .cache .CacheLoader ;
18+ import com .google .common .cache .LoadingCache ;
1619import com .google .common .collect .ImmutableList ;
20+ import com .google .common .util .concurrent .MoreExecutors ;
1721import io .airlift .log .Logger ;
22+ import io .airlift .stats .CounterStat ;
1823import io .trino .gateway .ha .config .ProxyBackendConfiguration ;
1924import io .trino .gateway .ha .config .RoutingConfiguration ;
2025import io .trino .gateway .ha .persistence .dao .GatewayBackend ;
2429import java .util .ArrayList ;
2530import java .util .List ;
2631import java .util .Optional ;
32+ import java .util .concurrent .Executors ;
2733
2834import static com .google .common .base .Preconditions .checkState ;
35+ import static com .google .common .collect .ImmutableList .toImmutableList ;
2936import static java .util .Objects .requireNonNull ;
3037
3138public class HaGatewayManager
3239 implements GatewayBackendManager
3340{
3441 private static final Logger log = Logger .get (HaGatewayManager .class );
42+ private static final Object ALL_BACKEND_CACHE_KEY = new Object ();
3543
3644 private final GatewayBackendDao dao ;
3745 private final String defaultRoutingGroup ;
46+ private final boolean cacheEnabled ;
47+ private final LoadingCache <Object , List <GatewayBackend >> backendCache ;
48+
49+ private final CounterStat backendLookupSuccesses = new CounterStat ();
50+ private final CounterStat backendLookupFailures = new CounterStat ();
3851
3952 public HaGatewayManager (Jdbi jdbi , RoutingConfiguration routingConfiguration )
4053 {
4154 dao = requireNonNull (jdbi , "jdbi is null" ).onDemand (GatewayBackendDao .class );
4255 this .defaultRoutingGroup = routingConfiguration .getDefaultRoutingGroup ();
56+ if (!routingConfiguration .getDatabaseCacheTTL ().isZero ()) {
57+ cacheEnabled = true ;
58+ backendCache = CacheBuilder
59+ .newBuilder ()
60+ .initialCapacity (1 )
61+ .refreshAfterWrite (routingConfiguration .getDatabaseCacheTTL ().toJavaTime ())
62+ .build (CacheLoader .asyncReloading (
63+ CacheLoader .from (this ::fetchAllBackends ),
64+ MoreExecutors .listeningDecorator (Executors .newSingleThreadExecutor ())));
65+ // Load the data once during initialization. This ensures a fail-fast behavior in case of database misconfiguration.
66+ backendCache .getUnchecked (ALL_BACKEND_CACHE_KEY );
67+ }
68+ else {
69+ cacheEnabled = false ;
70+ backendCache = null ;
71+ }
72+ }
73+
74+ private List <GatewayBackend > fetchAllBackends ()
75+ {
76+ try {
77+ List <GatewayBackend > backends = dao .findAll ();
78+ backendLookupSuccesses .update (1 );
79+ return backends ;
80+ }
81+ catch (Exception e ) {
82+ backendLookupFailures .update (1 );
83+ log .warn (e , "Failed to fetch backends" );
84+ throw e ;
85+ }
86+ }
87+
88+ private void invalidateBackendCache ()
89+ {
90+ if (cacheEnabled ) {
91+ backendCache .invalidateAll ();
92+ }
93+ }
94+
95+ private List <GatewayBackend > getOrFetchAllBackends ()
96+ {
97+ if (cacheEnabled ) {
98+ return backendCache .getUnchecked (ALL_BACKEND_CACHE_KEY );
99+ }
100+ else {
101+ return fetchAllBackends ();
102+ }
43103 }
44104
45105 @ Override
46106 public List <ProxyBackendConfiguration > getAllBackends ()
47107 {
48- List <GatewayBackend > proxyBackendList = dao . findAll ();
108+ List <GatewayBackend > proxyBackendList = getOrFetchAllBackends ();
49109 return upcast (proxyBackendList );
50110 }
51111
52112 @ Override
53113 public List <ProxyBackendConfiguration > getAllActiveBackends ()
54114 {
55- List <GatewayBackend > proxyBackendList = dao .findActiveBackend ();
115+ List <GatewayBackend > proxyBackendList = getOrFetchAllBackends ().stream ()
116+ .filter (GatewayBackend ::active )
117+ .collect (toImmutableList ());
56118 return upcast (proxyBackendList );
57119 }
58120
@@ -71,14 +133,19 @@ public List<ProxyBackendConfiguration> getActiveDefaultBackends()
71133 @ Override
72134 public List <ProxyBackendConfiguration > getActiveBackends (String routingGroup )
73135 {
74- List <GatewayBackend > proxyBackendList = dao .findActiveBackendByRoutingGroup (routingGroup );
136+ List <GatewayBackend > proxyBackendList = getOrFetchAllBackends ().stream ()
137+ .filter (GatewayBackend ::active )
138+ .filter (backend -> backend .routingGroup ().equals (routingGroup ))
139+ .collect (toImmutableList ());
75140 return upcast (proxyBackendList );
76141 }
77142
78143 @ Override
79144 public Optional <ProxyBackendConfiguration > getBackendByName (String name )
80145 {
81- List <GatewayBackend > proxyBackendList = dao .findByName (name );
146+ List <GatewayBackend > proxyBackendList = getOrFetchAllBackends ().stream ()
147+ .filter (backend -> backend .name ().equals (name ))
148+ .collect (toImmutableList ());
82149 return upcast (proxyBackendList ).stream ().findAny ();
83150 }
84151
@@ -102,6 +169,7 @@ private void updateClusterActivationStatus(String clusterName, boolean newStatus
102169 boolean previousStatus = model .active ();
103170 changeActiveStatus .run ();
104171 logActivationStatusChange (clusterName , newStatus , previousStatus );
172+ invalidateBackendCache ();
105173 }
106174
107175 private static void logActivationStatusChange (String clusterName , boolean newStatus , boolean previousStatus )
@@ -117,6 +185,7 @@ public ProxyBackendConfiguration addBackend(ProxyBackendConfiguration backend)
117185 String backendProxyTo = removeTrailingSlash (backend .getProxyTo ());
118186 String backendExternalUrl = removeTrailingSlash (backend .getExternalUrl ());
119187 dao .create (backend .getName (), backend .getRoutingGroup (), backendProxyTo , backendExternalUrl , backend .isActive ());
188+ invalidateBackendCache ();
120189 return backend ;
121190 }
122191
@@ -133,12 +202,14 @@ public ProxyBackendConfiguration updateBackend(ProxyBackendConfiguration backend
133202 dao .update (backend .getName (), backend .getRoutingGroup (), backendProxyTo , backendExternalUrl , backend .isActive ());
134203 logActivationStatusChange (backend .getName (), backend .isActive (), model .active ());
135204 }
205+ invalidateBackendCache ();
136206 return backend ;
137207 }
138208
139209 public void deleteBackend (String name )
140210 {
141211 dao .deleteByName (name );
212+ invalidateBackendCache ();
142213 }
143214
144215 private static List <ProxyBackendConfiguration > upcast (List <GatewayBackend > gatewayBackendList )
0 commit comments