1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.tikv.common;
19
20 import static org.tikv.common.pd.PDUtils.addrToUri;
21
22 import com.google.common.annotations.Beta;
23 import io.etcd.jetcd.ByteSequence;
24 import io.etcd.jetcd.Client;
25 import io.etcd.jetcd.KeyValue;
26 import io.etcd.jetcd.kv.GetResponse;
27 import java.net.URI;
28 import java.nio.charset.StandardCharsets;
29 import java.util.List;
30 import java.util.concurrent.CompletableFuture;
31 import java.util.concurrent.ConcurrentHashMap;
32 import java.util.concurrent.ConcurrentMap;
33 import java.util.concurrent.ExecutionException;
34 import org.slf4j.Logger;
35 import org.slf4j.LoggerFactory;
36
37 public class DefaultHostMapping implements HostMapping {
38 private static final String NETWORK_MAPPING_PATH = "/client/url-mapping";
39 private final Client etcdClient;
40 private final String networkMappingName;
41 private final ConcurrentMap<String, String> hostMapping;
42 private final Logger logger = LoggerFactory.getLogger(DefaultHostMapping.class);
43
44 public DefaultHostMapping(Client etcdClient, String networkMappingName) {
45 this.etcdClient = etcdClient;
46 this.networkMappingName = networkMappingName;
47 this.hostMapping = new ConcurrentHashMap<>();
48 }
49
50 private ByteSequence hostToNetworkMappingKey(String host) {
51 String path = NETWORK_MAPPING_PATH + "/" + networkMappingName + "/" + host;
52 return ByteSequence.from(path, StandardCharsets.UTF_8);
53 }
54
55 @Beta
56 private String getMappedHostFromPD(String host) {
57 ByteSequence hostKey = hostToNetworkMappingKey(host);
58 for (int i = 0; i < 5; i++) {
59 CompletableFuture<GetResponse> future = etcdClient.getKVClient().get(hostKey);
60 try {
61 GetResponse resp = future.get();
62 List<KeyValue> kvs = resp.getKvs();
63 if (kvs.size() != 1) {
64 break;
65 }
66 return kvs.get(0).getValue().toString(StandardCharsets.UTF_8);
67 } catch (InterruptedException e) {
68 Thread.currentThread().interrupt();
69 } catch (ExecutionException e) {
70 logger.info("failed to get mapped Host from PD: " + host, e);
71 break;
72 } catch (Exception ignore) {
73
74 break;
75 }
76 }
77 return host;
78 }
79
80 public URI getMappedURI(URI uri) {
81 if (networkMappingName.isEmpty()) {
82 return uri;
83 }
84 return addrToUri(
85 hostMapping.computeIfAbsent(uri.getHost(), this::getMappedHostFromPD)
86 + ":"
87 + uri.getPort());
88 }
89 }