blob: 2e57cb118ded3290b65a194b02da2530963bc596 [file] [log] [blame]
/*
* 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 org.apache.beam.sdk.extensions.sql.impl.planner;
import java.util.Objects;
import org.apache.beam.vendor.calcite.v1_20_0.org.apache.calcite.plan.RelOptCost;
import org.apache.beam.vendor.calcite.v1_20_0.org.apache.calcite.plan.RelOptCostFactory;
import org.apache.beam.vendor.calcite.v1_20_0.org.apache.calcite.plan.RelOptUtil;
/**
* <code>VolcanoCost</code> represents the cost of a plan node.
*
* <p>This class is immutable: none of the methods modify any member variables.
*/
public class BeamCostModel implements RelOptCost {
private static final double RATE_IMPORTANCE = 3600;
static final BeamCostModel INFINITY =
new BeamCostModel(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY) {
@Override
public String toString() {
return "{inf}";
}
};
static final BeamCostModel HUGE =
new BeamCostModel(Double.MAX_VALUE, Double.MAX_VALUE) {
@Override
public String toString() {
return "{huge}";
}
};
static final BeamCostModel ZERO =
new BeamCostModel(0.0, 0.0) {
@Override
public String toString() {
return "{0}";
}
};
static final BeamCostModel TINY =
new BeamCostModel(1.0, 0.001) {
@Override
public String toString() {
return "{tiny}";
}
};
public static final BeamCostModel.Factory FACTORY = new BeamCostModel.Factory();
final double cpu;
final double cpuRate;
BeamCostModel(double cpu, double cpuRate) {
this.cpu = Math.max(cpu, 0);
this.cpuRate = Math.max(cpuRate, 0);
}
@Override
public double getCpu() {
return cpu;
}
@Override
public boolean isInfinite() {
return (this.equals(INFINITY))
|| (this.cpu == Double.POSITIVE_INFINITY)
|| (this.cpuRate == Double.POSITIVE_INFINITY);
}
@Override
public double getIo() {
return 0;
}
public double getCpuRate() {
return cpuRate;
}
@Override
public boolean isLe(RelOptCost other) {
BeamCostModel that = (BeamCostModel) other;
// This if is to make sure Infinity.isLe(Huge) wont be true.
// Without this both of the costCombinations are infinity and therefore, this will return true.
// if one of them is infinite then the only thing that matters is "that" being infinite.
if (this.isInfinite() || that.isInfinite()) {
return that.isInfinite();
}
return getCostCombination(this) <= getCostCombination(that);
}
@Override
public boolean isLt(RelOptCost other) {
BeamCostModel that = (BeamCostModel) other;
// This is to make sure Huge.isLt(Infinity) returns true
if (that.isInfinite() || this.isInfinite()) {
return !this.isInfinite();
}
return getCostCombination(this) < getCostCombination(that);
}
private static double getCostCombination(BeamCostModel cost) {
return cost.cpu + cost.cpuRate * RATE_IMPORTANCE;
}
@Override
public double getRows() {
return 0;
}
@Override
public int hashCode() {
return Objects.hash(cpu, cpuRate);
}
@SuppressWarnings("NonOverridingEquals")
@Override
public boolean equals(RelOptCost other) {
return other instanceof BeamCostModel
&& (this.cpu == ((BeamCostModel) other).cpu)
&& (this.cpuRate == ((BeamCostModel) other).cpuRate);
}
@Override
public boolean equals(Object obj) {
if (obj instanceof BeamCostModel) {
return equals((BeamCostModel) obj);
}
return false;
}
@Override
public boolean isEqWithEpsilon(RelOptCost other) {
if (!(other instanceof BeamCostModel)) {
return false;
}
BeamCostModel that = (BeamCostModel) other;
return ((Math.abs(this.cpu - that.cpu) < RelOptUtil.EPSILON)
&& (Math.abs(this.cpuRate - that.cpuRate) < RelOptUtil.EPSILON));
}
@Override
public BeamCostModel minus(RelOptCost other) {
if (this.equals(INFINITY)) {
return this;
}
BeamCostModel that = (BeamCostModel) other;
return new BeamCostModel(this.cpu - that.cpu, this.cpuRate - that.cpuRate);
}
@Override
public BeamCostModel multiplyBy(double factor) {
if (this.equals(INFINITY)) {
return this;
}
return new BeamCostModel(cpu * factor, cpuRate * factor);
}
@Override
public double divideBy(RelOptCost cost) {
// Compute the geometric average of the ratios of all of the factors
// which are non-zero and finite. (Except the window size)
BeamCostModel that = (BeamCostModel) cost;
if ((getCostCombination(this) != 0)
&& !Double.isInfinite(getCostCombination(this))
&& (getCostCombination(that) != 0)
&& !Double.isInfinite(getCostCombination(that))) {
return getCostCombination(this) / getCostCombination(that);
}
return 1.0;
}
@Override
public BeamCostModel plus(RelOptCost other) {
BeamCostModel that = (BeamCostModel) other;
if (this.equals(INFINITY) || that.equals(INFINITY)) {
return INFINITY;
}
return new BeamCostModel(this.cpu + that.cpu, this.cpuRate + that.cpuRate);
}
@Override
public String toString() {
return "{" + cpu + " cpu, " + cpuRate + " cpuRate " + "}";
}
public static BeamCostModel convertRelOptCost(RelOptCost ic) {
BeamCostModel inputCost;
if (ic instanceof BeamCostModel) {
inputCost = ((BeamCostModel) ic);
} else {
inputCost = BeamCostModel.FACTORY.makeCost(ic.getRows(), ic.getCpu(), ic.getIo());
}
return inputCost;
}
/**
* Implementation of {@link
* org.apache.beam.vendor.calcite.v1_20_0.org.apache.calcite.plan.RelOptCostFactory} that creates
* {@link BeamCostModel}s.
*/
public static class Factory implements RelOptCostFactory {
@Override
public BeamCostModel makeCost(double dRows, double dCpu, double dIo) {
return BeamCostModel.INFINITY;
}
public BeamCostModel makeCost(double dCpu, double dCpuRate) {
return new BeamCostModel(dCpu, dCpuRate);
}
@Override
public BeamCostModel makeHugeCost() {
return BeamCostModel.HUGE;
}
@Override
public BeamCostModel makeInfiniteCost() {
return BeamCostModel.INFINITY;
}
@Override
public BeamCostModel makeTinyCost() {
return BeamCostModel.TINY;
}
@Override
public BeamCostModel makeZeroCost() {
return BeamCostModel.ZERO;
}
}
}