3232import java .util .Objects ;
3333import java .util .concurrent .ThreadLocalRandom ;
3434import java .util .concurrent .atomic .AtomicLong ;
35+ import java .util .function .Predicate ;
3536
3637/**
3738 * Finds a server for a request using location-aware routing metadata.
4041 */
4142@ InternalApi
4243public final class ChannelFinder {
44+ private static final Predicate <String > NO_EXCLUDED_ENDPOINTS = address -> false ;
45+
4346 private final Object updateLock = new Object ();
4447 private final AtomicLong databaseId = new AtomicLong ();
4548 private final KeyRecipeCache recipeCache = new KeyRecipeCache ();
@@ -71,47 +74,83 @@ public void update(CacheUpdate update) {
7174 }
7275
7376 public ChannelEndpoint findServer (ReadRequest .Builder reqBuilder ) {
74- return findServer (reqBuilder , preferLeader (reqBuilder .getTransaction ()));
77+ return findServer (reqBuilder , preferLeader (reqBuilder .getTransaction ()), NO_EXCLUDED_ENDPOINTS );
78+ }
79+
80+ public ChannelEndpoint findServer (
81+ ReadRequest .Builder reqBuilder , Predicate <String > excludedEndpoints ) {
82+ return findServer (reqBuilder , preferLeader (reqBuilder .getTransaction ()), excludedEndpoints );
7583 }
7684
7785 public ChannelEndpoint findServer (ReadRequest .Builder reqBuilder , boolean preferLeader ) {
86+ return findServer (reqBuilder , preferLeader , NO_EXCLUDED_ENDPOINTS );
87+ }
88+
89+ public ChannelEndpoint findServer (
90+ ReadRequest .Builder reqBuilder , boolean preferLeader , Predicate <String > excludedEndpoints ) {
7891 recipeCache .computeKeys (reqBuilder );
7992 return fillRoutingHint (
8093 preferLeader ,
8194 KeyRangeCache .RangeMode .COVERING_SPLIT ,
8295 reqBuilder .getDirectedReadOptions (),
83- reqBuilder .getRoutingHintBuilder ());
96+ reqBuilder .getRoutingHintBuilder (),
97+ excludedEndpoints );
8498 }
8599
86100 public ChannelEndpoint findServer (ExecuteSqlRequest .Builder reqBuilder ) {
87- return findServer (reqBuilder , preferLeader (reqBuilder .getTransaction ()));
101+ return findServer (reqBuilder , preferLeader (reqBuilder .getTransaction ()), NO_EXCLUDED_ENDPOINTS );
102+ }
103+
104+ public ChannelEndpoint findServer (
105+ ExecuteSqlRequest .Builder reqBuilder , Predicate <String > excludedEndpoints ) {
106+ return findServer (reqBuilder , preferLeader (reqBuilder .getTransaction ()), excludedEndpoints );
88107 }
89108
90109 public ChannelEndpoint findServer (ExecuteSqlRequest .Builder reqBuilder , boolean preferLeader ) {
110+ return findServer (reqBuilder , preferLeader , NO_EXCLUDED_ENDPOINTS );
111+ }
112+
113+ public ChannelEndpoint findServer (
114+ ExecuteSqlRequest .Builder reqBuilder ,
115+ boolean preferLeader ,
116+ Predicate <String > excludedEndpoints ) {
91117 recipeCache .computeKeys (reqBuilder );
92118 return fillRoutingHint (
93119 preferLeader ,
94120 KeyRangeCache .RangeMode .PICK_RANDOM ,
95121 reqBuilder .getDirectedReadOptions (),
96- reqBuilder .getRoutingHintBuilder ());
122+ reqBuilder .getRoutingHintBuilder (),
123+ excludedEndpoints );
97124 }
98125
99126 public ChannelEndpoint findServer (BeginTransactionRequest .Builder reqBuilder ) {
127+ return findServer (reqBuilder , NO_EXCLUDED_ENDPOINTS );
128+ }
129+
130+ public ChannelEndpoint findServer (
131+ BeginTransactionRequest .Builder reqBuilder , Predicate <String > excludedEndpoints ) {
100132 if (!reqBuilder .hasMutationKey ()) {
101133 return null ;
102134 }
103135 return routeMutation (
104136 reqBuilder .getMutationKey (),
105137 preferLeader (reqBuilder .getOptions ()),
106- reqBuilder .getRoutingHintBuilder ());
138+ reqBuilder .getRoutingHintBuilder (),
139+ excludedEndpoints );
107140 }
108141
109142 public ChannelEndpoint fillRoutingHint (CommitRequest .Builder reqBuilder ) {
143+ return fillRoutingHint (reqBuilder , NO_EXCLUDED_ENDPOINTS );
144+ }
145+
146+ public ChannelEndpoint fillRoutingHint (
147+ CommitRequest .Builder reqBuilder , Predicate <String > excludedEndpoints ) {
110148 Mutation mutation = selectMutationForRouting (reqBuilder .getMutationsList ());
111149 if (mutation == null ) {
112150 return null ;
113151 }
114- return routeMutation (mutation , /* preferLeader= */ true , reqBuilder .getRoutingHintBuilder ());
152+ return routeMutation (
153+ mutation , /* preferLeader= */ true , reqBuilder .getRoutingHintBuilder (), excludedEndpoints );
115154 }
116155
117156 private static Mutation selectMutationForRouting (List <Mutation > mutations ) {
@@ -139,7 +178,10 @@ private static Mutation selectMutationForRouting(List<Mutation> mutations) {
139178 }
140179
141180 private ChannelEndpoint routeMutation (
142- Mutation mutation , boolean preferLeader , RoutingHint .Builder hintBuilder ) {
181+ Mutation mutation ,
182+ boolean preferLeader ,
183+ RoutingHint .Builder hintBuilder ,
184+ Predicate <String > excludedEndpoints ) {
143185 recipeCache .applySchemaGeneration (hintBuilder );
144186 TargetRange target = recipeCache .mutationToTargetRange (mutation );
145187 if (target == null ) {
@@ -150,20 +192,23 @@ private ChannelEndpoint routeMutation(
150192 preferLeader ,
151193 KeyRangeCache .RangeMode .COVERING_SPLIT ,
152194 DirectedReadOptions .getDefaultInstance (),
153- hintBuilder );
195+ hintBuilder ,
196+ excludedEndpoints );
154197 }
155198
156199 private ChannelEndpoint fillRoutingHint (
157200 boolean preferLeader ,
158201 KeyRangeCache .RangeMode rangeMode ,
159202 DirectedReadOptions directedReadOptions ,
160- RoutingHint .Builder hintBuilder ) {
203+ RoutingHint .Builder hintBuilder ,
204+ Predicate <String > excludedEndpoints ) {
161205 long id = databaseId .get ();
162206 if (id == 0 ) {
163207 return null ;
164208 }
165209 hintBuilder .setDatabaseId (id );
166- return rangeCache .fillRoutingHint (preferLeader , rangeMode , directedReadOptions , hintBuilder );
210+ return rangeCache .fillRoutingHint (
211+ preferLeader , rangeMode , directedReadOptions , hintBuilder , excludedEndpoints );
167212 }
168213
169214 private static boolean preferLeader (TransactionSelector selector ) {
0 commit comments