/// <exception cref="Org.Apache.Hadoop.Yarn.Server.Resourcemanager.Reservation.Exceptions.ContractValidationException /// "/> private void ValidateInput(Plan plan, ReservationRequest rr, Resource totalCapacity ) { if (rr.GetConcurrency() < 1) { throw new ContractValidationException("Gang Size should be >= 1"); } if (rr.GetNumContainers() <= 0) { throw new ContractValidationException("Num containers should be >= 0"); } // check that gangSize and numContainers are compatible if (rr.GetNumContainers() % rr.GetConcurrency() != 0) { throw new ContractValidationException("Parallelism must be an exact multiple of gang size" ); } // check that the largest container request does not exceed // the cluster-wide limit for container sizes if (Resources.GreaterThan(plan.GetResourceCalculator(), totalCapacity, rr.GetCapability (), plan.GetMaximumAllocation())) { throw new ContractValidationException("Individual" + " capability requests should not exceed cluster's maxAlloc" ); } }
/// <summary>Removes a resource for the specified interval</summary> /// <param name="reservationInterval"> /// the interval for which the resource is to be /// removed /// </param> /// <param name="capacity">the resource to be removed</param> /// <returns>true if removal is successful, false otherwise</returns> public virtual bool RemoveInterval(ReservationInterval reservationInterval, ReservationRequest capacity) { Org.Apache.Hadoop.Yarn.Api.Records.Resource totCap = Resources.Multiply(capacity. GetCapability(), (float)capacity.GetNumContainers()); if (totCap.Equals(ZeroResource)) { return(true); } writeLock.Lock(); try { long startKey = reservationInterval.GetStartTime(); long endKey = reservationInterval.GetEndTime(); // update the start key NavigableMap <long, Org.Apache.Hadoop.Yarn.Api.Records.Resource> ticks = cumulativeCapacity .HeadMap(endKey, false); // Decrease all the capacities of overlapping intervals SortedDictionary <long, Org.Apache.Hadoop.Yarn.Api.Records.Resource> overlapSet = ticks.TailMap(startKey); if (overlapSet != null && !overlapSet.IsEmpty()) { Org.Apache.Hadoop.Yarn.Api.Records.Resource updatedCapacity = Org.Apache.Hadoop.Yarn.Api.Records.Resource .NewInstance(0, 0); long currentKey = -1; for (IEnumerator <KeyValuePair <long, Org.Apache.Hadoop.Yarn.Api.Records.Resource> > overlapEntries = overlapSet.GetEnumerator(); overlapEntries.HasNext();) { KeyValuePair <long, Org.Apache.Hadoop.Yarn.Api.Records.Resource> entry = overlapEntries .Next(); currentKey = entry.Key; updatedCapacity = Resources.Subtract(entry.Value, totCap); // update each entry between start and end key cumulativeCapacity[currentKey] = updatedCapacity; } // Remove the first overlap entry if it is same as previous after // updation long firstKey = overlapSet.FirstKey(); if (IsSameAsPrevious(firstKey, overlapSet[firstKey])) { Sharpen.Collections.Remove(cumulativeCapacity, firstKey); } // Remove the next entry if it is same as end entry after updation if ((currentKey != -1) && (IsSameAsNext(currentKey, updatedCapacity))) { Sharpen.Collections.Remove(cumulativeCapacity, cumulativeCapacity.HigherKey(currentKey )); } } return(true); } finally { writeLock.Unlock(); } }
/// <summary>Add multiple resources for the specified interval</summary> /// <param name="reservationInterval"> /// the interval for which the resource is to be /// added /// </param> /// <param name="ReservationRequests">the resources to be added</param> /// <param name="clusterResource">the total resources in the cluster</param> /// <returns>true if addition is successful, false otherwise</returns> public virtual bool AddCompositeInterval(ReservationInterval reservationInterval, IList <ReservationRequest> ReservationRequests, Org.Apache.Hadoop.Yarn.Api.Records.Resource clusterResource) { ReservationRequest aggregateReservationRequest = Org.Apache.Hadoop.Yarn.Util.Records .NewRecord <ReservationRequest>(); Org.Apache.Hadoop.Yarn.Api.Records.Resource capacity = Org.Apache.Hadoop.Yarn.Api.Records.Resource .NewInstance(0, 0); foreach (ReservationRequest ReservationRequest in ReservationRequests) { Resources.AddTo(capacity, Resources.Multiply(ReservationRequest.GetCapability(), ReservationRequest.GetNumContainers())); } aggregateReservationRequest.SetNumContainers((int)Math.Ceil(Resources.Divide(resourceCalculator , clusterResource, capacity, minAlloc))); aggregateReservationRequest.SetCapability(minAlloc); return(AddInterval(reservationInterval, aggregateReservationRequest)); }
/// <summary>Add a resource for the specified interval</summary> /// <param name="reservationInterval"> /// the interval for which the resource is to be /// added /// </param> /// <param name="capacity">the resource to be added</param> /// <returns>true if addition is successful, false otherwise</returns> public virtual bool AddInterval(ReservationInterval reservationInterval, ReservationRequest capacity) { Org.Apache.Hadoop.Yarn.Api.Records.Resource totCap = Resources.Multiply(capacity. GetCapability(), (float)capacity.GetNumContainers()); if (totCap.Equals(ZeroResource)) { return(true); } writeLock.Lock(); try { long startKey = reservationInterval.GetStartTime(); long endKey = reservationInterval.GetEndTime(); NavigableMap <long, Org.Apache.Hadoop.Yarn.Api.Records.Resource> ticks = cumulativeCapacity .HeadMap(endKey, false); if (ticks != null && !ticks.IsEmpty()) { Org.Apache.Hadoop.Yarn.Api.Records.Resource updatedCapacity = Org.Apache.Hadoop.Yarn.Api.Records.Resource .NewInstance(0, 0); KeyValuePair <long, Org.Apache.Hadoop.Yarn.Api.Records.Resource> lowEntry = ticks. FloorEntry(startKey); if (lowEntry == null) { // This is the earliest starting interval cumulativeCapacity[startKey] = totCap; } else { updatedCapacity = Resources.Add(lowEntry.Value, totCap); // Add a new tick only if the updated value is different // from the previous tick if ((startKey == lowEntry.Key) && (IsSameAsPrevious(lowEntry.Key, updatedCapacity ))) { Sharpen.Collections.Remove(cumulativeCapacity, lowEntry.Key); } else { cumulativeCapacity[startKey] = updatedCapacity; } } // Increase all the capacities of overlapping intervals ICollection <KeyValuePair <long, Org.Apache.Hadoop.Yarn.Api.Records.Resource> > overlapSet = ticks.TailMap(startKey, false); foreach (KeyValuePair <long, Org.Apache.Hadoop.Yarn.Api.Records.Resource> entry in overlapSet) { updatedCapacity = Resources.Add(entry.Value, totCap); entry.SetValue(updatedCapacity); } } else { // This is the first interval to be added cumulativeCapacity[startKey] = totCap; } Org.Apache.Hadoop.Yarn.Api.Records.Resource nextTick = cumulativeCapacity[endKey]; if (nextTick != null) { // If there is overlap, remove the duplicate entry if (IsSameAsPrevious(endKey, nextTick)) { Sharpen.Collections.Remove(cumulativeCapacity, endKey); } } else { // Decrease capacity as this is end of the interval cumulativeCapacity[endKey] = Resources.Subtract(cumulativeCapacity.FloorEntry(endKey ).Value, totCap); } return(true); } finally { writeLock.Unlock(); } }
/// <summary> /// This method actually perform the placement of an atomic stage of the /// reservation. /// </summary> /// <remarks> /// This method actually perform the placement of an atomic stage of the /// reservation. The key idea is to traverse the plan backward for a /// "lease-duration" worth of time, and compute what is the maximum multiple of /// our concurrency (gang) parameter we can fit. We do this and move towards /// previous instant in time until the time-window is exhausted or we placed /// all the user request. /// </remarks> private IDictionary <ReservationInterval, ReservationRequest> PlaceSingleStage(Plan plan, RLESparseResourceAllocation tempAssigned, ReservationRequest rr, long earliestStart , long curDeadline, ReservationAllocation oldResAllocation, Org.Apache.Hadoop.Yarn.Api.Records.Resource totalCapacity) { IDictionary <ReservationInterval, ReservationRequest> allocationRequests = new Dictionary <ReservationInterval, ReservationRequest>(); // compute the gang as a resource and get the duration Org.Apache.Hadoop.Yarn.Api.Records.Resource gang = Resources.Multiply(rr.GetCapability (), rr.GetConcurrency()); long dur = rr.GetDuration(); long step = plan.GetStep(); // ceil the duration to the next multiple of the plan step if (dur % step != 0) { dur += (step - (dur % step)); } // we know for sure that this division has no remainder (part of contract // with user, validate before int gangsToPlace = rr.GetNumContainers() / rr.GetConcurrency(); int maxGang = 0; // loop trying to place until we are done, or we are considering // an invalid range of times while (gangsToPlace > 0 && curDeadline - dur >= earliestStart) { // as we run along we remember how many gangs we can fit, and what // was the most constraining moment in time (we will restart just // after that to place the next batch) maxGang = gangsToPlace; long minPoint = curDeadline; int curMaxGang = maxGang; // start placing at deadline (excluded due to [,) interval semantics and // move backward for (long t = curDeadline - plan.GetStep(); t >= curDeadline - dur && maxGang > 0 ; t = t - plan.GetStep()) { // As we run along we will logically remove the previous allocation for // this reservation // if one existed Org.Apache.Hadoop.Yarn.Api.Records.Resource oldResCap = Org.Apache.Hadoop.Yarn.Api.Records.Resource .NewInstance(0, 0); if (oldResAllocation != null) { oldResCap = oldResAllocation.GetResourcesAtTime(t); } // compute net available resources Org.Apache.Hadoop.Yarn.Api.Records.Resource netAvailableRes = Resources.Clone(totalCapacity ); Resources.AddTo(netAvailableRes, oldResCap); Resources.SubtractFrom(netAvailableRes, plan.GetTotalCommittedResources(t)); Resources.SubtractFrom(netAvailableRes, tempAssigned.GetCapacityAtTime(t)); // compute maximum number of gangs we could fit curMaxGang = (int)Math.Floor(Resources.Divide(plan.GetResourceCalculator(), totalCapacity , netAvailableRes, gang)); // pick the minimum between available resources in this instant, and how // many gangs we have to place curMaxGang = Math.Min(gangsToPlace, curMaxGang); // compare with previous max, and set it. also remember *where* we found // the minimum (useful for next attempts) if (curMaxGang <= maxGang) { maxGang = curMaxGang; minPoint = t; } } // if we were able to place any gang, record this, and decrement // gangsToPlace if (maxGang > 0) { gangsToPlace -= maxGang; ReservationInterval reservationInt = new ReservationInterval(curDeadline - dur, curDeadline ); ReservationRequest reservationRes = ReservationRequest.NewInstance(rr.GetCapability (), rr.GetConcurrency() * maxGang, rr.GetConcurrency(), rr.GetDuration()); // remember occupied space (plan is read-only till we find a plausible // allocation for the entire request). This is needed since we might be // placing other ReservationRequest within the same // ReservationDefinition, // and we must avoid double-counting the available resources tempAssigned.AddInterval(reservationInt, reservationRes); allocationRequests[reservationInt] = reservationRes; } // reset our new starting point (curDeadline) to the most constraining // point so far, we will look "left" of that to find more places where // to schedule gangs (for sure nothing on the "right" of this point can // fit a full gang. curDeadline = minPoint; } // if no gangs are left to place we succeed and return the allocation if (gangsToPlace == 0) { return(allocationRequests); } else { // If we are here is becasue we did not manage to satisfy this request. // So we need to remove unwanted side-effect from tempAssigned (needed // for ANY). foreach (KeyValuePair <ReservationInterval, ReservationRequest> tempAllocation in allocationRequests) { tempAssigned.RemoveInterval(tempAllocation.Key, tempAllocation.Value); } // and return null to signal failure in this allocation return(null); } }