/** * This software is licensed to you under the Apache License, Version 2.0 (the * "Apache License"). * * LinkedIn's contributions are made under the Apache License. If you contribute * to the Software, the contributions will be deemed to have been made under the * Apache License, unless you expressly indicate otherwise. Please do not make any * contributions that would be inconsistent with the Apache License. * * You may obtain a copy of the Apache License at http://www.apache.org/licenses/LICENSE-2.0 * Unless required by applicable law or agreed to in writing, this software * distributed under the Apache License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the Apache * License for the specific language governing permissions and limitations for the * software governed under the Apache License. * * © 2012 LinkedIn Corp. All Rights Reserved. */ package com.senseidb.search.node.broker; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import com.linkedin.norbert.javacompat.network.PartitionedLoadBalancerFactory; import com.linkedin.norbert.network.Serializer; import com.senseidb.cluster.routing.SenseiPartitionedLoadBalancerFactory; import com.senseidb.conf.SenseiConfParams; import com.senseidb.plugin.SenseiPlugin; import com.senseidb.plugin.SenseiPluginRegistry; import com.senseidb.search.node.Broker; import com.senseidb.search.node.ResultMerger; import com.senseidb.search.node.SenseiBroker; import com.senseidb.search.req.SenseiRequest; import com.senseidb.search.req.SenseiResult; import com.senseidb.svc.api.SenseiException; import com.senseidb.svc.impl.CoreSenseiServiceImpl; public class LayeredBroker implements SenseiPlugin, Broker<SenseiRequest, SenseiResult> { private static final String CLUSTERS = "clusters"; private List<String> clusters = new ArrayList<String>(); private Map<String, CompoundBrokerConfig> clusterBrokerConfig = new HashMap<String, CompoundBrokerConfig>() ; private Map<String, SenseiBroker> brokers = new HashMap<String, SenseiBroker>() ; private LayeredClusterPruner federatedPruner; @Override public void init(Map<String, String> config, SenseiPluginRegistry pluginRegistry) { String clustersConfig = config.get(CLUSTERS); if (clustersConfig == null) { throw new IllegalArgumentException("Clusters param should be present"); } federatedPruner = pluginRegistry.getBeanByFullPrefix(SenseiConfParams.SENSEI_FEDERATED_BROKER_PRUNER, LayeredClusterPruner.class); if (federatedPruner == null) { federatedPruner = new AllClustersPruner(); } PartitionedLoadBalancerFactory<String> routerFactory = pluginRegistry.getBeanByFullPrefix(SenseiConfParams.SERVER_SEARCH_ROUTER_FACTORY, PartitionedLoadBalancerFactory.class); if (routerFactory == null) { routerFactory = new SenseiPartitionedLoadBalancerFactory(50); } Serializer<SenseiRequest, SenseiResult> serializer = pluginRegistry.getBeanByFullPrefix(SenseiConfParams.SENSEI_SEARCH_SERIALIZER, Serializer.class); if (serializer == null) { serializer = CoreSenseiServiceImpl.JAVA_SERIALIZER; } for (String cluster : clustersConfig.split(",")) { String trimmed = cluster.trim(); if (trimmed.length() > 0) { clusters.add(trimmed); clusterBrokerConfig.put(trimmed, new CompoundBrokerConfig(pluginRegistry.getConfiguration(), routerFactory, serializer, config, trimmed)); } } } @Override public void start() { for (String cluster : clusters) { CompoundBrokerConfig brokerConfig = clusterBrokerConfig.get(cluster); brokerConfig.init(); brokers.put(cluster, brokerConfig.buildSenseiBroker()); } } @Override public void stop() { for (CompoundBrokerConfig brokerConfig : clusterBrokerConfig.values()) { brokerConfig.getSenseiBroker().shutdown(); brokerConfig.getNetworkClient().shutdown(); brokerConfig.getClusterClient().shutdown(); } } public void warmUp() { for (SenseiBroker broker : brokers.values()) { try { broker.browse(new SenseiRequest()); } catch (SenseiException e) { throw new RuntimeException(e); } } } public SenseiResult browse(final SenseiRequest req) throws SenseiException { List<String> prunedClusters = federatedPruner.pruneClusters(req, clusters); int count = req.getCount(); int offset = req.getOffset(); if (count == 0) { return new SenseiResult(); } List<SenseiResult> results = new ArrayList<SenseiResult>(); if (!federatedPruner.clusterPrioritiesEqual(req)) { for (String cluster : prunedClusters) { if (count <= 0) { break; } SenseiRequest request = req.clone(); request.setCount(count); request.setOffset(offset); SenseiResult currentResult = brokers.get(cluster).browse(request); int numHits = currentResult.getNumHits(); if (offset >= numHits) { offset -= numHits; continue; } else { numHits -= offset; offset = 0; count -= numHits; results.add(currentResult); } } } else { for (String cluster : prunedClusters) { SenseiRequest request = req.clone(); SenseiResult currentResult = brokers.get(cluster).browse(request); results.add(currentResult); } } SenseiResult res = ResultMerger.merge(req, results, false); return res; } }