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

Commit c4c9c69

Browse files
committed
feat: add ChannelFinder server interfaces for SpanFE bypass
This commit adds the server abstraction interfaces for the SpanFE bypass feature: - ChannelFinderServer: Interface representing a Spanner server endpoint with address, health check, and channel access - ChannelFinderServerFactory: Factory interface for creating and caching server connections - GrpcChannelFinderServerFactory: gRPC implementation that creates and manages gRPC channels for different server endpoints These interfaces enable the client to maintain connections to multiple Spanner servers and route requests directly to the appropriate server based on key location information. This is part of the SpanFE bypass feature that enables location-aware routing for improved latency.
1 parent e3fa634 commit c4c9c69

3 files changed

Lines changed: 100 additions & 0 deletions

File tree

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package com.google.cloud.spanner.spi.v1;
2+
3+
import io.grpc.ManagedChannel;
4+
5+
public interface ChannelFinderServer {
6+
String getAddress();
7+
8+
boolean isHealthy();
9+
10+
ManagedChannel getChannel(); // Added to get the underlying channel for RPC calls
11+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package com.google.cloud.spanner.spi.v1;
2+
3+
public interface ChannelFinderServerFactory {
4+
ChannelFinderServer defaultServer();
5+
6+
ChannelFinderServer create(String address);
7+
}
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
package com.google.cloud.spanner.spi.v1;
2+
3+
import com.google.api.gax.grpc.GrpcTransportChannel;
4+
import com.google.api.gax.grpc.InstantiatingGrpcChannelProvider;
5+
import io.grpc.ManagedChannel;
6+
import java.io.IOException;
7+
import java.util.Map;
8+
import java.util.concurrent.ConcurrentHashMap;
9+
10+
class GrpcChannelFinderServerFactory implements ChannelFinderServerFactory {
11+
private final InstantiatingGrpcChannelProvider.Builder channelBuilder;
12+
private final Map<String, GrpcChannelFinderServer> servers = new ConcurrentHashMap<>();
13+
private final GrpcChannelFinderServer defaultServer;
14+
15+
public GrpcChannelFinderServerFactory(InstantiatingGrpcChannelProvider.Builder channelBuilder)
16+
throws IOException {
17+
this.channelBuilder = channelBuilder;
18+
// The "default" server will use the original endpoint from the builder.
19+
this.defaultServer =
20+
new GrpcChannelFinderServer(this.channelBuilder.getEndpoint(), channelBuilder.build());
21+
this.servers.put(this.defaultServer.getAddress(), this.defaultServer);
22+
}
23+
24+
@Override
25+
public ChannelFinderServer defaultServer() {
26+
return defaultServer;
27+
}
28+
29+
@Override
30+
public ChannelFinderServer create(String address) {
31+
return servers.computeIfAbsent(
32+
address,
33+
addr -> {
34+
try {
35+
// Modify the builder to use the new address
36+
synchronized (channelBuilder) {
37+
InstantiatingGrpcChannelProvider.Builder newBuilder =
38+
channelBuilder.setEndpoint(addr);
39+
return new GrpcChannelFinderServer(addr, newBuilder.build());
40+
}
41+
} catch (IOException e) {
42+
throw new RuntimeException("Failed to create channel for address: " + addr, e);
43+
}
44+
});
45+
}
46+
47+
static class GrpcChannelFinderServer implements ChannelFinderServer {
48+
private final String address;
49+
private final ManagedChannel channel;
50+
51+
public GrpcChannelFinderServer(String address, InstantiatingGrpcChannelProvider provider)
52+
throws IOException {
53+
this.address = address;
54+
// It's assumed that getTransportChannel() returns a ManagedChannel or can be cast to one.
55+
// For this example, GrpcTransportChannel is used as in KeyAwareChannel.
56+
GrpcTransportChannel transportChannel = (GrpcTransportChannel) provider.getTransportChannel();
57+
this.channel = (ManagedChannel) transportChannel.getChannel();
58+
}
59+
60+
// Constructor for the default server that already has a channel
61+
public GrpcChannelFinderServer(String address, ManagedChannel channel) {
62+
this.address = address;
63+
this.channel = channel;
64+
}
65+
66+
@Override
67+
public String getAddress() {
68+
return address;
69+
}
70+
71+
@Override
72+
public boolean isHealthy() {
73+
// A simple health check. In a real scenario, this might involve a ping or other checks.
74+
return !channel.isShutdown() && !channel.isTerminated();
75+
}
76+
77+
@Override
78+
public ManagedChannel getChannel() {
79+
return channel;
80+
}
81+
}
82+
}

0 commit comments

Comments
 (0)