|
19 | 19 |
|
20 | 20 | package grakn.client;
|
21 | 21 |
|
22 |
| -import grakn.client.Grakn.Client; |
23 |
| -import grakn.client.Grakn.DatabaseManager; |
24 |
| -import grakn.client.Grakn.Session; |
| 22 | +import grakn.client.common.exception.GraknClientException; |
| 23 | +import grakn.client.rpc.Address; |
25 | 24 | import grakn.client.rpc.RPCDatabaseManager;
|
26 | 25 | import grakn.client.rpc.RPCSession;
|
| 26 | +import grakn.common.collection.Pair; |
| 27 | +import grakn.protocol.cluster.ClusterProto; |
| 28 | +import grakn.protocol.cluster.GraknClusterGrpc; |
27 | 29 | import io.grpc.Channel;
|
28 | 30 | import io.grpc.ManagedChannel;
|
29 | 31 | import io.grpc.ManagedChannelBuilder;
|
| 32 | +import io.grpc.StatusRuntimeException; |
| 33 | +import org.slf4j.Logger; |
| 34 | +import org.slf4j.LoggerFactory; |
30 | 35 |
|
| 36 | +import java.util.Map; |
| 37 | +import java.util.Set; |
31 | 38 | import java.util.concurrent.TimeUnit;
|
| 39 | +import java.util.concurrent.atomic.AtomicInteger; |
| 40 | +import java.util.stream.Collectors; |
32 | 41 |
|
33 |
| -public class GraknClient implements Client { |
| 42 | +import static grakn.client.common.exception.ErrorMessage.Client.CLUSTER_NOT_AVAILABLE; |
| 43 | +import static grakn.common.collection.Collections.pair; |
34 | 44 |
|
35 |
| - public static final String DEFAULT_URI = "localhost:1729"; |
| 45 | +public class GraknClient { |
| 46 | + public static final String DEFAULT_ADDRESS = "localhost:1729"; |
36 | 47 |
|
37 |
| - private final ManagedChannel channel; |
38 |
| - private final DatabaseManager databases; |
39 |
| - |
40 |
| - public GraknClient() { |
41 |
| - this(DEFAULT_URI); |
| 48 | + public static GraknClient.Core core() { |
| 49 | + return core(DEFAULT_ADDRESS); |
42 | 50 | }
|
43 | 51 |
|
44 |
| - public GraknClient(String address) { |
45 |
| - channel = ManagedChannelBuilder.forTarget(address).usePlaintext().build(); |
46 |
| - databases = new RPCDatabaseManager(channel); |
| 52 | + public static GraknClient.Core core(String address) { |
| 53 | + return new GraknClient.Core(address); |
47 | 54 | }
|
48 | 55 |
|
49 |
| - @Override |
50 |
| - public Session session(String database, Session.Type type) { |
51 |
| - return session(database, type, new GraknOptions()); |
| 56 | + public static GraknClient.Cluster cluster() { |
| 57 | + return new GraknClient.Cluster(DEFAULT_ADDRESS); |
52 | 58 | }
|
53 | 59 |
|
54 |
| - @Override |
55 |
| - public Session session(String database, Session.Type type, GraknOptions options) { |
56 |
| - return new RPCSession(this, database, type, options); |
| 60 | + public static GraknClient.Cluster cluster(String address) { |
| 61 | + return new GraknClient.Cluster(address); |
57 | 62 | }
|
58 | 63 |
|
59 |
| - @Override |
60 |
| - public DatabaseManager databases() { |
61 |
| - return databases; |
62 |
| - } |
| 64 | + public static class Core implements Grakn.Client { |
| 65 | + private final ManagedChannel channel; |
| 66 | + private final RPCDatabaseManager.Core databases; |
63 | 67 |
|
64 |
| - @Override |
65 |
| - public boolean isOpen() { |
66 |
| - return !channel.isShutdown(); |
67 |
| - } |
| 68 | + private Core(String address) { |
| 69 | + channel = ManagedChannelBuilder.forTarget(address).usePlaintext().build(); |
| 70 | + databases = new RPCDatabaseManager.Core(channel); |
| 71 | + } |
68 | 72 |
|
69 |
| - @Override |
70 |
| - public void close() { |
71 |
| - try { |
72 |
| - channel.shutdown().awaitTermination(10, TimeUnit.SECONDS); |
73 |
| - } catch (InterruptedException e) { |
74 |
| - Thread.currentThread().interrupt(); |
| 73 | + @Override |
| 74 | + public RPCSession.Core session(String database, Grakn.Session.Type type) { |
| 75 | + return session(database, type, new GraknOptions()); |
| 76 | + } |
| 77 | + |
| 78 | + @Override |
| 79 | + public RPCSession.Core session(String database, Grakn.Session.Type type, GraknOptions options) { |
| 80 | + return new RPCSession.Core(this, database, type, options); |
| 81 | + } |
| 82 | + |
| 83 | + @Override |
| 84 | + public RPCDatabaseManager.Core databases() { |
| 85 | + return databases; |
| 86 | + } |
| 87 | + |
| 88 | + @Override |
| 89 | + public boolean isOpen() { |
| 90 | + return !channel.isShutdown(); |
| 91 | + } |
| 92 | + |
| 93 | + @Override |
| 94 | + public void close() { |
| 95 | + try { |
| 96 | + channel.shutdown().awaitTermination(10, TimeUnit.SECONDS); |
| 97 | + } catch (InterruptedException e) { |
| 98 | + Thread.currentThread().interrupt(); |
| 99 | + } |
| 100 | + } |
| 101 | + |
| 102 | + public Channel channel() { |
| 103 | + return channel; |
75 | 104 | }
|
76 | 105 | }
|
77 | 106 |
|
78 |
| - public Channel channel() { |
79 |
| - return channel; |
| 107 | + public static class Cluster implements Grakn.Client { |
| 108 | + private static final Logger LOG = LoggerFactory.getLogger(Cluster.class); |
| 109 | + private final Map<Address.Cluster.Server, Core> coreClientMap; |
| 110 | + private final Core[] coreClientArray; |
| 111 | + private final AtomicInteger selectedCoreClientIndex; |
| 112 | + private GraknClusterGrpc.GraknClusterBlockingStub clusterDiscoveryRPC; |
| 113 | + private final RPCDatabaseManager.Cluster databases; |
| 114 | + private boolean isOpen; |
| 115 | + |
| 116 | + private Cluster(String address) { |
| 117 | + Pair<GraknClusterGrpc.GraknClusterBlockingStub, Set<Address.Cluster.Server>> discovery = discoverCluster(address); |
| 118 | + clusterDiscoveryRPC = discovery.first(); |
| 119 | + coreClientMap = discovery.second().stream() |
| 120 | + .map(addr -> pair(addr, new Core(addr.client()))) |
| 121 | + .collect(Collectors.toMap(Pair::first, Pair::second)); |
| 122 | + coreClientArray = coreClientMap.values().toArray(new Core[] {}); |
| 123 | + selectedCoreClientIndex = new AtomicInteger(); |
| 124 | + databases = new RPCDatabaseManager.Cluster( |
| 125 | + coreClientMap.entrySet().stream() |
| 126 | + .map(client -> pair(client.getKey(), client.getValue().databases())) |
| 127 | + .collect(Collectors.toMap(Pair::first, Pair::second)) |
| 128 | + ); |
| 129 | + isOpen = true; |
| 130 | + } |
| 131 | + |
| 132 | + @Override |
| 133 | + public RPCSession.Cluster session(String database, Grakn.Session.Type type) { |
| 134 | + return session(database, type, new GraknOptions()); |
| 135 | + } |
| 136 | + |
| 137 | + @Override |
| 138 | + public RPCSession.Cluster session(String database, Grakn.Session.Type type, GraknOptions options) { |
| 139 | + return new RPCSession.Cluster(this, database, type, options, clusterDiscoveryRPC); |
| 140 | + } |
| 141 | + |
| 142 | + public GraknClusterGrpc.GraknClusterBlockingStub selectNextClusterDiscoveryRPC() { |
| 143 | + Core selected = selectNextCoreClient(); |
| 144 | + clusterDiscoveryRPC = GraknClusterGrpc.newBlockingStub(selected.channel()); |
| 145 | + return clusterDiscoveryRPC; |
| 146 | + } |
| 147 | + |
| 148 | + @Override |
| 149 | + public RPCDatabaseManager.Cluster databases() { |
| 150 | + return databases; |
| 151 | + } |
| 152 | + |
| 153 | + @Override |
| 154 | + public boolean isOpen() { |
| 155 | + return isOpen; |
| 156 | + } |
| 157 | + |
| 158 | + @Override |
| 159 | + public void close() { |
| 160 | + coreClientMap.values().forEach(GraknClient.Core::close); |
| 161 | + isOpen = false; |
| 162 | + } |
| 163 | + |
| 164 | + public Map<Address.Cluster.Server, Core> coreClients() { |
| 165 | + return coreClientMap; |
| 166 | + } |
| 167 | + |
| 168 | + private Pair<GraknClusterGrpc.GraknClusterBlockingStub, Set<Address.Cluster.Server>> discoverCluster(String... addresses) { |
| 169 | + for (String address: addresses) { |
| 170 | + try (GraknClient.Core client = new Core(address)) { |
| 171 | + LOG.info("Performing server discovery to {}...", address); |
| 172 | + GraknClusterGrpc.GraknClusterBlockingStub clusterDiscoveryRPC = GraknClusterGrpc.newBlockingStub(client.channel()); |
| 173 | + ClusterProto.Cluster.Discover.Res res = |
| 174 | + clusterDiscoveryRPC.clusterDiscover(ClusterProto.Cluster.Discover.Req.newBuilder().build()); |
| 175 | + Set<Address.Cluster.Server> servers = res.getServersList().stream().map(Address.Cluster.Server::parse).collect(Collectors.toSet()); |
| 176 | + LOG.info("Discovered {}", servers); |
| 177 | + return pair(clusterDiscoveryRPC, servers); |
| 178 | + } catch (StatusRuntimeException e) { |
| 179 | + LOG.error("Server discovery to {} failed.", address); |
| 180 | + } |
| 181 | + } |
| 182 | + throw new GraknClientException(CLUSTER_NOT_AVAILABLE.message((Object) addresses)); // remove ambiguity by casting to Object |
| 183 | + } |
| 184 | + |
| 185 | + private Core selectNextCoreClient() { |
| 186 | + return coreClientArray[selectedCoreClientIndex.getAndIncrement() % coreClientMap.size()]; |
| 187 | + } |
80 | 188 | }
|
81 | 189 | }
|
0 commit comments