22
22
package com .datastax .driver .core ;
23
23
24
24
import com .google .common .annotations .Beta ;
25
+ import com .google .common .collect .ImmutableList ;
25
26
import com .google .common .collect .ImmutableMap ;
26
27
import com .google .common .collect .ImmutableSet ;
27
28
import com .google .common .collect .Maps ;
34
35
import java .util .Collections ;
35
36
import java .util .HashMap ;
36
37
import java .util .HashSet ;
38
+ import java .util .LinkedHashSet ;
37
39
import java .util .List ;
38
40
import java .util .Map ;
39
41
import java .util .Set ;
51
53
public class Metadata {
52
54
53
55
private static final Logger logger = LoggerFactory .getLogger (Metadata .class );
56
+ private static final ImmutableList <Host > EMPTY_LIST = ImmutableList .of ();
54
57
55
58
final Cluster .Manager cluster ;
56
59
volatile String clusterName ;
@@ -553,18 +556,48 @@ public Set<TokenRange> getTokenRanges(String keyspace, Host host) {
553
556
* @return the (immutable) set of replicas for {@code partitionKey} as known by the driver. Note
554
557
* that the result might be stale or empty if metadata was explicitly disabled with {@link
555
558
* QueryOptions#setMetadataEnabled(boolean)}.
559
+ * @deprecated use {@link Metadata#getReplicasList(String, String, Token.Factory, ByteBuffer)}
556
560
*/
561
+ @ Deprecated
557
562
@ Beta
558
563
public Set <Host > getReplicas (
559
564
String keyspace , String table , Token .Factory partitioner , ByteBuffer partitionKey ) {
565
+ return new LinkedHashSet <>(this .getReplicasList (keyspace , table , partitioner , partitionKey ));
566
+ }
567
+
568
+ /**
569
+ * Extension of legacy method {@link Metadata#getReplicas(String, Token.Factory, ByteBuffer)}.
570
+ * Tablets model requires knowledge of the table name to determine the replicas. This method will
571
+ * first try to lookup replicas through known tablets metadata. It will default to TokenMap lookup
572
+ * if either {@code null} was passed as table name or the tablet lookup is unsuccessful for any
573
+ * other reason.
574
+ *
575
+ * <p>Returns the list of hosts that are replica for a given partition key. Partitioner can be
576
+ * {@code null} and then a cluster-wide partitioner will be invoked.
577
+ *
578
+ * <p>Note that this information is refreshed asynchronously by the control connection, when
579
+ * schema or ring topology changes. It might occasionally be stale (or even empty).
580
+ *
581
+ * @param keyspace the name of the keyspace to get replicas for.
582
+ * @param table the name of the table to get replicas for. Necessary for distinction for tablets.
583
+ * Unnecessary for regular TokenMap
584
+ * @param partitioner the partitioner to use or @{code null} for cluster-wide partitioner.
585
+ * @param partitionKey the partition key for which to find the list of replica.
586
+ * @return the (immutable) list of replicas for {@code partitionKey} as known by the driver. Note
587
+ * that the result might be stale or empty if metadata was explicitly disabled with {@link
588
+ * QueryOptions#setMetadataEnabled(boolean)}.
589
+ */
590
+ @ Beta
591
+ public List <Host > getReplicasList (
592
+ String keyspace , String table , Token .Factory partitioner , ByteBuffer partitionKey ) {
560
593
keyspace = handleId (keyspace );
561
594
table = handleId (table );
562
595
TokenMap current = tokenMap ;
563
596
if (partitioner == null && current != null ) {
564
597
partitioner = current .factory ;
565
598
}
566
599
if (partitioner == null ) {
567
- return Collections . emptySet () ;
600
+ return EMPTY_LIST ;
568
601
}
569
602
Token token = partitioner .hash (partitionKey );
570
603
@@ -575,14 +608,13 @@ public Set<Host> getReplicas(
575
608
assert (token instanceof Token .TokenLong64 );
576
609
return tabletMap .getReplicas (keyspace , table , (long ) token .getValue ());
577
610
} else {
578
- return Collections . emptySet () ;
611
+ return EMPTY_LIST ;
579
612
}
580
613
}
581
614
582
615
// 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 ;
616
+ if (current == null ) return EMPTY_LIST ;
617
+ return current .getReplicas (keyspace , token );
586
618
}
587
619
588
620
/**
@@ -598,12 +630,33 @@ public Set<Host> getReplicas(
598
630
* @return the (immutable) set of replicas for {@code partitionKey} as known by the driver. Note
599
631
* that the result might be stale or empty if metadata was explicitly disabled with {@link
600
632
* QueryOptions#setMetadataEnabled(boolean)}.
633
+ * @deprecated use {@link Metadata#getReplicasList(String, Token.Factory, ByteBuffer)}
601
634
*/
635
+ @ Deprecated
602
636
public Set <Host > getReplicas (
603
637
String keyspace , Token .Factory partitioner , ByteBuffer partitionKey ) {
604
638
return getReplicas (keyspace , null , partitioner , partitionKey );
605
639
}
606
640
641
+ /**
642
+ * Returns the immutable list of hosts that are replica for a given partition key. Partitioner can
643
+ * be {@code null} and then a cluster-wide partitioner will be invoked.
644
+ *
645
+ * <p>Note that this information is refreshed asynchronously by the control connection, when
646
+ * schema or ring topology changes. It might occasionally be stale (or even empty).
647
+ *
648
+ * @param keyspace the name of the keyspace to get replicas for.
649
+ * @param partitioner the partitioner to use or @{code null} for cluster-wide partitioner.
650
+ * @param partitionKey the partition key for which to find the set of replica.
651
+ * @return the (immutable) list of replicas for {@code partitionKey} as known by the driver. Note
652
+ * that the result might be stale or empty if metadata was explicitly disabled with {@link
653
+ * QueryOptions#setMetadataEnabled(boolean)}.
654
+ */
655
+ public List <Host > getReplicasList (
656
+ String keyspace , Token .Factory partitioner , ByteBuffer partitionKey ) {
657
+ return getReplicasList (keyspace , null , partitioner , partitionKey );
658
+ }
659
+
607
660
/**
608
661
* Returns the set of hosts that are replica for a given token range.
609
662
*
@@ -620,15 +673,42 @@ public Set<Host> getReplicas(
620
673
* @return the (immutable) set of replicas for {@code range} as known by the driver. Note that the
621
674
* result might be stale or empty if metadata was explicitly disabled with {@link
622
675
* QueryOptions#setMetadataEnabled(boolean)}.
676
+ * @deprecated use {@link Metadata#getReplicasList(String, TokenRange)}
623
677
*/
624
678
public Set <Host > getReplicas (String keyspace , TokenRange range ) {
625
679
keyspace = handleId (keyspace );
626
680
TokenMap current = tokenMap ;
627
681
if (current == null ) {
628
682
return Collections .emptySet ();
629
683
} else {
630
- Set <Host > hosts = current .getReplicas (keyspace , range .getEnd ());
631
- return hosts == null ? Collections .<Host >emptySet () : hosts ;
684
+ return new HashSet <>(current .getReplicas (keyspace , range .getEnd ()));
685
+ }
686
+ }
687
+
688
+ /**
689
+ * Returns the list of hosts that are replica for a given token range.
690
+ *
691
+ * <p>Note that it is assumed that the input range does not overlap across multiple host ranges.
692
+ * If the range extends over multiple hosts, it only returns the replicas for those hosts that are
693
+ * replicas for the last token of the range. This behavior may change in a future release, see <a
694
+ * href="https://datastax-oss.atlassian.net/browse/JAVA-1355">JAVA-1355</a>.
695
+ *
696
+ * <p>Also note that this information is refreshed asynchronously by the control connection, when
697
+ * schema or ring topology changes. It might occasionally be stale (or even empty).
698
+ *
699
+ * @param keyspace the name of the keyspace to get replicas for.
700
+ * @param range the token range.
701
+ * @return the list of replicas for {@code range} as known by the driver. Note that the result
702
+ * might be stale or empty if metadata was explicitly disabled with {@link
703
+ * QueryOptions#setMetadataEnabled(boolean)}.
704
+ */
705
+ public List <Host > getReplicasList (String keyspace , TokenRange range ) {
706
+ keyspace = handleId (keyspace );
707
+ TokenMap current = tokenMap ;
708
+ if (current == null ) {
709
+ return EMPTY_LIST ;
710
+ } else {
711
+ return current .getReplicas (keyspace , range .getEnd ());
632
712
}
633
713
}
634
714
@@ -985,7 +1065,7 @@ private static class TokenMap {
985
1065
986
1066
private final Token .Factory factory ;
987
1067
private final Map <Host , Set <Token >> primaryToTokens ;
988
- private final Map <String , Map <Token , Set <Host >>> tokenToHostsByKeyspace ;
1068
+ private final Map <String , Map <Token , ImmutableList <Host >>> tokenToHostsByKeyspace ;
989
1069
private final Map <String , Map <Host , Set <TokenRange >>> hostsToRangesByKeyspace ;
990
1070
private final List <Token > ring ;
991
1071
private final Set <TokenRange > tokenRanges ;
@@ -997,7 +1077,7 @@ private TokenMap(
997
1077
Set <TokenRange > tokenRanges ,
998
1078
Map <Token , Host > tokenToPrimary ,
999
1079
Map <Host , Set <Token >> primaryToTokens ,
1000
- Map <String , Map <Token , Set <Host >>> tokenToHostsByKeyspace ,
1080
+ Map <String , Map <Token , ImmutableList <Host >>> tokenToHostsByKeyspace ,
1001
1081
Map <String , Map <Host , Set <TokenRange >>> hostsToRangesByKeyspace ) {
1002
1082
this .factory = factory ;
1003
1083
this .ring = ring ;
@@ -1042,15 +1122,13 @@ private static TokenMap build(
1042
1122
Set <TokenRange > tokenRanges ,
1043
1123
Map <Token , Host > tokenToPrimary ) {
1044
1124
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 >>>();
1125
+ Map <String , Map <Token , ImmutableList <Host >>> tokenToHosts = new HashMap <>();
1126
+ Map <ReplicationStrategy , Map <Token , ImmutableList <Host >>> replStrategyToHosts =
1127
+ new HashMap <>();
1128
+ Map <String , Map <Host , Set <TokenRange >>> hostsToRanges = new HashMap <>();
1051
1129
for (KeyspaceMetadata keyspace : keyspaces ) {
1052
1130
ReplicationStrategy strategy = keyspace .replicationStrategy ();
1053
- Map <Token , Set <Host >> ksTokens = replStrategyToHosts .get (strategy );
1131
+ Map <Token , ImmutableList <Host >> ksTokens = replStrategyToHosts .get (strategy );
1054
1132
if (ksTokens == null ) {
1055
1133
ksTokens =
1056
1134
(strategy == null )
@@ -1077,14 +1155,14 @@ private static TokenMap build(
1077
1155
factory , ring , tokenRanges , tokenToPrimary , allTokens , tokenToHosts , hostsToRanges );
1078
1156
}
1079
1157
1080
- private Set <Host > getReplicas (String keyspace , Token token ) {
1158
+ private ImmutableList <Host > getReplicas (String keyspace , Token token ) {
1081
1159
1082
- Map <Token , Set <Host >> tokenToHosts = tokenToHostsByKeyspace .get (keyspace );
1083
- if (tokenToHosts == null ) return Collections . emptySet () ;
1160
+ Map <Token , ImmutableList <Host >> tokenToHosts = tokenToHostsByKeyspace .get (keyspace );
1161
+ if (tokenToHosts == null ) return EMPTY_LIST ;
1084
1162
1085
1163
// 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 ;
1164
+ ImmutableList <Host > hosts = tokenToHosts .get (token );
1165
+ if (hosts != null ) return ImmutableList . copyOf ( hosts ) ;
1088
1166
1089
1167
// Otherwise, find closest "primary" token on the ring
1090
1168
int i = Collections .binarySearch (ring , token );
@@ -1096,10 +1174,10 @@ private Set<Host> getReplicas(String keyspace, Token token) {
1096
1174
return tokenToHosts .get (ring .get (i ));
1097
1175
}
1098
1176
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 ());
1177
+ private static Map <Token , ImmutableList <Host >> makeNonReplicatedMap (Map <Token , Host > input ) {
1178
+ Map <Token , ImmutableList <Host >> output = new HashMap <>(input .size ());
1101
1179
for (Map .Entry <Token , Host > entry : input .entrySet ())
1102
- output .put (entry .getKey (), ImmutableSet .of (entry .getValue ()));
1180
+ output .put (entry .getKey (), ImmutableList .of (entry .getValue ()));
1103
1181
return output ;
1104
1182
}
1105
1183
@@ -1119,11 +1197,11 @@ private static Set<TokenRange> makeTokenRanges(List<Token> ring, Token.Factory f
1119
1197
}
1120
1198
1121
1199
private static Map <Host , Set <TokenRange >> computeHostsToRangesMap (
1122
- Set <TokenRange > tokenRanges , Map <Token , Set <Host >> ksTokens , int hostCount ) {
1200
+ Set <TokenRange > tokenRanges , Map <Token , ImmutableList <Host >> ksTokens , int hostCount ) {
1123
1201
Map <Host , ImmutableSet .Builder <TokenRange >> builders =
1124
1202
Maps .newHashMapWithExpectedSize (hostCount );
1125
1203
for (TokenRange range : tokenRanges ) {
1126
- Set <Host > replicas = ksTokens .get (range .getEnd ());
1204
+ List <Host > replicas = ksTokens .get (range .getEnd ());
1127
1205
for (Host host : replicas ) {
1128
1206
ImmutableSet .Builder <TokenRange > hostRanges = builders .get (host );
1129
1207
if (hostRanges == null ) {
0 commit comments