Enable cross cluster search only when at least one remote cluster is configured

If no remote clusters are registered, we shouldn't even try resolving remote clusters as part of indices names. Just go ahead and treat the index as a local one, which may or may not exist. In fact, the character that we use a separator may be part of an alias name, or part of a date math expression. We will go ahead with the remote search only if the prefix before the first occurrence of the separator is an actual registered cluster. Otherwise we will treat the index as a local one.

Previously we would go remotely anytime we'd find the separator in an index name, which caused false positives with aliases and date math expressions. It is also safer to not go remotely unless there is some remote cluster registered. We'd also throw exception whenever an unknown remote cluster was referred to, but this could again conflict with date math expressions or aliases: say we have some remote cluster configured, and we are using the separator in a date math expression, we only want to go remotely when the prefix matches a configured cluster, stay local otherwise, as the index name may still be valid locally.
This commit is contained in:
javanna 2016-11-24 15:35:52 +01:00 committed by Luca Cavanna
parent 7804aa0988
commit 276adbd990
2 changed files with 31 additions and 18 deletions

View File

@ -175,6 +175,14 @@ public class SearchTransportService extends AbstractComponent {
remoteClustersSeeds = buildRemoteClustersSeeds(settings);
}
boolean isCrossClusterSearchEnabled() {
return remoteClustersSeeds.isEmpty() == false;
}
boolean isRemoteClusterRegistered(String clusterName) {
return remoteClustersSeeds.containsKey(clusterName);
}
private DiscoveryNode connectToRemoteCluster(String clusterName) {
List<DiscoveryNode> nodes = remoteClustersSeeds.get(clusterName);
if (nodes == null) {

View File

@ -109,29 +109,34 @@ public class TransportSearchAction extends HandledTransportAction<SearchRequest,
// pure paranoia if time goes backwards we are at least positive
final long startTimeInMillis = Math.max(0, System.currentTimeMillis());
//TODO make selection smarter: aliases can still contain any character and remote indices should have the precedence all the time.
//e.g. we could skip the remote logic if no remote clusters are registered. Also don't go remotely if the prefix is not
//a registered cluster rather than throwing an error?
final List<String> localIndicesList = new ArrayList<>();
final String[] localIndices;
final Map<String, List<String>> remoteIndicesByCluster = new HashMap<>();
for (String index : searchRequest.indices()) {
int i = index.indexOf(REMOTE_CLUSTER_INDEX_SEPARATOR);
if (i >= 0) {
String remoteCluster = index.substring(0, i);
String remoteIndex = index.substring(i + 1);
List<String> indices = remoteIndicesByCluster.get(remoteCluster);
if (indices == null) {
indices = new ArrayList<>();
remoteIndicesByCluster.put(remoteCluster, indices);
if (searchTransportService.isCrossClusterSearchEnabled()) {
List<String> localIndicesList = new ArrayList<>();
for (String index : searchRequest.indices()) {
int i = index.indexOf(REMOTE_CLUSTER_INDEX_SEPARATOR);
if (i >= 0) {
String remoteCluster = index.substring(0, i);
if (searchTransportService.isRemoteClusterRegistered(remoteCluster)) {
String remoteIndex = index.substring(i + 1);
List<String> indices = remoteIndicesByCluster.get(remoteCluster);
if (indices == null) {
indices = new ArrayList<>();
remoteIndicesByCluster.put(remoteCluster, indices);
}
indices.add(remoteIndex);
} else {
localIndicesList.add(index);
}
} else {
localIndicesList.add(index);
}
indices.add(remoteIndex);
} else {
localIndicesList.add(index);
}
localIndices = localIndicesList.toArray(new String[localIndicesList.size()]);
} else {
localIndices = searchRequest.indices();
}
String[] localIndices = localIndicesList.toArray(new String[localIndicesList.size()]);
if (remoteIndicesByCluster.isEmpty()) {
executeSearch((SearchTask)task, startTimeInMillis, searchRequest, localIndices,
Strings.EMPTY_ARRAY, Collections.emptyList(), Collections.emptySet(), listener);