/***********************************************************************************************************************
* Copyright (C) 2010-2013 by the Stratosphere project (http://stratosphere.eu)
*
* 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 eu.stratosphere.compiler.plan;
import eu.stratosphere.api.common.distributions.DataDistribution;
import eu.stratosphere.api.common.operators.util.FieldList;
import eu.stratosphere.api.common.typeutils.TypeComparatorFactory;
import eu.stratosphere.api.common.typeutils.TypeSerializerFactory;
import eu.stratosphere.compiler.CompilerException;
import eu.stratosphere.compiler.dag.EstimateProvider;
import eu.stratosphere.compiler.dag.TempMode;
import eu.stratosphere.compiler.dataproperties.GlobalProperties;
import eu.stratosphere.compiler.dataproperties.LocalProperties;
import eu.stratosphere.compiler.plandump.DumpableConnection;
import eu.stratosphere.compiler.util.Utils;
import eu.stratosphere.pact.runtime.shipping.ShipStrategyType;
import eu.stratosphere.pact.runtime.task.util.LocalStrategy;
/**
*
*/
public class Channel implements EstimateProvider, Cloneable, DumpableConnection<PlanNode> {
private PlanNode source;
private PlanNode target;
private ShipStrategyType shipStrategy = ShipStrategyType.NONE;
private LocalStrategy localStrategy = LocalStrategy.NONE;
private FieldList shipKeys;
private FieldList localKeys;
private boolean[] shipSortOrder;
private boolean[] localSortOrder;
private GlobalProperties globalProps;
private LocalProperties localProps;
private TypeSerializerFactory<?> serializer;
private TypeComparatorFactory<?> shipStrategyComparator;
private TypeComparatorFactory<?> localStrategyComparator;
private DataDistribution dataDistribution;
private TempMode tempMode;
private long tempMemory;
private long memoryGlobalStrategy;
private long memoryLocalStrategy;
private int replicationFactor = 1;
// --------------------------------------------------------------------------------------------
public Channel(PlanNode sourceNode) {
this(sourceNode, null);
}
public Channel(PlanNode sourceNode, TempMode tempMode) {
this.source = sourceNode;
this.tempMode = (tempMode == null ? TempMode.NONE : tempMode);
}
// --------------------------------------------------------------------------------------------
// Accessors
// --------------------------------------------------------------------------------------------
/**
* Gets the source of this Channel.
*
* @return The source.
*/
public PlanNode getSource() {
return this.source;
}
/**
* Sets the target of this Channel.
*
* @param target The target.
*/
public void setTarget(PlanNode target) {
this.target = target;
}
/**
* Gets the target of this Channel.
*
* @return The target.
*/
public PlanNode getTarget() {
return this.target;
}
public void setShipStrategy(ShipStrategyType strategy) {
setShipStrategy(strategy, null, null);
}
public void setShipStrategy(ShipStrategyType strategy, FieldList keys) {
setShipStrategy(strategy, keys, null);
}
public void setShipStrategy(ShipStrategyType strategy, FieldList keys, boolean[] sortDirection) {
this.shipStrategy = strategy;
this.shipKeys = keys;
this.shipSortOrder = sortDirection;
this.globalProps = null; // reset the global properties
}
public ShipStrategyType getShipStrategy() {
return this.shipStrategy;
}
public FieldList getShipStrategyKeys() {
return this.shipKeys;
}
public boolean[] getShipStrategySortOrder() {
return this.shipSortOrder;
}
public void setLocalStrategy(LocalStrategy strategy) {
setLocalStrategy(strategy, null, null);
}
public void setLocalStrategy(LocalStrategy strategy, FieldList keys) {
setLocalStrategy(strategy, keys, null);
}
public void setLocalStrategy(LocalStrategy strategy, FieldList keys, boolean[] sortDirection) {
this.localStrategy = strategy;
this.localKeys = keys;
this.localSortOrder = sortDirection;
this.localProps = null; // reset the local properties
}
public LocalStrategy getLocalStrategy() {
return this.localStrategy;
}
public FieldList getLocalStrategyKeys() {
return this.localKeys;
}
public boolean[] getLocalStrategySortOrder() {
return this.localSortOrder;
}
public void setDataDistribution(DataDistribution dataDistribution) {
this.dataDistribution = dataDistribution;
}
public DataDistribution getDataDistribution() {
return this.dataDistribution;
}
public TempMode getTempMode() {
return this.tempMode;
}
/**
* Sets the temp mode of the connection.
*
* @param tempMode
* The temp mode of the connection.
*/
public void setTempMode(TempMode tempMode) {
this.tempMode = tempMode;
}
/**
* Gets the memory for materializing the channel's result from this Channel.
*
* @return The temp memory.
*/
public long getTempMemory() {
return this.tempMemory;
}
/**
* Sets the memory for materializing the channel's result from this Channel.
*
* @param tempMemory The memory for materialization.
*/
public void setTempMemory(long tempMemory) {
this.tempMemory = tempMemory;
}
/**
* Sets the replication factor of the connection.
*
* @param factor The replication factor of the connection.
*/
public void setReplicationFactor(int factor) {
this.replicationFactor = factor;
}
/**
* Returns the replication factor of the connection.
*
* @return The replication factor of the connection.
*/
public int getReplicationFactor() {
return this.replicationFactor;
}
/**
* Gets the serializer from this Channel.
*
* @return The serializer.
*/
public TypeSerializerFactory<?> getSerializer() {
return serializer;
}
/**
* Sets the serializer for this Channel.
*
* @param serializer The serializer to set.
*/
public void setSerializer(TypeSerializerFactory<?> serializer) {
this.serializer = serializer;
}
/**
* Gets the ship strategy comparator from this Channel.
*
* @return The ship strategy comparator.
*/
public TypeComparatorFactory<?> getShipStrategyComparator() {
return shipStrategyComparator;
}
/**
* Sets the ship strategy comparator for this Channel.
*
* @param shipStrategyComparator The ship strategy comparator to set.
*/
public void setShipStrategyComparator(TypeComparatorFactory<?> shipStrategyComparator) {
this.shipStrategyComparator = shipStrategyComparator;
}
/**
* Gets the local strategy comparator from this Channel.
*
* @return The local strategy comparator.
*/
public TypeComparatorFactory<?> getLocalStrategyComparator() {
return localStrategyComparator;
}
/**
* Sets the local strategy comparator for this Channel.
*
* @param localStrategyComparator The local strategy comparator to set.
*/
public void setLocalStrategyComparator(TypeComparatorFactory<?> localStrategyComparator) {
this.localStrategyComparator = localStrategyComparator;
}
public long getMemoryGlobalStrategy() {
return memoryGlobalStrategy;
}
public void setMemoryGlobalStrategy(long memoryGlobalStrategy) {
this.memoryGlobalStrategy = memoryGlobalStrategy;
}
public long getMemoryLocalStrategy() {
return memoryLocalStrategy;
}
public void setMemoryLocalStrategy(long memoryLocalStrategy) {
this.memoryLocalStrategy = memoryLocalStrategy;
}
public boolean isOnDynamicPath() {
return this.source.isOnDynamicPath();
}
public int getCostWeight() {
return this.source.getCostWeight();
}
// --------------------------------------------------------------------------------------------
// Statistic Estimates
// --------------------------------------------------------------------------------------------
@Override
public long getEstimatedOutputSize() {
return this.source.template.getEstimatedOutputSize() * this.replicationFactor;
}
@Override
public long getEstimatedNumRecords() {
return this.source.template.getEstimatedNumRecords() * this.replicationFactor;
}
@Override
public float getEstimatedAvgWidthPerOutputRecord() {
return this.source.template.getEstimatedAvgWidthPerOutputRecord();
}
// --------------------------------------------------------------------------------------------
// Data Property Handling
// --------------------------------------------------------------------------------------------
public GlobalProperties getGlobalProperties() {
if (this.globalProps == null) {
this.globalProps = this.source.getGlobalProperties().clone();
switch (this.shipStrategy) {
case BROADCAST:
this.globalProps.clearUniqueFieldCombinations();
this.globalProps.setFullyReplicated();
break;
case PARTITION_HASH:
this.globalProps.setHashPartitioned(this.shipKeys);
break;
case PARTITION_RANGE:
this.globalProps.setRangePartitioned(Utils.createOrdering(this.shipKeys, this.shipSortOrder));
break;
case FORWARD:
break;
case PARTITION_RANDOM:
this.globalProps.reset();
break;
case PARTITION_LOCAL_HASH:
if (getSource().getGlobalProperties().isPartitionedOnFields(this.shipKeys)) {
// after a local hash partitioning, we can only state that the data is somehow
// partitioned. even if we had a hash partitioning before over 8 partitions,
// locally rehashing that onto 16 partitions (each one partition into two) gives you
// a different result than directly hashing to 16 partitions. the hash-partitioning
// property is only valid, if the assumed built in hash function is directly used.
// hence, we can only state that this is some form of partitioning.
this.globalProps.setAnyPartitioning(this.shipKeys);
} else {
this.globalProps.reset();
}
break;
case NONE:
throw new CompilerException("Cannot produce GlobalProperties before ship strategy is set.");
}
}
return this.globalProps;
}
public LocalProperties getLocalProperties() {
if (this.localProps == null) {
this.localProps = getLocalPropertiesAfterShippingOnly().clone();
switch (this.localStrategy) {
case NONE:
break;
case SORT:
case COMBININGSORT:
this.localProps.setOrdering(Utils.createOrdering(this.localKeys, this.localSortOrder));
break;
default:
throw new CompilerException("Unsupported local strategy for channel.");
}
}
return this.localProps;
}
public LocalProperties getLocalPropertiesAfterShippingOnly() {
if (this.shipStrategy == ShipStrategyType.FORWARD) {
return this.source.getLocalProperties();
} else {
final LocalProperties props = this.source.getLocalProperties().clone();
switch (this.shipStrategy) {
case BROADCAST:
case PARTITION_HASH:
case PARTITION_RANGE:
case PARTITION_RANDOM:
props.reset();
break;
case PARTITION_LOCAL_HASH:
case FORWARD:
break;
case NONE:
throw new CompilerException("ShipStrategy has not yet been set.");
}
return props;
}
}
public void adjustGlobalPropertiesForFullParallelismChange() {
if (this.shipStrategy == null || this.shipStrategy == ShipStrategyType.NONE) {
throw new IllegalStateException("Cannot adjust channel for degree of parallelism " +
"change before the ship strategy is set.");
}
// make sure the properties are acquired
if (this.globalProps == null) {
getGlobalProperties();
}
// some strategies globally reestablish properties
switch (this.shipStrategy) {
case FORWARD:
case PARTITION_LOCAL_HASH:
throw new CompilerException("Cannot use FORWARD or LOCAL_HASH strategy between operations " +
"with different number of parallel instances.");
case NONE: // excluded by sanity check. lust here for verification check completion
case BROADCAST:
case PARTITION_HASH:
case PARTITION_RANGE:
case PARTITION_RANDOM:
return;
}
throw new CompilerException("Unrecognized Ship Strategy Type: " + this.shipStrategy);
}
public void adjustGlobalPropertiesForLocalParallelismChange() {
if (this.shipStrategy == null || this.shipStrategy == ShipStrategyType.NONE) {
throw new IllegalStateException("Cannot adjust channel for degree of parallelism " +
"change before the ship strategy is set.");
}
// make sure the properties are acquired
if (this.globalProps == null) {
getGlobalProperties();
}
// some strategies globally reestablish properties
switch (this.shipStrategy) {
case FORWARD:
this.globalProps.reset();
return;
case NONE: // excluded by sanity check. lust here for verification check completion
case PARTITION_LOCAL_HASH:
case BROADCAST:
case PARTITION_HASH:
case PARTITION_RANGE:
case PARTITION_RANDOM:
return;
}
throw new CompilerException("Unrecognized Ship Strategy Type: " + this.shipStrategy);
}
// --------------------------------------------------------------------------------------------
/**
* Utility method used while swapping binary union nodes for n-ary union nodes.
*
* @param newUnionNode
*/
public void swapUnionNodes(PlanNode newUnionNode) {
if (!(this.source instanceof BinaryUnionPlanNode)) {
throw new IllegalStateException();
} else {
this.source = newUnionNode;
}
}
// --------------------------------------------------------------------------------------------
public int getMaxDepth() {
return this.source.getOptimizerNode().getMaxDepth() + 1;
}
// --------------------------------------------------------------------------------------------
public String toString() {
return "Channel (" + this.source + (this.target == null ? ')' : ") -> (" + this.target + ')') +
'[' + this.shipStrategy + "] [" + this.localStrategy + "] " +
(this.tempMode == null || this.tempMode == TempMode.NONE ? "{NO-TEMP}" : this.tempMode);
}
public Channel clone() {
try {
return (Channel) super.clone();
} catch (CloneNotSupportedException cnsex) {
throw new RuntimeException(cnsex);
}
}
}