/** * Helper method for {@link #updateProgress(Allocation, long)}. Subtract {@code units} from {@code * indexedRemainingUnits}. Updates {@link IndexedRemainingUnits} for parent {@link Allocation}s if * remaining units becomes 0. This method is <em>not</em> thread-safe for the {@code * indexedRemainingUnits} and should be called atomically relative to the {@code * indexedRemainingUnits}. * * @param indexedRemainingUnits the {@link IndexedRemainingUnits} to update progress for * @param units the units of progress */ private void UpdateIndexedRemainingUnits( IndexedRemainingUnits indexedRemainingUnits, long units) { if (units == 0) { return; } Allocation allocation = indexedRemainingUnits.allocation; long newUnits = indexedRemainingUnits.remainingUnits.AddAndGet(-units); if (newUnits < 0L) { throw new InvalidOperationException( "Progress exceeds max for '" + allocation.GetDescription() + "': " + -newUnits + " more beyond " + allocation.GetAllocationUnits()); } // Updates the parent allocations if this allocation completed. if (newUnits == 0L) { allocation .GetParent() .IfPresent( parentAllocation => UpdateIndexedRemainingUnits( Preconditions.CheckNotNull(completionMap[parentAllocation]), 1L)); } }
/** * Updates the progress for {@link Allocation} atomically relative to the {@code allocation}. * * <p>For any {@link Allocation}, this method <em>must</em> have been called on all of its parents * beforehand. * * @param allocation the {@link Allocation} to update progress for * @param units the units of progress * @return {@code true} if the map was updated */ public bool UpdateProgress(Allocation allocation, long units) { IndexedRemainingUnits newValue = new IndexedRemainingUnits(allocation); var finalValue = completionMap.GetOrAdd(allocation, newValue); UpdateIndexedRemainingUnits(finalValue, units); return(newValue == finalValue || units != 0); }