/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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.twitter.distributedlog.client.routing; import com.google.common.base.Preconditions; import com.google.common.collect.Sets; import com.twitter.distributedlog.client.resolver.RegionResolver; import com.twitter.finagle.NoBrokersAvailableException; import com.twitter.finagle.stats.NullStatsReceiver; import com.twitter.finagle.stats.StatsReceiver; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.net.SocketAddress; import java.util.Set; /** * Chain multiple routing services */ public class RegionsRoutingService implements RoutingService { private static final Logger logger = LoggerFactory.getLogger(RegionsRoutingService.class); @Deprecated public static RegionsRoutingService of(RegionResolver regionResolver, RoutingService...services) { return new RegionsRoutingService(regionResolver, services); } public static Builder newBuilder() { return new Builder(); } public static class Builder implements RoutingService.Builder { private RegionResolver _resolver; private RoutingService.Builder[] _routingServiceBuilders; private StatsReceiver _statsReceiver = NullStatsReceiver.get(); private Builder() {} public Builder routingServiceBuilders(RoutingService.Builder...builders) { this._routingServiceBuilders = builders; return this; } public Builder resolver(RegionResolver regionResolver) { this._resolver = regionResolver; return this; } @Override public RoutingService.Builder statsReceiver(StatsReceiver statsReceiver) { this._statsReceiver = statsReceiver; return this; } @Override public RegionsRoutingService build() { Preconditions.checkNotNull(_routingServiceBuilders, "No routing service builder provided."); Preconditions.checkNotNull(_resolver, "No region resolver provided."); Preconditions.checkNotNull(_statsReceiver, "No stats receiver provided"); RoutingService[] services = new RoutingService[_routingServiceBuilders.length]; for (int i = 0; i < services.length; i++) { String statsScope; if (0 == i) { statsScope = "local"; } else { statsScope = "remote_" + i; } services[i] = _routingServiceBuilders[i] .statsReceiver(_statsReceiver.scope(statsScope)) .build(); } return new RegionsRoutingService(_resolver, services); } } protected final RegionResolver regionResolver; protected final RoutingService[] routingServices; private RegionsRoutingService(RegionResolver resolver, RoutingService[] routingServices) { this.regionResolver = resolver; this.routingServices = routingServices; } @Override public Set<SocketAddress> getHosts() { Set<SocketAddress> hosts = Sets.newHashSet(); for (RoutingService rs : routingServices) { hosts.addAll(rs.getHosts()); } return hosts; } @Override public void startService() { for (RoutingService service : routingServices) { service.startService(); } logger.info("Regions Routing Service Started"); } @Override public void stopService() { for (RoutingService service : routingServices) { service.stopService(); } logger.info("Regions Routing Service Stopped"); } @Override public RoutingService registerListener(RoutingListener listener) { for (RoutingService service : routingServices) { service.registerListener(listener); } return this; } @Override public RoutingService unregisterListener(RoutingListener listener) { for (RoutingService service : routingServices) { service.registerListener(listener); } return this; } @Override public SocketAddress getHost(String key, RoutingContext routingContext) throws NoBrokersAvailableException { for (RoutingService service : routingServices) { try { SocketAddress addr = service.getHost(key, routingContext); if (routingContext.hasUnavailableRegions()) { // current region is unavailable String region = regionResolver.resolveRegion(addr); if (routingContext.isUnavailableRegion(region)) { continue; } } if (!routingContext.isTriedHost(addr)) { return addr; } } catch (NoBrokersAvailableException nbae) { // if there isn't broker available in current service, try next service. logger.debug("No brokers available in region {} : ", service, nbae); } } throw new NoBrokersAvailableException("No host found for " + key + ", routing context : " + routingContext); } @Override public void removeHost(SocketAddress address, Throwable reason) { for (RoutingService service : routingServices) { service.removeHost(address, reason); } } }