diff options
Diffstat (limited to 'adaptors/resource-assignment/provider/src/main/java/org/onap/ccsdk/sli/adaptors/rm/comp/AllocationFunction.java')
-rw-r--r-- | adaptors/resource-assignment/provider/src/main/java/org/onap/ccsdk/sli/adaptors/rm/comp/AllocationFunction.java | 433 |
1 files changed, 433 insertions, 0 deletions
diff --git a/adaptors/resource-assignment/provider/src/main/java/org/onap/ccsdk/sli/adaptors/rm/comp/AllocationFunction.java b/adaptors/resource-assignment/provider/src/main/java/org/onap/ccsdk/sli/adaptors/rm/comp/AllocationFunction.java new file mode 100644 index 000000000..485010656 --- /dev/null +++ b/adaptors/resource-assignment/provider/src/main/java/org/onap/ccsdk/sli/adaptors/rm/comp/AllocationFunction.java @@ -0,0 +1,433 @@ +/*- + * ============LICENSE_START======================================================= + * openECOMP : SDN-C + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights + * reserved. + * ================================================================================ + * Modifications Copyright (C) 2018 IBM. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.adaptors.rm.comp; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; +import java.util.SortedSet; +import java.util.TreeSet; +import org.onap.ccsdk.sli.adaptors.lock.comp.LockHelper; +import org.onap.ccsdk.sli.adaptors.lock.comp.ResourceLockedException; +import org.onap.ccsdk.sli.adaptors.lock.comp.SynchronizedFunction; +import org.onap.ccsdk.sli.adaptors.rm.dao.ResourceDao; +import org.onap.ccsdk.sli.adaptors.rm.data.AllocationOutcome; +import org.onap.ccsdk.sli.adaptors.rm.data.AllocationRequest; +import org.onap.ccsdk.sli.adaptors.rm.data.AllocationStatus; +import org.onap.ccsdk.sli.adaptors.rm.data.LabelAllocationOutcome; +import org.onap.ccsdk.sli.adaptors.rm.data.LabelAllocationRequest; +import org.onap.ccsdk.sli.adaptors.rm.data.LabelResource; +import org.onap.ccsdk.sli.adaptors.rm.data.LimitAllocationOutcome; +import org.onap.ccsdk.sli.adaptors.rm.data.LimitAllocationRequest; +import org.onap.ccsdk.sli.adaptors.rm.data.LimitResource; +import org.onap.ccsdk.sli.adaptors.rm.data.MultiAssetAllocationOutcome; +import org.onap.ccsdk.sli.adaptors.rm.data.MultiAssetAllocationRequest; +import org.onap.ccsdk.sli.adaptors.rm.data.MultiResourceAllocationOutcome; +import org.onap.ccsdk.sli.adaptors.rm.data.MultiResourceAllocationRequest; +import org.onap.ccsdk.sli.adaptors.rm.data.Range; +import org.onap.ccsdk.sli.adaptors.rm.data.RangeAllocationOutcome; +import org.onap.ccsdk.sli.adaptors.rm.data.RangeAllocationRequest; +import org.onap.ccsdk.sli.adaptors.rm.data.RangeResource; +import org.onap.ccsdk.sli.adaptors.rm.data.Resource; +import org.onap.ccsdk.sli.adaptors.rm.data.ResourceKey; +import org.onap.ccsdk.sli.adaptors.rm.data.ResourceType; +import org.onap.ccsdk.sli.adaptors.rm.util.LabelUtil; +import org.onap.ccsdk.sli.adaptors.rm.util.LimitUtil; +import org.onap.ccsdk.sli.adaptors.rm.util.RangeUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +class AllocationFunction extends SynchronizedFunction { + + @SuppressWarnings("unused") + private static final Logger log = LoggerFactory.getLogger(AllocationFunction.class); + + private ResourceDao resourceDao; + + private AllocationRequest request; + private AllocationOutcome outcome; + + private List<Resource> updateList = new ArrayList<>(); + + public AllocationFunction(LockHelper lockHelper, ResourceDao resourceDao, AllocationRequest request, + int lockTimeout) { + super(lockHelper, getLockNames(request), lockTimeout); + this.resourceDao = resourceDao; + this.request = request; + } + + private static Collection<String> getLockNames(AllocationRequest request) { + Set<String> lockResourceNames = new HashSet<>(); + addLockNames(lockResourceNames, request); + return lockResourceNames; + } + + private static void addLockNames(Set<String> lockResourceNames, AllocationRequest request) { + if (request instanceof MultiAssetAllocationRequest) { + MultiAssetAllocationRequest req = (MultiAssetAllocationRequest) request; + if (req.assetIdList != null) { + lockResourceNames.addAll(req.assetIdList); + } + } else if (request instanceof MultiResourceAllocationRequest) { + MultiResourceAllocationRequest req = (MultiResourceAllocationRequest) request; + if (req.allocationRequestList != null) { + for (AllocationRequest request1 : req.allocationRequestList) { + addLockNames(lockResourceNames, request1); + } + } + } else if (request.assetId != null) { + lockResourceNames.add(request.assetId); + } + } + + @Override + public void _exec() throws ResourceLockedException { + outcome = allocate(request); + + if (outcome!=null && outcome.status == AllocationStatus.Success) { + for (Resource r : updateList) { + resourceDao.saveResource(r); + } + } + } + + private AllocationOutcome allocate(AllocationRequest allocationRequest) throws ResourceLockedException { + if (allocationRequest instanceof MultiAssetAllocationRequest) { + return allocateMultiAsset((MultiAssetAllocationRequest) allocationRequest); + } + if (allocationRequest instanceof MultiResourceAllocationRequest) { + return allocateMultiResource((MultiResourceAllocationRequest) allocationRequest); + } + if (allocationRequest instanceof LimitAllocationRequest) { + return allocateLimit((LimitAllocationRequest) allocationRequest); + } + if (allocationRequest instanceof LabelAllocationRequest) { + return allocateLabel((LabelAllocationRequest) allocationRequest); + } + if (allocationRequest instanceof RangeAllocationRequest) { + return allocateRange((RangeAllocationRequest) allocationRequest); + } + return null; + } + + private MultiAssetAllocationOutcome allocateMultiAsset(MultiAssetAllocationRequest req) { + + return null; + } + + private MultiResourceAllocationOutcome allocateMultiResource(MultiResourceAllocationRequest req) { + MultiResourceAllocationOutcome out = new MultiResourceAllocationOutcome(); + out.request = req; + out.allocationOutcomeList = new ArrayList<>(); + out.status = AllocationStatus.Success; + + if (req.allocationRequestList != null) { + for (AllocationRequest req1 : req.allocationRequestList) { + AllocationOutcome out1 = allocate(req1); + out.allocationOutcomeList.add(out1); + if (out1.status != AllocationStatus.Success) { + out.status = AllocationStatus.Failure; + } + } + } + + return out; + } + + private LimitAllocationOutcome allocateLimit(LimitAllocationRequest req) { + LimitAllocationOutcome out = new LimitAllocationOutcome(); + out.request = req; + + Resource r = resourceDao.getResource(req.assetId, req.resourceName); + if (r == null) { + r = new LimitResource(); + r.resourceKey = new ResourceKey(); + r.resourceKey.assetId = req.assetId; + r.resourceKey.resourceName = req.resourceName; + r.resourceType = ResourceType.Limit; + } else { + if (r.resourceType != ResourceType.Limit) { + out.status = AllocationStatus.ResourceNotFound; + return out; + } + LimitUtil.recalculate((LimitResource) r); + } + + LimitResource l = (LimitResource) r; + if (LimitUtil.checkLimit(l, req)) { + out.status = AllocationStatus.Success; + if (req.allocateCount > 0) { + out.allocatedCount = LimitUtil.allocateLimit(l, req); + updateList.add(l); + } + } else { + out.status = AllocationStatus.Failure; + } + + out.used = l.used; + out.limit = req.checkLimit; + + return out; + } + + private LabelAllocationOutcome allocateLabel(LabelAllocationRequest req) { + LabelAllocationOutcome out = new LabelAllocationOutcome(); + + out.request = req; + + Resource r = resourceDao.getResource(req.assetId, req.resourceName); + if (r == null) { + r = new LabelResource(); + r.resourceKey = new ResourceKey(); + r.resourceKey.assetId = req.assetId; + r.resourceKey.resourceName = req.resourceName; + r.resourceType = ResourceType.Label; + } else { + if (r.resourceType != ResourceType.Label) { + out.status = AllocationStatus.ResourceNotFound; + return out; + } + LabelUtil.recalculate((LabelResource) r); + } + + LabelResource l = (LabelResource) r; + if (LabelUtil.checkLabel(l, req)) { + out.status = AllocationStatus.Success; + out.currentLabel = l.label; + if (req.allocate) { + out.allocatedLabel = LabelUtil.allocateLabel(l, req); + updateList.add(l); + } + } else { + out.status = AllocationStatus.Failure; + } + + return out; + } + + private RangeAllocationOutcome allocateRange(RangeAllocationRequest req) { + RangeAllocationOutcome out = new RangeAllocationOutcome(); + + out.request = req; + + Resource r = resourceDao.getResource(req.assetId, req.resourceName); + if (r == null) { + r = new RangeResource(); + r.resourceKey = new ResourceKey(); + r.resourceKey.assetId = req.assetId; + r.resourceKey.resourceName = req.resourceName; + r.resourceType = ResourceType.Range; + } else { + if (r.resourceType != ResourceType.Range) { + out.status = AllocationStatus.ResourceNotFound; + return out; + } + RangeUtil.recalculate((RangeResource) r); + } + + RangeResource rr = (RangeResource) r; + SortedSet<Integer> foundNumbers = null; + if (!req.check) { + out.status = AllocationStatus.Success; + foundNumbers = req.requestedNumbers; + } else { + if (req.requestedNumbers != null && !req.requestedNumbers.isEmpty()) { + foundNumbers = req.requestedNumbers; + out.status = AllocationStatus.Success; + for (int n : foundNumbers) { + if (!RangeUtil.checkRange(rr, req, n)) { + out.status = AllocationStatus.Failure; + break; + } + } + } else { + foundNumbers = new TreeSet<>(); + int foundCount = 0; + + // First try to reuse the numbers already taken by the same resource union + SortedSet<Integer> uu = RangeUtil.getUsed(rr, req.resourceUnionId); + if (uu != null && !uu.isEmpty() && req.replace && !req.forceNewNumbers) { + if (uu.size() >= req.requestedCount) { + // Just take the first req.requestedCount numbers from uu + Iterator<Integer> i = uu.iterator(); + while (foundCount < req.requestedCount) { + foundNumbers.add(i.next()); + foundCount++; + } + } else { + // Additional numbers are requested. Try to find them starting from + // the minimum we have in uu (the first element) towards the min + // parameter, and then starting from the maximum in uu (the last + // element) towards the max parameter. + // NOTE: In case of request for sequential numbers, the parameters + // alignBlockSize and alignModulus are ignored. It would be harder + // to take them into account, and currently it is not needed. + + // Request may contain multiple ranges. We will find the range from the request + // that contains the currently used numbers (the first one). We will only look + // for additional numbers in that range. + + Range range = null; + if (req.rangeList != null) { + for (Range range1 : req.rangeList) { + if (uu.first() >= range1.min && uu.first() <= range1.max) { + range = range1; + break; + } + } + } + + if (range != null) { + int uumin = uu.first() - 1; + int uumax = uu.last() + 1; + foundNumbers.addAll(uu); + foundCount = uu.size(); + for (int n = uumin; foundCount < req.requestedCount && n >= range.min; n--) { + if (RangeUtil.checkRange(rr, req, n)) { + foundNumbers.add(n); + foundCount++; + } else if (req.sequential) { + break; + } + } + for (int n = uumax; foundCount < req.requestedCount && n <= range.max; n++) { + if (RangeUtil.checkRange(rr, req, n)) { + foundNumbers.add(n); + foundCount++; + } else if (req.sequential) { + break; + } + } + } + + // If we could not find enough numbers trying to reuse currently + // allocated, reset foundNumbers and foundCount, continue with + // the normal allocation of new numbers. + if (foundCount < req.requestedCount) { + foundNumbers = new TreeSet<>(); + foundCount = 0; + } + } + } + + if (req.rangeList != null && !req.rangeList.isEmpty()) { + if (req.nextInSequence) { + // This means we allocate numbers in ascending sequence, not trying from the beginning + // of the range (leaving possible holes in the sequence of allocated numbers) + // To do that, we go through the ranges from the last towards the first (assuming + // ranges are ordered from smallest to the largest numbers), and within each range, from + // the max towards the min and find the first allocated number. Then we take the next numbers + // in the range (that we already checked are available). + + int rangeIndex; + Range range = null; + int n = 0; + boolean foundAllocated = false; + for (rangeIndex = req.rangeList.size() - 1; !foundAllocated && rangeIndex >= 0; rangeIndex--) { + range = req.rangeList.get(rangeIndex); + for (n = range.max; n >= range.min; n--) { + if (!RangeUtil.checkRange(rr, req, n)) { + foundAllocated = true; + break; + } + } + if (foundAllocated) { + break; + } + } + n++; + for (; foundCount < req.requestedCount && n <= range.max; n++) { + foundNumbers.add(n); + foundCount++; + } + if (foundCount < req.requestedCount) { + rangeIndex++; + for (; rangeIndex < req.rangeList.size(); rangeIndex++) { + range = req.rangeList.get(rangeIndex); + for (n = range.min; foundCount < req.requestedCount && n <= range.max; n++) { + foundNumbers.add(n); + foundCount++; + } + } + } + // If we could not find enough numbers by going up in sequence, + // reset foundNumbers and foundCount, and go back to the holes + if (foundCount < req.requestedCount) { + foundNumbers = new TreeSet<>(); + foundCount = 0; + } + } + + if (req.reverseOrder) { + for (int i = req.rangeList.size() - 1; i >= 0; i--) { + Range range = req.rangeList.get(i); + for (int n = range.max; foundCount < req.requestedCount && n >= range.min; n--) { + if (RangeUtil.checkRange(rr, req, n)) { + foundNumbers.add(n); + foundCount++; + } else if (req.sequential) { + foundCount = 0; + } + } + } + } else { + for (Range range : req.rangeList) { + for (int n = range.min; foundCount < req.requestedCount && n <= range.max; n++) { + if (RangeUtil.checkRange(rr, req, n)) { + foundNumbers.add(n); + foundCount++; + } else if (req.sequential) { + foundCount = 0; + } + } + } + } + } + + out.status = foundCount == req.requestedCount ? AllocationStatus.Success : AllocationStatus.Failure; + } + } + + if (out.status == AllocationStatus.Success) { + out.allocated = foundNumbers; + if (req.allocate) { + RangeUtil.allocateRange(rr, out.allocated, req); + updateList.add(rr); + } + } else { + out.allocated = new TreeSet<>(); + } + + out.used = rr.used; + + return out; + } + + public AllocationOutcome getAllocationOutcome() { + return outcome; + } +} |