Skip to content

Commit eeaaac3

Browse files
committed
Move metadata internal API to use List instead of Set as replicas store
In almost all use cases replicas are getting converted into a List. To make performance better make these API provide List instead.
1 parent 7b6f2d4 commit eeaaac3

File tree

12 files changed

+178
-85
lines changed

12 files changed

+178
-85
lines changed

driver-core/src/main/java/com/datastax/driver/core/Metadata.java

Lines changed: 105 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
package com.datastax.driver.core;
2323

2424
import com.google.common.annotations.Beta;
25+
import com.google.common.collect.ImmutableList;
2526
import com.google.common.collect.ImmutableMap;
2627
import com.google.common.collect.ImmutableSet;
2728
import com.google.common.collect.Maps;
@@ -34,6 +35,7 @@
3435
import java.util.Collections;
3536
import java.util.HashMap;
3637
import java.util.HashSet;
38+
import java.util.LinkedHashSet;
3739
import java.util.List;
3840
import java.util.Map;
3941
import java.util.Set;
@@ -51,6 +53,8 @@
5153
public class Metadata {
5254

5355
private static final Logger logger = LoggerFactory.getLogger(Metadata.class);
56+
private static final ImmutableList<Host> EMPTY_LIST =
57+
ImmutableList.copyOf(Collections.emptyList());
5458

5559
final Cluster.Manager cluster;
5660
volatile String clusterName;
@@ -553,18 +557,48 @@ public Set<TokenRange> getTokenRanges(String keyspace, Host host) {
553557
* @return the (immutable) set of replicas for {@code partitionKey} as known by the driver. Note
554558
* that the result might be stale or empty if metadata was explicitly disabled with {@link
555559
* QueryOptions#setMetadataEnabled(boolean)}.
560+
* @deprecated use {@link Metadata#getReplicasList(String, String, Token.Factory, ByteBuffer)}
556561
*/
562+
@Deprecated
557563
@Beta
558564
public Set<Host> getReplicas(
559565
String keyspace, String table, Token.Factory partitioner, ByteBuffer partitionKey) {
566+
return new LinkedHashSet<>(this.getReplicasList(keyspace, table, partitioner, partitionKey));
567+
}
568+
569+
/**
570+
* Extension of legacy method {@link Metadata#getReplicas(String, Token.Factory, ByteBuffer)}.
571+
* Tablets model requires knowledge of the table name to determine the replicas. This method will
572+
* first try to lookup replicas through known tablets metadata. It will default to TokenMap lookup
573+
* if either {@code null} was passed as table name or the tablet lookup is unsuccessful for any
574+
* other reason.
575+
*
576+
* <p>Returns the set of hosts that are replica for a given partition key. Partitioner can be
577+
* {@code null} and then a cluster-wide partitioner will be invoked.
578+
*
579+
* <p>Note that this information is refreshed asynchronously by the control connection, when
580+
* schema or ring topology changes. It might occasionally be stale (or even empty).
581+
*
582+
* @param keyspace the name of the keyspace to get replicas for.
583+
* @param table the name of the table to get replicas for. Necessary for distinction for tablets.
584+
* Unnecessary for regular TokenMap
585+
* @param partitioner the partitioner to use or @{code null} for cluster-wide partitioner.
586+
* @param partitionKey the partition key for which to find the set of replica.
587+
* @return the (immutable) set of replicas for {@code partitionKey} as known by the driver. Note
588+
* that the result might be stale or empty if metadata was explicitly disabled with {@link
589+
* QueryOptions#setMetadataEnabled(boolean)}.
590+
*/
591+
@Beta
592+
public List<Host> getReplicasList(
593+
String keyspace, String table, Token.Factory partitioner, ByteBuffer partitionKey) {
560594
keyspace = handleId(keyspace);
561595
table = handleId(table);
562596
TokenMap current = tokenMap;
563597
if (partitioner == null && current != null) {
564598
partitioner = current.factory;
565599
}
566600
if (partitioner == null) {
567-
return Collections.emptySet();
601+
return Collections.emptyList();
568602
}
569603
Token token = partitioner.hash(partitionKey);
570604

@@ -575,14 +609,13 @@ public Set<Host> getReplicas(
575609
assert (token instanceof Token.TokenLong64);
576610
return tabletMap.getReplicas(keyspace, table, (long) token.getValue());
577611
} else {
578-
return Collections.emptySet();
612+
return Collections.emptyList();
579613
}
580614
}
581615

582616
// TokenMap:
583-
if (current == null) return Collections.<Host>emptySet();
584-
Set<Host> hosts = current.getReplicas(keyspace, token);
585-
return hosts == null ? Collections.<Host>emptySet() : hosts;
617+
if (current == null) return Collections.<Host>emptyList();
618+
return current.getReplicas(keyspace, token);
586619
}
587620

588621
/**
@@ -598,12 +631,33 @@ public Set<Host> getReplicas(
598631
* @return the (immutable) set of replicas for {@code partitionKey} as known by the driver. Note
599632
* that the result might be stale or empty if metadata was explicitly disabled with {@link
600633
* QueryOptions#setMetadataEnabled(boolean)}.
634+
* @deprecated use {@link Metadata#getReplicasList(String, Token.Factory, ByteBuffer)}
601635
*/
636+
@Deprecated
602637
public Set<Host> getReplicas(
603638
String keyspace, Token.Factory partitioner, ByteBuffer partitionKey) {
604639
return getReplicas(keyspace, null, partitioner, partitionKey);
605640
}
606641

642+
/**
643+
* Returns the immutable list of hosts that are replica for a given partition key. Partitioner can
644+
* be {@code null} and then a cluster-wide partitioner will be invoked.
645+
*
646+
* <p>Note that this information is refreshed asynchronously by the control connection, when
647+
* schema or ring topology changes. It might occasionally be stale (or even empty).
648+
*
649+
* @param keyspace the name of the keyspace to get replicas for.
650+
* @param partitioner the partitioner to use or @{code null} for cluster-wide partitioner.
651+
* @param partitionKey the partition key for which to find the set of replica.
652+
* @return the (immutable) list of replicas for {@code partitionKey} as known by the driver. Note
653+
* that the result might be stale or empty if metadata was explicitly disabled with {@link
654+
* QueryOptions#setMetadataEnabled(boolean)}.
655+
*/
656+
public List<Host> getReplicasList(
657+
String keyspace, Token.Factory partitioner, ByteBuffer partitionKey) {
658+
return getReplicasList(keyspace, null, partitioner, partitionKey);
659+
}
660+
607661
/**
608662
* Returns the set of hosts that are replica for a given token range.
609663
*
@@ -620,15 +674,42 @@ public Set<Host> getReplicas(
620674
* @return the (immutable) set of replicas for {@code range} as known by the driver. Note that the
621675
* result might be stale or empty if metadata was explicitly disabled with {@link
622676
* QueryOptions#setMetadataEnabled(boolean)}.
677+
* @deprecated use {@link Metadata#getReplicasList(String, TokenRange)}
623678
*/
624679
public Set<Host> getReplicas(String keyspace, TokenRange range) {
625680
keyspace = handleId(keyspace);
626681
TokenMap current = tokenMap;
627682
if (current == null) {
628683
return Collections.emptySet();
629684
} else {
630-
Set<Host> hosts = current.getReplicas(keyspace, range.getEnd());
631-
return hosts == null ? Collections.<Host>emptySet() : hosts;
685+
return new HashSet<>(current.getReplicas(keyspace, range.getEnd()));
686+
}
687+
}
688+
689+
/**
690+
* Returns the list of hosts that are replica for a given token range.
691+
*
692+
* <p>Note that it is assumed that the input range does not overlap across multiple host ranges.
693+
* If the range extends over multiple hosts, it only returns the replicas for those hosts that are
694+
* replicas for the last token of the range. This behavior may change in a future release, see <a
695+
* href="https://datastax-oss.atlassian.net/browse/JAVA-1355">JAVA-1355</a>.
696+
*
697+
* <p>Also note that this information is refreshed asynchronously by the control connection, when
698+
* schema or ring topology changes. It might occasionally be stale (or even empty).
699+
*
700+
* @param keyspace the name of the keyspace to get replicas for.
701+
* @param range the token range.
702+
* @return the list of replicas for {@code range} as known by the driver. Note that the result
703+
* might be stale or empty if metadata was explicitly disabled with {@link
704+
* QueryOptions#setMetadataEnabled(boolean)}.
705+
*/
706+
public List<Host> getReplicasList(String keyspace, TokenRange range) {
707+
keyspace = handleId(keyspace);
708+
TokenMap current = tokenMap;
709+
if (current == null) {
710+
return EMPTY_LIST;
711+
} else {
712+
return current.getReplicas(keyspace, range.getEnd());
632713
}
633714
}
634715

@@ -985,7 +1066,7 @@ private static class TokenMap {
9851066

9861067
private final Token.Factory factory;
9871068
private final Map<Host, Set<Token>> primaryToTokens;
988-
private final Map<String, Map<Token, Set<Host>>> tokenToHostsByKeyspace;
1069+
private final Map<String, Map<Token, ImmutableList<Host>>> tokenToHostsByKeyspace;
9891070
private final Map<String, Map<Host, Set<TokenRange>>> hostsToRangesByKeyspace;
9901071
private final List<Token> ring;
9911072
private final Set<TokenRange> tokenRanges;
@@ -997,7 +1078,7 @@ private TokenMap(
9971078
Set<TokenRange> tokenRanges,
9981079
Map<Token, Host> tokenToPrimary,
9991080
Map<Host, Set<Token>> primaryToTokens,
1000-
Map<String, Map<Token, Set<Host>>> tokenToHostsByKeyspace,
1081+
Map<String, Map<Token, ImmutableList<Host>>> tokenToHostsByKeyspace,
10011082
Map<String, Map<Host, Set<TokenRange>>> hostsToRangesByKeyspace) {
10021083
this.factory = factory;
10031084
this.ring = ring;
@@ -1042,15 +1123,13 @@ private static TokenMap build(
10421123
Set<TokenRange> tokenRanges,
10431124
Map<Token, Host> tokenToPrimary) {
10441125
Set<Host> hosts = allTokens.keySet();
1045-
Map<String, Map<Token, Set<Host>>> tokenToHosts =
1046-
new HashMap<String, Map<Token, Set<Host>>>();
1047-
Map<ReplicationStrategy, Map<Token, Set<Host>>> replStrategyToHosts =
1048-
new HashMap<ReplicationStrategy, Map<Token, Set<Host>>>();
1049-
Map<String, Map<Host, Set<TokenRange>>> hostsToRanges =
1050-
new HashMap<String, Map<Host, Set<TokenRange>>>();
1126+
Map<String, Map<Token, ImmutableList<Host>>> tokenToHosts = new HashMap<>();
1127+
Map<ReplicationStrategy, Map<Token, ImmutableList<Host>>> replStrategyToHosts =
1128+
new HashMap<>();
1129+
Map<String, Map<Host, Set<TokenRange>>> hostsToRanges = new HashMap<>();
10511130
for (KeyspaceMetadata keyspace : keyspaces) {
10521131
ReplicationStrategy strategy = keyspace.replicationStrategy();
1053-
Map<Token, Set<Host>> ksTokens = replStrategyToHosts.get(strategy);
1132+
Map<Token, ImmutableList<Host>> ksTokens = replStrategyToHosts.get(strategy);
10541133
if (ksTokens == null) {
10551134
ksTokens =
10561135
(strategy == null)
@@ -1077,14 +1156,14 @@ private static TokenMap build(
10771156
factory, ring, tokenRanges, tokenToPrimary, allTokens, tokenToHosts, hostsToRanges);
10781157
}
10791158

1080-
private Set<Host> getReplicas(String keyspace, Token token) {
1159+
private ImmutableList<Host> getReplicas(String keyspace, Token token) {
10811160

1082-
Map<Token, Set<Host>> tokenToHosts = tokenToHostsByKeyspace.get(keyspace);
1083-
if (tokenToHosts == null) return Collections.emptySet();
1161+
Map<Token, ImmutableList<Host>> tokenToHosts = tokenToHostsByKeyspace.get(keyspace);
1162+
if (tokenToHosts == null) return EMPTY_LIST;
10841163

10851164
// If the token happens to be one of the "primary" tokens, get result directly
1086-
Set<Host> hosts = tokenToHosts.get(token);
1087-
if (hosts != null) return hosts;
1165+
ImmutableList<Host> hosts = tokenToHosts.get(token);
1166+
if (hosts != null) return ImmutableList.copyOf(hosts);
10881167

10891168
// Otherwise, find closest "primary" token on the ring
10901169
int i = Collections.binarySearch(ring, token);
@@ -1096,10 +1175,10 @@ private Set<Host> getReplicas(String keyspace, Token token) {
10961175
return tokenToHosts.get(ring.get(i));
10971176
}
10981177

1099-
private static Map<Token, Set<Host>> makeNonReplicatedMap(Map<Token, Host> input) {
1100-
Map<Token, Set<Host>> output = new HashMap<Token, Set<Host>>(input.size());
1178+
private static Map<Token, ImmutableList<Host>> makeNonReplicatedMap(Map<Token, Host> input) {
1179+
Map<Token, ImmutableList<Host>> output = new HashMap<>(input.size());
11011180
for (Map.Entry<Token, Host> entry : input.entrySet())
1102-
output.put(entry.getKey(), ImmutableSet.of(entry.getValue()));
1181+
output.put(entry.getKey(), ImmutableList.of(entry.getValue()));
11031182
return output;
11041183
}
11051184

@@ -1119,11 +1198,11 @@ private static Set<TokenRange> makeTokenRanges(List<Token> ring, Token.Factory f
11191198
}
11201199

11211200
private static Map<Host, Set<TokenRange>> computeHostsToRangesMap(
1122-
Set<TokenRange> tokenRanges, Map<Token, Set<Host>> ksTokens, int hostCount) {
1201+
Set<TokenRange> tokenRanges, Map<Token, ImmutableList<Host>> ksTokens, int hostCount) {
11231202
Map<Host, ImmutableSet.Builder<TokenRange>> builders =
11241203
Maps.newHashMapWithExpectedSize(hostCount);
11251204
for (TokenRange range : tokenRanges) {
1126-
Set<Host> replicas = ksTokens.get(range.getEnd());
1205+
List<Host> replicas = ksTokens.get(range.getEnd());
11271206
for (Host host : replicas) {
11281207
ImmutableSet.Builder<TokenRange> hostRanges = builders.get(host);
11291208
if (hostRanges == null) {

driver-core/src/main/java/com/datastax/driver/core/ReplicationStategy.java

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
*/
1616
package com.datastax.driver.core;
1717

18-
import com.google.common.collect.ImmutableSet;
18+
import com.google.common.collect.ImmutableList;
1919
import com.google.common.collect.Maps;
2020
import com.google.common.collect.Sets;
2121
import java.util.HashMap;
@@ -67,7 +67,7 @@ static ReplicationStrategy create(Map<String, String> replicationOptions) {
6767
}
6868
}
6969

70-
abstract Map<Token, Set<Host>> computeTokenToReplicaMap(
70+
abstract Map<Token, ImmutableList<Host>> computeTokenToReplicaMap(
7171
String keyspaceName, Map<Token, Host> tokenToPrimary, List<Token> ring);
7272

7373
private static Token getTokenWrapping(int i, List<Token> ring) {
@@ -83,18 +83,18 @@ private SimpleStrategy(ReplicationFactor replicationFactor) {
8383
}
8484

8585
@Override
86-
Map<Token, Set<Host>> computeTokenToReplicaMap(
86+
Map<Token, ImmutableList<Host>> computeTokenToReplicaMap(
8787
String keyspaceName, Map<Token, Host> tokenToPrimary, List<Token> ring) {
8888

8989
int rf = Math.min(replicationFactor.fullReplicas(), ring.size());
9090

91-
Map<Token, Set<Host>> replicaMap = new HashMap<Token, Set<Host>>(tokenToPrimary.size());
91+
Map<Token, ImmutableList<Host>> replicaMap = new HashMap<>(tokenToPrimary.size());
9292
for (int i = 0; i < ring.size(); i++) {
9393
// Consecutive sections of the ring can assigned to the same host
94-
Set<Host> replicas = new LinkedHashSet<Host>();
94+
Set<Host> replicas = new LinkedHashSet<>();
9595
for (int j = 0; j < ring.size() && replicas.size() < rf; j++)
9696
replicas.add(tokenToPrimary.get(getTokenWrapping(i + j, ring)));
97-
replicaMap.put(ring.get(i), ImmutableSet.copyOf(replicas));
97+
replicaMap.put(ring.get(i), ImmutableList.copyOf(replicas));
9898
}
9999
return replicaMap;
100100
}
@@ -125,7 +125,7 @@ private NetworkTopologyStrategy(Map<String, ReplicationFactor> replicationFactor
125125
}
126126

127127
@Override
128-
Map<Token, Set<Host>> computeTokenToReplicaMap(
128+
Map<Token, ImmutableList<Host>> computeTokenToReplicaMap(
129129
String keyspaceName, Map<Token, Host> tokenToPrimary, List<Token> ring) {
130130

131131
logger.debug("Computing token to replica map for keyspace: {}.", keyspaceName);
@@ -135,7 +135,7 @@ Map<Token, Set<Host>> computeTokenToReplicaMap(
135135

136136
// This is essentially a copy of org.apache.cassandra.locator.NetworkTopologyStrategy
137137
Map<String, Set<String>> racks = getRacksInDcs(tokenToPrimary.values());
138-
Map<Token, Set<Host>> replicaMap = new HashMap<Token, Set<Host>>(tokenToPrimary.size());
138+
Map<Token, ImmutableList<Host>> replicaMap = new HashMap<>(tokenToPrimary.size());
139139
Map<String, Integer> dcHostCount = Maps.newHashMapWithExpectedSize(replicationFactors.size());
140140
Set<String> warnedDcs = Sets.newHashSetWithExpectedSize(replicationFactors.size());
141141
// find maximum number of nodes in each DC
@@ -157,7 +157,7 @@ Map<Token, Set<Host>> computeTokenToReplicaMap(
157157
}
158158

159159
// Preserve order - primary replica will be first
160-
Set<Host> replicas = new LinkedHashSet<Host>();
160+
Set<Host> replicas = new LinkedHashSet<>();
161161
for (int j = 0; j < ring.size() && !allDone(allDcReplicas, dcHostCount); j++) {
162162
Host h = tokenToPrimary.get(getTokenWrapping(i + j, ring));
163163
String dc = h.getDatacenter();
@@ -214,7 +214,7 @@ Map<Token, Set<Host>> computeTokenToReplicaMap(
214214
}
215215
}
216216

217-
replicaMap.put(ring.get(i), ImmutableSet.copyOf(replicas));
217+
replicaMap.put(ring.get(i), ImmutableList.copyOf(replicas));
218218
}
219219

220220
long duration = System.currentTimeMillis() - startTime;

driver-core/src/main/java/com/datastax/driver/core/RequestHandler.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,11 +121,11 @@ private Iterator<Host> getReplicas(
121121
tableName = defs.getTable(0);
122122
}
123123

124-
final Set<Host> replicas =
124+
final List<Host> replicas =
125125
manager
126126
.cluster
127127
.getMetadata()
128-
.getReplicas(Metadata.quote(keyspace), tableName, partitioner, partitionKey);
128+
.getReplicasList(Metadata.quote(keyspace), tableName, partitioner, partitionKey);
129129

130130
// replicas are stored in the right order starting with the primary replica
131131
return replicas.iterator();

driver-core/src/main/java/com/datastax/driver/core/SessionManager.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -659,6 +659,7 @@ else if (fetchSize != Integer.MAX_VALUE)
659659
boolean skipMetadata =
660660
protocolVersion != ProtocolVersion.V1
661661
&& bs.statement.getPreparedId().resultSetMetadata.variables != null;
662+
662663
Requests.QueryProtocolOptions options =
663664
new Requests.QueryProtocolOptions(
664665
Message.Request.Type.EXECUTE,

0 commit comments

Comments
 (0)