Skip to content
This repository was archived by the owner on Apr 7, 2026. It is now read-only.

Commit 4269aa6

Browse files
committed
Merge feat/channel-finder-interfaces
2 parents a6b8fc2 + 2c9da0d commit 4269aa6

3 files changed

Lines changed: 150 additions & 0 deletions

File tree

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/*
2+
* Copyright 2026 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.google.cloud.spanner.spi.v1;
18+
19+
import io.grpc.ManagedChannel;
20+
21+
/** Represents a Spanner server endpoint for location-aware routing. */
22+
public interface ChannelFinderServer {
23+
String getAddress();
24+
25+
boolean isHealthy();
26+
27+
ManagedChannel getChannel(); // Added to get the underlying channel for RPC calls
28+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/*
2+
* Copyright 2026 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.google.cloud.spanner.spi.v1;
18+
19+
/** Factory for creating and caching server connections for location-aware routing. */
20+
public interface ChannelFinderServerFactory {
21+
ChannelFinderServer defaultServer();
22+
23+
ChannelFinderServer create(String address);
24+
}
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
/*
2+
* Copyright 2026 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.google.cloud.spanner.spi.v1;
18+
19+
import com.google.api.gax.grpc.GrpcTransportChannel;
20+
import com.google.api.gax.grpc.InstantiatingGrpcChannelProvider;
21+
import io.grpc.ManagedChannel;
22+
import java.io.IOException;
23+
import java.util.Map;
24+
import java.util.concurrent.ConcurrentHashMap;
25+
26+
class GrpcChannelFinderServerFactory implements ChannelFinderServerFactory {
27+
private final InstantiatingGrpcChannelProvider.Builder channelBuilder;
28+
private final Map<String, GrpcChannelFinderServer> servers = new ConcurrentHashMap<>();
29+
private final GrpcChannelFinderServer defaultServer;
30+
31+
public GrpcChannelFinderServerFactory(InstantiatingGrpcChannelProvider.Builder channelBuilder)
32+
throws IOException {
33+
this.channelBuilder = channelBuilder;
34+
// The "default" server will use the original endpoint from the builder.
35+
this.defaultServer =
36+
new GrpcChannelFinderServer(this.channelBuilder.getEndpoint(), channelBuilder.build());
37+
this.servers.put(this.defaultServer.getAddress(), this.defaultServer);
38+
}
39+
40+
@Override
41+
public ChannelFinderServer defaultServer() {
42+
return defaultServer;
43+
}
44+
45+
@Override
46+
public ChannelFinderServer create(String address) {
47+
return servers.computeIfAbsent(
48+
address,
49+
addr -> {
50+
try {
51+
// Modify the builder to use the new address
52+
synchronized (channelBuilder) {
53+
InstantiatingGrpcChannelProvider.Builder newBuilder =
54+
channelBuilder.setEndpoint(addr);
55+
return new GrpcChannelFinderServer(addr, newBuilder.build());
56+
}
57+
} catch (IOException e) {
58+
throw new RuntimeException("Failed to create channel for address: " + addr, e);
59+
}
60+
});
61+
}
62+
63+
static class GrpcChannelFinderServer implements ChannelFinderServer {
64+
private final String address;
65+
private final ManagedChannel channel;
66+
67+
public GrpcChannelFinderServer(String address, InstantiatingGrpcChannelProvider provider)
68+
throws IOException {
69+
this.address = address;
70+
// It's assumed that getTransportChannel() returns a ManagedChannel or can be cast to one.
71+
// For this example, GrpcTransportChannel is used as in KeyAwareChannel.
72+
GrpcTransportChannel transportChannel = (GrpcTransportChannel) provider.getTransportChannel();
73+
this.channel = (ManagedChannel) transportChannel.getChannel();
74+
}
75+
76+
// Constructor for the default server that already has a channel
77+
public GrpcChannelFinderServer(String address, ManagedChannel channel) {
78+
this.address = address;
79+
this.channel = channel;
80+
}
81+
82+
@Override
83+
public String getAddress() {
84+
return address;
85+
}
86+
87+
@Override
88+
public boolean isHealthy() {
89+
// A simple health check. In a real scenario, this might involve a ping or other checks.
90+
return !channel.isShutdown() && !channel.isTerminated();
91+
}
92+
93+
@Override
94+
public ManagedChannel getChannel() {
95+
return channel;
96+
}
97+
}
98+
}

0 commit comments

Comments
 (0)