package org.ovirt.engine.core.bll.network.macpool; import java.util.ArrayList; import java.util.BitSet; import java.util.List; import org.apache.commons.lang.Validate; class Range { private final long rangeStart; private final long rangeEnd; private final int numberOfMacsInRange; /** * object counter, which holds number of MACs duplicates. */ private final ObjectCounter<Integer> macDuplicityCount = new ObjectCounter<>(true); private int availableMacsCount; private BitSet usedMacs; private int startingLocationWhenSearchingForUnusedMac = 0; public Range(long rangeStart, long rangeEnd) { this.rangeStart = rangeStart; this.rangeEnd = rangeEnd; long numberOfMacsLong = (rangeEnd - rangeStart) + 1; Validate.isTrue(numberOfMacsLong <= Integer.MAX_VALUE, String.format("Range too big; Range shouldn't be bigger than %1$s, but passed one " + "contains %2$s elements.", Integer.MAX_VALUE, numberOfMacsLong)); numberOfMacsInRange = (int) numberOfMacsLong; this.availableMacsCount = numberOfMacsInRange; this.usedMacs = new BitSet(numberOfMacsInRange); } public boolean contains(long mac) { return rangeStart <= mac && rangeEnd >= mac; } private void checkIfMacIsFromWithinRange(long mac) { if (!contains(mac)) { throw new IllegalArgumentException(); } } /** * @param mac mac to add * * @return if mac was used (it's usage count was increased). I.e. if it was not used, it's used now, or * it was used and duplicates are allowed so it's not used one more time. */ public boolean use(long mac, boolean allowDuplicates) { checkIfMacIsFromWithinRange(mac); int arrayIndex = macToArrayIndex(mac); if (!usedMacs.get(arrayIndex)) { availableMacsCount--; usedMacs.set(arrayIndex, true); return true; } if (allowDuplicates) { return macDuplicityCount.increase(arrayIndex); } else { return false; } } private int macToArrayIndex(long mac) { return (int) (mac - rangeStart); } public boolean isAllocated(long mac) { checkIfMacIsFromWithinRange(mac); return usedMacs.get(macToArrayIndex(mac)); } public void freeMac(long mac) { checkIfMacIsFromWithinRange(mac); int arrayIndex = macToArrayIndex(mac); if (!usedMacs.get(arrayIndex)) { return; } final boolean duplicatesExist = macDuplicityCount.count(arrayIndex) != 0; if (duplicatesExist) { macDuplicityCount.decrease(arrayIndex); } else { usedMacs.set(arrayIndex, false); availableMacsCount++; } } public int getAvailableCount() { return availableMacsCount; } public List<Long> allocateMacs(int numberOfMacs) { if (numberOfMacs > getAvailableCount()) { throw new IllegalStateException("Insufficient amount of free MACs."); } List<Long> result = new ArrayList<>(numberOfMacs); for (int count = 0; count < numberOfMacs; count++) { final long mac = findUnusedMac(); // Well duplicates may be allowed, but we're using unallocated mac. use(mac, false); result.add(mac); } return result; } private long findUnusedMac() { int index = usedMacs.nextClearBit(startingLocationWhenSearchingForUnusedMac); boolean notFound = index == numberOfMacsInRange; if (notFound) { index = usedMacs.nextClearBit(0); } startingLocationWhenSearchingForUnusedMac = (index + 1) % numberOfMacsInRange; return rangeStart + index; } }