You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficcontrol.apache.org by el...@apache.org on 2018/06/14 17:31:28 UTC
[trafficcontrol] 01/05: Implement geo-sorting of CLIENT_STEERING
targets
This is an automated email from the ASF dual-hosted git repository.
elsloo pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/trafficcontrol.git
commit a625fda763897b5dbf4b56b44845790ca5b8ffe2
Author: Rawlin Peters <ra...@comcast.com>
AuthorDate: Tue Feb 20 18:01:22 2018 -0700
Implement geo-sorting of CLIENT_STEERING targets
For GEO targets in a CLIENT_STEERING DS, sort the resulting list from
most optimal to least optimal, where "optimal" means shortest distance
from client -> edge -> origin.
If there is a mix of STEERING_WEIGHT, STEERING_ORDER, and GEO targets,
the ordering would be:
1. negative STEERING_ORDER
2. GEO
3. STEERING_WEIGHT
4. positive STEERING_ORDER
---
.../app/lib/API/DeliveryService/Steering.pm | 7 +-
.../app/lib/API/DeliveryService/SteeringTarget.pm | 1 +
.../traffic_router/core/cache/Cache.java | 13 ++-
.../traffic_router/core/config/ConfigHandler.java | 2 +-
.../core/ds/SteeringGeolocationComparator.java | 75 +++++++++++++
.../traffic_router/core/ds/SteeringRegistry.java | 10 +-
.../traffic_router/core/ds/SteeringResult.java | 54 +++++++++
.../traffic_router/core/ds/SteeringTarget.java | 54 +++++++++
.../traffic_router/core/router/TrafficRouter.java | 121 +++++++++++++++------
9 files changed, 297 insertions(+), 40 deletions(-)
diff --git a/traffic_ops/app/lib/API/DeliveryService/Steering.pm b/traffic_ops/app/lib/API/DeliveryService/Steering.pm
index e036b5d..6ce009a 100644
--- a/traffic_ops/app/lib/API/DeliveryService/Steering.pm
+++ b/traffic_ops/app/lib/API/DeliveryService/Steering.pm
@@ -46,7 +46,7 @@ sub find_steering {
my $rs_data = $self->db->resultset('SteeringView')->search({}, {order_by => ['steering_xml_id', 'target_xml_id']});
while ( my $row = $rs_data->next ) {
- if ($steering_xml_id && $row->steering_xml_id ne $steering_xml_id) {
+ if ($steering_xml_id && $row->steering_xml_id ne $steering_xml_id) { # TODO: can this be optimized into the SQL query?
next;
}
@@ -92,6 +92,9 @@ sub find_steering {
my $targets = $steering_entry->{"targets"};
+ # TODO: add new STEERING_GEO_WEIGHT and STEERING_GEO_ORDER types, handle them here
+ # verify if STEERING_ORDER and STEERING_WEIGHT should omit latitude, longitude, and geoOrder
+ # if GEO, get the target DS's lat/long, add it to result (add it to SteeringView?)
if ( $row->type eq "STEERING_ORDER" ) {
push(@{$targets},{
'deliveryService' => $row->target_xml_id,
@@ -191,6 +194,7 @@ sub update() {
my $req_targets = $self->req->json->{'targets'};
foreach my $req_target (@{$req_targets}) {
+ # TODO: update this validation to handle new GEO types
if (!$req_target->{'deliveryService'} && ( !$req_target->{'weight'} || !$req_target->{'order'} ) || ( $req_target->{'weight'} && $req_target->{'order'} ) ) {
return $self->render(json => {"message" => "please provide a valid json for targets"}, status => 400);
}
@@ -218,6 +222,7 @@ sub update() {
foreach my $req_target (@{$req_targets}) {
my $target_id = $valid_targets->{$req_target->{'deliveryService'}};
+ # TODO: update this to handle GEO-type targets
if ($req_target->{'weight'}) {
my $steering_target_row = $self->db->resultset('SteeringTarget')->find({ deliveryservice => $steering_id, target => $target_id});
$steering_target_row->value($req_target->{weight});
diff --git a/traffic_ops/app/lib/API/DeliveryService/SteeringTarget.pm b/traffic_ops/app/lib/API/DeliveryService/SteeringTarget.pm
index 7ea4dee..88bdb15 100644
--- a/traffic_ops/app/lib/API/DeliveryService/SteeringTarget.pm
+++ b/traffic_ops/app/lib/API/DeliveryService/SteeringTarget.pm
@@ -308,6 +308,7 @@ sub is_target_valid {
# Validate the input against the rules
my $result = validate( $params, $rules );
+ # TODO: fix indentation below, validate GEO-types
if ( $result->{success} ) {
if ( ( $target_type eq "STEERING_WEIGHT" ) and ( $params->{value} < 0 ) ) {
return ( 0, "Invalid value for target type STEERING_WEIGHT: can not be negative" );
diff --git a/traffic_router/core/src/main/java/com/comcast/cdn/traffic_control/traffic_router/core/cache/Cache.java b/traffic_router/core/src/main/java/com/comcast/cdn/traffic_control/traffic_router/core/cache/Cache.java
index a9882ff..efd676a 100644
--- a/traffic_router/core/src/main/java/com/comcast/cdn/traffic_control/traffic_router/core/cache/Cache.java
+++ b/traffic_router/core/src/main/java/com/comcast/cdn/traffic_control/traffic_router/core/cache/Cache.java
@@ -27,6 +27,7 @@ import java.util.Map;
import com.comcast.cdn.traffic_control.traffic_router.core.hash.DefaultHashable;
import com.comcast.cdn.traffic_control.traffic_router.core.hash.Hashable;
import com.comcast.cdn.traffic_control.traffic_router.core.util.JsonUtils;
+import com.comcast.cdn.traffic_control.traffic_router.geolocation.Geolocation;
import com.fasterxml.jackson.databind.JsonNode;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
@@ -43,12 +44,18 @@ public class Cache implements Comparable<Cache>, Hashable<Cache> {
private List<InetRecord> ipAddresses;
private int port;
private final Map<String, DeliveryServiceReference> deliveryServices = new HashMap<String, DeliveryServiceReference>();
+ private final Geolocation geolocation;
private final Hashable hashable = new DefaultHashable();
private int httpsPort = 443;
- public Cache(final String id, final String hashId, final int hashCount) {
+ public Cache(final String id, final String hashId, final int hashCount, final Geolocation geolocation) {
this.id = id;
hashable.generateHashes(hashId, hashCount > 0 ? hashCount : REPLICAS);
+ this.geolocation = geolocation;
+ }
+
+ public Cache(final String id, final String hashId, final int hashCount) {
+ this(id, hashId, hashCount, null);
}
@Override
@@ -74,6 +81,10 @@ public class Cache implements Comparable<Cache>, Hashable<Cache> {
return deliveryServices.values();
}
+ public Geolocation getGeolocation() {
+ return geolocation;
+ }
+
public String getFqdn() {
return fqdn;
}
diff --git a/traffic_router/core/src/main/java/com/comcast/cdn/traffic_control/traffic_router/core/config/ConfigHandler.java b/traffic_router/core/src/main/java/com/comcast/cdn/traffic_control/traffic_router/core/config/ConfigHandler.java
index 6ab8fa1..90fc738 100644
--- a/traffic_router/core/src/main/java/com/comcast/cdn/traffic_control/traffic_router/core/config/ConfigHandler.java
+++ b/traffic_router/core/src/main/java/com/comcast/cdn/traffic_control/traffic_router/core/config/ConfigHandler.java
@@ -340,7 +340,7 @@ public class ConfigHandler {
hashId = jo.get("hashId").textValue();
}
- final Cache cache = new Cache(node, hashId, JsonUtils.optInt(jo, "hashCount"));
+ final Cache cache = new Cache(node, hashId, JsonUtils.optInt(jo, "hashCount"), loc.getGeolocation());
cache.setFqdn(JsonUtils.getString(jo, "fqdn"));
cache.setPort(JsonUtils.getInt(jo, "port"));
diff --git a/traffic_router/core/src/main/java/com/comcast/cdn/traffic_control/traffic_router/core/ds/SteeringGeolocationComparator.java b/traffic_router/core/src/main/java/com/comcast/cdn/traffic_control/traffic_router/core/ds/SteeringGeolocationComparator.java
new file mode 100644
index 0000000..5436dae
--- /dev/null
+++ b/traffic_router/core/src/main/java/com/comcast/cdn/traffic_control/traffic_router/core/ds/SteeringGeolocationComparator.java
@@ -0,0 +1,75 @@
+/*
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.comcast.cdn.traffic_control.traffic_router.core.ds;
+
+import java.util.Comparator;
+
+import com.comcast.cdn.traffic_control.traffic_router.geolocation.Geolocation;
+
+// TODO: add unit tests for this class
+public class SteeringGeolocationComparator implements Comparator<SteeringResult> {
+
+ private final Geolocation clientLocation;
+
+ public SteeringGeolocationComparator(final Geolocation clientLocation) {
+ this.clientLocation = clientLocation;
+ }
+
+ @Override
+ public int compare(final SteeringResult result1, final SteeringResult result2) {
+ final Geolocation originGeo1 = result1.getSteeringTarget().getGeolocation();
+ final Geolocation originGeo2 = result2.getSteeringTarget().getGeolocation();
+
+ final Geolocation cacheGeo1 = result1.getCache().getGeolocation();
+ final Geolocation cacheGeo2 = result2.getCache().getGeolocation();
+
+ // null origin geolocations are considered greater than (i.e. farther away) than non-null origin geolocations
+ if (originGeo1 != null && originGeo2 == null) {
+ return -1;
+ }
+ if (originGeo1 == null && originGeo2 != null) {
+ return 1;
+ }
+ if (originGeo1 == null && originGeo2 == null) {
+ return 0;
+ }
+
+ // same cache and origin locations, prefer lower geoOrder
+ if (cacheGeo1.equals(cacheGeo2) && originGeo1.equals(originGeo2)) {
+ return Integer.compare(result1.getSteeringTarget().getGeoOrder(), result2.getSteeringTarget().getGeoOrder());
+ }
+
+ final double distanceFromClientToCache1 = clientLocation.getDistanceFrom(cacheGeo1);
+ final double distanceFromClientToCache2 = clientLocation.getDistanceFrom(cacheGeo2);
+
+ final double distanceFromCacheToOrigin1 = cacheGeo1.getDistanceFrom(originGeo1);
+ final double distanceFromCacheToOrigin2 = cacheGeo2.getDistanceFrom(originGeo2);
+
+ final double totalDistance1 = distanceFromClientToCache1 + distanceFromCacheToOrigin1;
+ final double totalDistance2 = distanceFromClientToCache2 + distanceFromCacheToOrigin2;
+
+ // different cache and origin locations, prefer shortest total distance
+ if (totalDistance1 != totalDistance2) {
+ // TODO: if the difference is smaller than a certain threshold, still prefer the closer edge even though distance is greater?
+ return Double.compare(totalDistance1, totalDistance2);
+ }
+
+ // total distance is equal, prefer the closest edge to the client
+ return Double.compare(distanceFromClientToCache1, distanceFromClientToCache2);
+
+ }
+
+}
diff --git a/traffic_router/core/src/main/java/com/comcast/cdn/traffic_control/traffic_router/core/ds/SteeringRegistry.java b/traffic_router/core/src/main/java/com/comcast/cdn/traffic_control/traffic_router/core/ds/SteeringRegistry.java
index 17340ac..2bf197b 100644
--- a/traffic_router/core/src/main/java/com/comcast/cdn/traffic_control/traffic_router/core/ds/SteeringRegistry.java
+++ b/traffic_router/core/src/main/java/com/comcast/cdn/traffic_control/traffic_router/core/ds/SteeringRegistry.java
@@ -56,9 +56,15 @@ public class SteeringRegistry {
registry.putAll(newSteerings);
for (final Steering steering : steerings) {
for (final SteeringTarget target : steering.getTargets()) {
- if (target.getWeight() > 0) {
+ if (target.getGeolocation() != null && target.getGeoOrder() != 0) {
+ LOGGER.info("Steering " + steering.getDeliveryService() + " target " + target.getDeliveryService() + " now has geolocation [" + target.getLatitude() + ", " + target.getLongitude() + "] and geoOrder " + target.getGeoOrder());
+ } else if (target.getGeolocation() != null && target.getWeight() > 0) {
+ LOGGER.info("Steering " + steering.getDeliveryService() + " target " + target.getDeliveryService() + " now has geolocation [" + target.getLatitude() + ", " + target.getLongitude() + "] and weight " + target.getWeight());
+ } else if (target.getGeolocation() != null) {
+ LOGGER.info("Steering " + steering.getDeliveryService() + " target " + target.getDeliveryService() + " now has geolocation [" + target.getLatitude() + ", " + target.getLongitude() + "]");
+ } else if (target.getWeight() > 0) {
LOGGER.info("Steering " + steering.getDeliveryService() + " target " + target.getDeliveryService() + " now has weight " + target.getWeight());
- } else if (target.getOrder() > 0 || target.getOrder() < 0) { // this target has a specific order set
+ } else if (target.getOrder() != 0) { // this target has a specific order set
LOGGER.info("Steering " + steering.getDeliveryService() + " target " + target.getDeliveryService() + " now has order " + target.getOrder());
} else {
LOGGER.info("Steering " + steering.getDeliveryService() + " target " + target.getDeliveryService() + " now has weight " + target.getWeight() + " and order " + target.getOrder());
diff --git a/traffic_router/core/src/main/java/com/comcast/cdn/traffic_control/traffic_router/core/ds/SteeringResult.java b/traffic_router/core/src/main/java/com/comcast/cdn/traffic_control/traffic_router/core/ds/SteeringResult.java
new file mode 100644
index 0000000..b86ccbd
--- /dev/null
+++ b/traffic_router/core/src/main/java/com/comcast/cdn/traffic_control/traffic_router/core/ds/SteeringResult.java
@@ -0,0 +1,54 @@
+/*
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.comcast.cdn.traffic_control.traffic_router.core.ds;
+
+import com.comcast.cdn.traffic_control.traffic_router.core.cache.Cache;
+
+public class SteeringResult {
+ private SteeringTarget steeringTarget;
+ private DeliveryService deliveryService;
+ private Cache cache;
+
+ public SteeringResult(final SteeringTarget steeringTarget, final DeliveryService deliveryService) {
+ this.steeringTarget = steeringTarget;
+ this.deliveryService = deliveryService;
+ }
+
+ public SteeringTarget getSteeringTarget() {
+ return steeringTarget;
+ }
+
+ public void setSteeringTarget(final SteeringTarget steeringTarget) {
+ this.steeringTarget = steeringTarget;
+ }
+
+ public DeliveryService getDeliveryService() {
+ return deliveryService;
+ }
+
+ public void setDeliveryService(final DeliveryService deliveryService) {
+ this.deliveryService = deliveryService;
+ }
+
+ public Cache getCache() {
+ return cache;
+ }
+
+ public void setCache(final Cache cache) {
+ this.cache = cache;
+ }
+
+}
diff --git a/traffic_router/core/src/main/java/com/comcast/cdn/traffic_control/traffic_router/core/ds/SteeringTarget.java b/traffic_router/core/src/main/java/com/comcast/cdn/traffic_control/traffic_router/core/ds/SteeringTarget.java
index ba400ac..d1a38df 100644
--- a/traffic_router/core/src/main/java/com/comcast/cdn/traffic_control/traffic_router/core/ds/SteeringTarget.java
+++ b/traffic_router/core/src/main/java/com/comcast/cdn/traffic_control/traffic_router/core/ds/SteeringTarget.java
@@ -16,15 +16,29 @@
package com.comcast.cdn.traffic_control.traffic_router.core.ds;
import com.comcast.cdn.traffic_control.traffic_router.core.hash.DefaultHashable;
+import com.comcast.cdn.traffic_control.traffic_router.geolocation.Geolocation;
import com.fasterxml.jackson.annotation.JsonProperty;
public class SteeringTarget extends DefaultHashable {
+
+ private static final double DEFAULT_LAT = 0.0;
+ private static final double DEFAULT_LON = 0.0;
+
@JsonProperty
private String deliveryService;
@JsonProperty
private int weight;
@JsonProperty
private int order = 0;
+ @JsonProperty
+ private int geoOrder = 0;
+ // TODO: lat/long should probably be moved to the DeliveryService itself, but this is ok for a start
+ @JsonProperty
+ private double latitude = DEFAULT_LAT;
+ @JsonProperty
+ private double longitude = DEFAULT_LON;
+
+ private Geolocation geolocation;
public DefaultHashable generateHashes() {
return generateHashes(deliveryService, weight);
@@ -54,6 +68,40 @@ public class SteeringTarget extends DefaultHashable {
return order;
}
+ public void setGeoOrder(final int geoOrder) {
+ this.geoOrder = geoOrder;
+ }
+
+ public int getGeoOrder() {
+ return geoOrder;
+ }
+
+ public void setLatitude(final double latitude) {
+ this.latitude = latitude;
+ }
+
+ public double getLatitude() {
+ return latitude;
+ }
+
+ public void setLongitude(final double longitude) {
+ this.longitude = longitude;
+ }
+
+ public double getLongitude() {
+ return longitude;
+ }
+
+ public Geolocation getGeolocation() {
+ if (geolocation != null) {
+ return geolocation;
+ }
+ if (latitude != DEFAULT_LAT && longitude != DEFAULT_LON) {
+ geolocation = new Geolocation(latitude, longitude);
+ }
+ return geolocation;
+ }
+
@Override
@SuppressWarnings("PMD")
public boolean equals(Object o) {
@@ -64,6 +112,9 @@ public class SteeringTarget extends DefaultHashable {
if (weight != target.weight) return false;
if (order != target.order) return false;
+ if (geoOrder != target.geoOrder) return false;
+ if (latitude != target.latitude) return false;
+ if (longitude != target.longitude) return false;
return deliveryService != null ? deliveryService.equals(target.deliveryService) : target.deliveryService == null;
}
@@ -73,6 +124,9 @@ public class SteeringTarget extends DefaultHashable {
int result = deliveryService != null ? deliveryService.hashCode() : 0;
result = 31 * result + weight;
result = 31 * result + order;
+ result = 31 * result + geoOrder;
+ result = 31 * result + (int) latitude;
+ result = 31 * result + (int) longitude;
return result;
}
}
diff --git a/traffic_router/core/src/main/java/com/comcast/cdn/traffic_control/traffic_router/core/router/TrafficRouter.java b/traffic_router/core/src/main/java/com/comcast/cdn/traffic_control/traffic_router/core/router/TrafficRouter.java
index caaf4e8..5f49865 100644
--- a/traffic_router/core/src/main/java/com/comcast/cdn/traffic_control/traffic_router/core/router/TrafficRouter.java
+++ b/traffic_router/core/src/main/java/com/comcast/cdn/traffic_control/traffic_router/core/router/TrafficRouter.java
@@ -22,6 +22,7 @@ import java.net.URL;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -31,6 +32,7 @@ import java.util.Set;
import java.util.stream.Collectors;
import com.comcast.cdn.traffic_control.traffic_router.configuration.ConfigurationListener;
+import com.comcast.cdn.traffic_control.traffic_router.core.ds.SteeringResult;
import com.comcast.cdn.traffic_control.traffic_router.core.ds.SteeringTarget;
import com.comcast.cdn.traffic_control.traffic_router.core.ds.Steering;
import com.comcast.cdn.traffic_control.traffic_router.core.ds.SteeringRegistry;
@@ -51,6 +53,7 @@ import com.comcast.cdn.traffic_control.traffic_router.core.cache.InetRecord;
import com.comcast.cdn.traffic_control.traffic_router.core.dns.ZoneManager;
import com.comcast.cdn.traffic_control.traffic_router.core.dns.DNSAccessRecord;
import com.comcast.cdn.traffic_control.traffic_router.core.ds.DeliveryService;
+import com.comcast.cdn.traffic_control.traffic_router.core.ds.SteeringGeolocationComparator;
import com.comcast.cdn.traffic_control.traffic_router.core.loc.FederationRegistry;
import com.comcast.cdn.traffic_control.traffic_router.geolocation.Geolocation;
import com.comcast.cdn.traffic_control.traffic_router.geolocation.GeolocationException;
@@ -510,36 +513,38 @@ public class TrafficRouter {
public HTTPRouteResult multiRoute(final HTTPRequest request, final Track track) throws MalformedURLException, GeolocationException {
final DeliveryService entryDeliveryService = cacheRegister.getDeliveryService(request, true);
- if (isTlsMismatch(request, entryDeliveryService)) {
- track.setResult(ResultType.ERROR);
- track.setResultDetails(ResultDetails.DS_TLS_MISMATCH);
+ final List<SteeringResult> steeringResults = getSteeringResults(request, track, entryDeliveryService);
+
+ if (steeringResults == null) {
return null;
}
final HTTPRouteResult routeResult = new HTTPRouteResult(true);
- final List<DeliveryService> deliveryServices = getDeliveryServices(request, track, entryDeliveryService);
+ routeResult.setDeliveryService(entryDeliveryService);
- if (deliveryServices == null) {
- return null;
- }
+ final List<SteeringResult> resultsToRemove = new ArrayList<>();
- routeResult.setDeliveryService(entryDeliveryService);
- for (final DeliveryService deliveryService : deliveryServices) {
- if (deliveryService.isRegionalGeoEnabled()) {
- LOGGER.error("Regional Geo Blocking is not supported with multi-route delivery services.. skipping " + entryDeliveryService.getId() + "/" + deliveryService.getId());
- continue;
- }
+ for (final SteeringResult steeringResult : steeringResults) {
+ final DeliveryService ds = steeringResult.getDeliveryService();
- if (deliveryService.isAvailable()) {
- final List<Cache> caches = selectCaches(request, deliveryService, track);
+ final List<Cache> caches = selectCaches(request, ds, track);
- if (caches != null && !caches.isEmpty()) {
- final Cache cache = consistentHasher.selectHashable(caches, deliveryService.getDispersion(), request.getPath());
- routeResult.addUrl(new URL(deliveryService.createURIString(request, cache)));
- }
+ if (caches != null && !caches.isEmpty()) {
+ final Cache cache = consistentHasher.selectHashable(caches, ds.getDispersion(), request.getPath());
+ steeringResult.setCache(cache);
+ } else {
+ resultsToRemove.add(steeringResult);
}
}
+ steeringResults.removeAll(resultsToRemove);
+
+ geoSortSteeringResults(steeringResults, request.getClientIP(), entryDeliveryService);
+
+ for (final SteeringResult steeringResult: steeringResults) {
+ routeResult.addUrl(new URL(steeringResult.getDeliveryService().createURIString(request, steeringResult.getCache())));
+ }
+
if (routeResult.getUrls().isEmpty()) {
routeResult.addUrl(entryDeliveryService.getFailureHttpResponse(request, track));
}
@@ -612,24 +617,41 @@ public class TrafficRouter {
return routeResult;
}
- private List<DeliveryService> getDeliveryServices(final HTTPRequest request, final Track track, final DeliveryService entryDeliveryService) {
- final List<DeliveryService> deliveryServices = consistentHashMultiDeliveryService(entryDeliveryService, request.getPath());
+ private List<SteeringResult> getSteeringResults(final HTTPRequest request, final Track track, final DeliveryService entryDeliveryService) {
+
+ if (isTlsMismatch(request, entryDeliveryService)) {
+ track.setResult(ResultType.ERROR);
+ track.setResultDetails(ResultDetails.DS_TLS_MISMATCH);
+ return null;
+ }
+
+ final List<SteeringResult> steeringResults = consistentHashMultiDeliveryService(entryDeliveryService, request.getPath());
- if (deliveryServices == null || deliveryServices.isEmpty()) {
+ if (steeringResults == null || steeringResults.isEmpty()) {
track.setResult(ResultType.DS_MISS);
track.setResultDetails(ResultDetails.DS_NOT_FOUND);
return null;
}
- for (final DeliveryService deliveryService : deliveryServices) {
- if (isTlsMismatch(request, deliveryService)) {
+ List<SteeringResult> toBeRemoved = new ArrayList<>();
+ for (final SteeringResult steeringResult : steeringResults) {
+ final DeliveryService ds = steeringResult.getDeliveryService();
+ if (isTlsMismatch(request, ds)) {
track.setResult(ResultType.ERROR);
track.setResultDetails(ResultDetails.DS_TLS_MISMATCH);
return null;
}
+ if (ds.isRegionalGeoEnabled()) {
+ LOGGER.error("Regional Geo Blocking is not supported with multi-route delivery services.. skipping " + entryDeliveryService.getId() + "/" + ds.getId());
+ toBeRemoved.add(steeringResult);
+ } else if (!ds.isAvailable()) {
+ toBeRemoved.add(steeringResult);
+ }
+
}
- return deliveryServices;
+ steeringResults.removeAll(toBeRemoved);
+ return steeringResults.isEmpty() ? null : steeringResults;
}
private DeliveryService getDeliveryService(final HTTPRequest request, final Track track) {
@@ -815,10 +837,6 @@ public class TrafficRouter {
return consistentHasher.selectHashable(caches, deliveryService.getDispersion(), requestPath);
}
- public DeliveryService consistentHashDeliveryService(final String deliveryServiceId, final String requestPath) {
- return consistentHashDeliveryService(cacheRegister.getDeliveryService(deliveryServiceId), requestPath, "");
- }
-
private boolean isSteeringDeliveryService(final DeliveryService deliveryService) {
return deliveryService != null && steeringRegistry.has(deliveryService.getId());
}
@@ -833,16 +851,45 @@ public class TrafficRouter {
return steeringRegistry.get(deliveryService.getId()).isClientSteering();
}
- public List<DeliveryService> consistentHashMultiDeliveryService(final DeliveryService deliveryService, final String requestPath) {
+ private Geolocation getClientLocationByCoverageZoneOrGeo(final String clientIP, final DeliveryService deliveryService) {
+ Geolocation clientLocation;
+ final NetworkNode networkNode = getNetworkNode(clientIP);
+ if (networkNode != null && networkNode.getGeolocation() != null) {
+ clientLocation = networkNode.getGeolocation();
+ } else {
+ try {
+ clientLocation = getLocation(clientIP, deliveryService);
+ } catch (GeolocationException e) {
+ clientLocation = null;
+ }
+ }
+ return deliveryService.supportLocation(clientLocation);
+ }
+
+ // TODO: add unit test for this method
+ private void geoSortSteeringResults(final List<SteeringResult> steeringResults, final String clientIP, final DeliveryService deliveryService) {
+ if (clientIP == null || clientIP.isEmpty()
+ || steeringResults.stream().allMatch(t -> t.getSteeringTarget().getGeolocation() == null)) {
+ return;
+ }
+
+ final Geolocation clientLocation = getClientLocationByCoverageZoneOrGeo(clientIP, deliveryService);
+ if (clientLocation != null) {
+ Collections.sort(steeringResults, new SteeringGeolocationComparator(clientLocation));
+ Collections.sort(steeringResults, Comparator.comparingInt(s -> s.getSteeringTarget().getOrder())); // re-sort by order to preserve the ordering done by ConsistentHasher
+ }
+ }
+
+ public List<SteeringResult> consistentHashMultiDeliveryService(final DeliveryService deliveryService, final String requestPath) {
if (deliveryService == null) {
return null;
}
- final List<DeliveryService> deliveryServices = new ArrayList<DeliveryService>();
+ final List<SteeringResult> steeringResults = new ArrayList<>();
if (!isSteeringDeliveryService(deliveryService)) {
- deliveryServices.add(deliveryService);
- return deliveryServices;
+ steeringResults.add(new SteeringResult(null, deliveryService));
+ return steeringResults;
}
final Steering steering = steeringRegistry.get(deliveryService.getId());
@@ -852,11 +899,15 @@ public class TrafficRouter {
final DeliveryService target = cacheRegister.getDeliveryService(steeringTarget.getDeliveryService());
if (target != null) { // target might not be in CRConfig yet
- deliveryServices.add(target);
+ steeringResults.add(new SteeringResult(steeringTarget, target));
}
}
- return deliveryServices;
+ return steeringResults;
+ }
+
+ public DeliveryService consistentHashDeliveryService(final String deliveryServiceId, final String requestPath) {
+ return consistentHashDeliveryService(cacheRegister.getDeliveryService(deliveryServiceId), requestPath, "");
}
public DeliveryService consistentHashDeliveryService(final DeliveryService deliveryService, final String requestPath, final String xtcSteeringOption) {
--
To stop receiving notification emails like this one, please contact
elsloo@apache.org.