/*
* Copyright 2010 LinkedIn, Inc
*
* 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 voldemort.store.routed.action;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import voldemort.VoldemortException;
import voldemort.client.ZoneAffinity;
import voldemort.cluster.Node;
import voldemort.cluster.Zone;
import voldemort.cluster.failuredetector.FailureDetector;
import voldemort.routing.RoutingStrategy;
import voldemort.store.routed.GetAllPipelineData;
import voldemort.store.routed.Pipeline;
import voldemort.store.routed.Pipeline.Event;
import voldemort.utils.ByteArray;
import voldemort.versioning.Versioned;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
public class GetAllConfigureNodes
extends
AbstractConfigureNodes<Iterable<ByteArray>, Map<ByteArray, List<Versioned<byte[]>>>, GetAllPipelineData> {
private final int preferred;
private final Iterable<ByteArray> keys;
private final Zone clientZone;
private final Map<ByteArray, byte[]> transforms;
private final ZoneAffinity zoneAffinity;
public GetAllConfigureNodes(GetAllPipelineData pipelineData,
Event completeEvent,
FailureDetector failureDetector,
int preferred,
int required,
RoutingStrategy routingStrategy,
Iterable<ByteArray> keys,
Map<ByteArray, byte[]> transforms,
Zone clientZone,
ZoneAffinity zoneAffinity) {
super(pipelineData, completeEvent, failureDetector, required, routingStrategy);
this.preferred = preferred;
this.keys = keys;
this.transforms = transforms;
this.clientZone = clientZone;
this.zoneAffinity = zoneAffinity;
}
public void execute(Pipeline pipeline) {
Map<Node, List<ByteArray>> nodeToKeysMap = Maps.newHashMap();
Map<ByteArray, List<Node>> keyToExtraNodesMap = Maps.newHashMap();
for(ByteArray key: keys) {
List<Node> nodes = null;
List<Node> originalNodes = null;
try {
originalNodes = getNodes(key);
} catch(VoldemortException e) {
pipelineData.setFatalError(e);
pipeline.addEvent(Event.ERROR);
return;
}
List<Node> preferredNodes = Lists.newArrayListWithCapacity(preferred);
List<Node> extraNodes = Lists.newArrayListWithCapacity(3);
if(zoneAffinity != null && zoneAffinity.isGetAllOpZoneAffinityEnabled()) {
nodes = new ArrayList<Node>();
for(Node node: originalNodes) {
if(node.getZoneId() == clientZone.getId()) {
nodes.add(node);
}
}
} else {
nodes = originalNodes;
}
if(pipelineData.getZonesRequired() != null) {
validateZonesRequired(this.clientZone, pipelineData.getZonesRequired());
// Create zone id to node mapping
Map<Integer, List<Node>> zoneIdToNode = convertToZoneNodeMap(nodes);
nodes = new ArrayList<Node>();
List<Integer> proximityList = this.clientZone.getProximityList();
// Add a node from every zone
for(int index = 0; index < pipelineData.getZonesRequired(); index++) {
List<Node> zoneNodes = zoneIdToNode.get(proximityList.get(index));
if(zoneNodes != null) {
nodes.add(zoneNodes.remove(0));
}
}
// Add the rest
List<Node> zoneIDNodeList = zoneIdToNode.get(this.clientZone.getId());
if(zoneIDNodeList != null) {
nodes.addAll(zoneIDNodeList);
}
for(int index = 0; index < proximityList.size(); index++) {
List<Node> zoneNodes = zoneIdToNode.get(proximityList.get(index));
if(zoneNodes != null)
nodes.addAll(zoneNodes);
}
}
for(Node node: nodes) {
if(preferredNodes.size() < preferred)
preferredNodes.add(node);
else
extraNodes.add(node);
}
for(Node node: preferredNodes) {
List<ByteArray> nodeKeys = nodeToKeysMap.get(node);
if(nodeKeys == null) {
nodeKeys = Lists.newArrayList();
nodeToKeysMap.put(node, nodeKeys);
}
nodeKeys.add(key);
}
if(!extraNodes.isEmpty()) {
List<Node> list = keyToExtraNodesMap.get(key);
if(list == null)
keyToExtraNodesMap.put(key, extraNodes);
else
list.addAll(extraNodes);
}
}
pipelineData.setKeyToExtraNodesMap(keyToExtraNodesMap);
pipelineData.setNodeToKeysMap(nodeToKeysMap);
pipelineData.setTransforms(transforms);
pipeline.addEvent(completeEvent);
}
}