/* * 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 gobblin.source.workunit; import java.util.List; import java.util.PriorityQueue; import java.util.Queue; import com.google.common.collect.ImmutableList; import com.google.common.primitives.Longs; /** * Helper class that distributes {@link WorkUnit}s amongst a series of {@link MultiWorkUnit}s. When a WorkUnit is added * to this queue, it is added along with a weight which indicates how much effort it will take to process this WorkUnit. * For example, a larger weight means that this WorkUnit will take longer to process. For files this can simply be the * file size. * * <p> * * The constructor {@link MultiWorkUnitWeightedQueue(int maxMultiWorkUnits)} sets a maximum size for the queue. This * means that when more than maxMultiWorkUnits are added to the queue, WorkUnits will start to be paired together into * MultiWorkUnits. * * @see MultiWorkUnit */ public class MultiWorkUnitWeightedQueue { private final Queue<WeightedMultiWorkUnit> weightedWorkUnitQueue; private int maxMultiWorkUnits = Integer.MAX_VALUE; private int numMultiWorkUnits = 0; /** * The default constructor sets the limit on the queue to size to be {@link Integer#MAX_VALUE}. This means that until * Integer.MAX_VALUE + 1 WorkUnits are added to the queue, no WorkUnits will be paired together. */ public MultiWorkUnitWeightedQueue() { this.weightedWorkUnitQueue = new PriorityQueue<>(); } public MultiWorkUnitWeightedQueue(int maxMultiWorkUnits) { this.weightedWorkUnitQueue = new PriorityQueue<>(maxMultiWorkUnits); this.maxMultiWorkUnits = maxMultiWorkUnits; } /** * Adds a {@link WorkUnit} to this queue, along with an associated weight for that WorkUnit. */ public void addWorkUnit(WorkUnit workUnit, long weight) { WeightedMultiWorkUnit weightMultiWorkUnit; if (this.numMultiWorkUnits < this.maxMultiWorkUnits) { weightMultiWorkUnit = new WeightedMultiWorkUnit(); this.numMultiWorkUnits++; } else { weightMultiWorkUnit = this.weightedWorkUnitQueue.poll(); } weightMultiWorkUnit.addWorkUnit(weight, workUnit); this.weightedWorkUnitQueue.offer(weightMultiWorkUnit); } /** * Returns the a list of WorkUnits that have been added to this queue via the {@link #addWorkUnit(WorkUnit, long)} * method. */ public List<WorkUnit> getQueueAsList() { return ImmutableList.<WorkUnit> builder().addAll(this.weightedWorkUnitQueue).build(); } /** * This class defines the weighted multiWorkUnit. It extends {@link MultiWorkUnit}. Each weightedMultiworkUnit has a * weight, which is the sum of the file sizes assigned to it. It also implements Comparable, based on the weight value. * * @author ydai */ private static class WeightedMultiWorkUnit extends MultiWorkUnit implements Comparable<WeightedMultiWorkUnit> { private long weight = 0l; /** * Add a new single workUnit to the current workUnits list. Update the weight by adding the weight of the new workUnit. * * @param weight the weight of the newWorkUnit. * @param newWorkUnit the new work unit. */ private void addWorkUnit(long weight, WorkUnit newWorkUnit) { this.addWorkUnit(newWorkUnit); this.weight += weight; } /** * Compare with the other weightedMultiWorkUnit based on weight. */ @Override public int compareTo(WeightedMultiWorkUnit weightedMultiWorkUnit) { return Longs.compare(this.weight, weightedMultiWorkUnit.getWeight()); } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + (int) (this.weight ^ (this.weight >>> 32)); return result; } @Override public boolean equals(Object obj) { if (!(obj instanceof WeightedMultiWorkUnit)) { return false; } WeightedMultiWorkUnit weightedMultiWorkUnit = (WeightedMultiWorkUnit) obj; return this.weight == weightedMultiWorkUnit.getWeight(); } public long getWeight() { return this.weight; } } }