Martin Mucha has posted comments on this change. Change subject: core: MacPoolManager strategy, alternative implementation, test for benchmarks ......................................................................
Patch Set 18: (62 comments) answers. http://gerrit.ovirt.org/#/c/26405/18//COMMIT_MSG Commit Message: Line 3: AuthorDate: 2014-04-03 15:34:31 +0200 Line 4: Commit: Martin Mucha <mmu...@redhat.com> Line 5: CommitDate: 2014-05-16 08:40:03 +0200 Line 6: Line 7: core: MacPoolManager strategy, alternative implementation, test for > Pretty sure this needs to be updated. Done Line 8: benchmarks Line 9: Line 10: * internals of MacPoolManager moved to separate implementation of Line 11: MacPoolManagerStrategy (MacPoolManagerStrategyOriginal) to allow Line 31: *MacPoolManager is singleton; only 'getInstance()' has to be Line 32: static other methods should be instance methods. Having them Line 33: static is mixing concepts. Line 34: --- Line 35: space costs(for 1 000 000 MACs range): > All the information bought forth is nice and very informative, but it would ok, can you point me to proper wiki page? This should probably not go to feature page. should this be removed from this message? It documents what have been done and with what outcome ... Line 36: (these measurements need not be accurate, but it's probably the Line 37: best you can get from JVM): Line 38: Measurement for: MacPoolManagerOriginal------ Line 39: Time: 794 ms http://gerrit.ovirt.org/#/c/26405/18/backend/manager/modules/bll/pom.xml File backend/manager/modules/bll/pom.xml: Line 18: <engine.schema>engine</engine.schema> Line 19: </properties> Line 20: Line 21: <dependencies> Line 22: > Not necessary to touch pom.xml at all, right? Done Line 23: <dependency> Line 24: <groupId>${engine.groupId}</groupId> Line 25: <artifactId>compat</artifactId> Line 26: <version>${engine.version}</version> http://gerrit.ovirt.org/#/c/26405/18/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/network/MacPoolManagerOriginal.java File backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/network/MacPoolManagerOriginal.java: Line 21 Line 22 Line 23 Line 24 Line 25 > Due to this change, org.ovirt.engine.core.utils.MacAddressRangeUtils.initRa I remove unused method; that's not a problem even in this patch. http://gerrit.ovirt.org/#/c/26405/18/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/network/MacPoolManagerRanges.java File backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/network/MacPoolManagerRanges.java: Line 19: public class MacPoolManagerRanges implements MacPoolManagerStrategy{ Line 20: Line 21: private static final Log log = LogFactory.getLog(MacPoolManagerRanges.class); Line 22: Line 23: private final int maxMacsInPool; > This should be deleted since there will be no possibility of memory leak, a I don't know intentions behind each config value. This is still valid config value. Until we deprecate it, it should remain functional. I'm not aware of request of deprecating this value and if there is such one(let me know) it should be done in another commit. Line 24: private final String rangesString; Line 25: Line 26: private final ReentrantReadWriteLock lockObj = new ReentrantReadWriteLock(); Line 27: private final Boolean allowDuplicates; Line 23: private final int maxMacsInPool; Line 24: private final String rangesString; Line 25: Line 26: private final ReentrantReadWriteLock lockObj = new ReentrantReadWriteLock(); Line 27: private final Boolean allowDuplicates; > Would null value make sense? Done Line 28: private boolean initialized; Line 29: private MacsStorage macsStorage; Line 30: Line 31: public MacPoolManagerRanges(Integer maxMacsInPool, String rangesString, Boolean allowDuplicates) { Line 35: } Line 36: Line 37: @Override Line 38: public void initialize() { Line 39: checkNotInitialized(); > This isn't thread safe. Done Line 40: Line 41: lockObj.writeLock().lock(); Line 42: try { Line 43: log.infoFormat("Start initializing "+getClass().getSimpleName()); Line 40: Line 41: lockObj.writeLock().lock(); Line 42: try { Line 43: log.infoFormat("Start initializing "+getClass().getSimpleName()); Line 44: > Not sure why there are so many empty lines between some code, and no new li Done Line 45: this.macsStorage = createMacsStorage(rangesString); Line 46: Line 47: Line 48: List<VmNic> interfaces = getVmNicInterfacesFromDB(); Line 41: lockObj.writeLock().lock(); Line 42: try { Line 43: log.infoFormat("Start initializing "+getClass().getSimpleName()); Line 44: Line 45: this.macsStorage = createMacsStorage(rangesString); > Don't call with this Done Line 46: Line 47: Line 48: List<VmNic> interfaces = getVmNicInterfacesFromDB(); Line 49: Line 50: for (VmNic iface : interfaces) { Line 51: forceAddMacWithoutLocking(iface.getMacAddress()); Line 52: } Line 53: initialized = true; Line 54: log.infoFormat("Finished initializing. Available MACs in pool: {0}", this.macsStorage.getAvailableMacsCount()); > Don't call with this Done Line 55: } catch (Exception ex) { Line 56: log.errorFormat("Error in initializing MAC Addresses pool manager.", ex); Line 57: } finally { Line 58: lockObj.writeLock().unlock(); Line 61: Line 62: private MacsStorage createMacsStorage(String rangesString) { Line 63: List<Pair<Long, Long>> rangesBoundaries = MacAddressRangeUtils.rangesTextualDefinitionToRangeBoundaries(rangesString); Line 64: int macsToCreate = maxMacsInPool; Line 65: MacsStorage macsStorage = new MacsStorage(this.allowDuplicates); > Don't call with this Done Line 66: for (Pair<Long, Long> rangesBoundary : rangesBoundaries) { Line 67: macsToCreate -= macsStorage.addRange(rangesBoundary.getFirst(), rangesBoundary.getSecond(), macsToCreate); Line 68: } Line 69: Line 62: private MacsStorage createMacsStorage(String rangesString) { Line 63: List<Pair<Long, Long>> rangesBoundaries = MacAddressRangeUtils.rangesTextualDefinitionToRangeBoundaries(rangesString); Line 64: int macsToCreate = maxMacsInPool; Line 65: MacsStorage macsStorage = new MacsStorage(this.allowDuplicates); Line 66: for (Pair<Long, Long> rangesBoundary : rangesBoundaries) { > Shouldn't the single instance be called just range? rewritten to use LongRange and uses name range. Line 67: macsToCreate -= macsStorage.addRange(rangesBoundary.getFirst(), rangesBoundary.getSecond(), macsToCreate); Line 68: } Line 69: Line 70: if (macsStorage.noAvailableMacs()) { Line 68: } Line 69: Line 70: if (macsStorage.noAvailableMacs()) { Line 71: throw new VdcBLLException(VdcBllErrors.MAC_POOL_INITIALIZATION_FAILED); Line 72: } else { > No need for else clause here we've already discussed it many times. Semantically full if-else construct is used for condition checking, only if with return is used for invariants. This is not an invariant. Why do you insist on code compression? This is normal java code construct. Line 73: return macsStorage; Line 74: } Line 75: } Line 76: Line 73: return macsStorage; Line 74: } Line 75: } Line 76: Line 77: private List<VmNic> getVmNicInterfacesFromDB() { > s/DB/Db/ Done Line 78: return DbFacade.getInstance().getVmNicDao().getAll(); Line 79: } Line 80: Line 81: private void logMacPoolEmpty() { Line 77: private List<VmNic> getVmNicInterfacesFromDB() { Line 78: return DbFacade.getInstance().getVmNicDao().getAll(); Line 79: } Line 80: Line 81: private void logMacPoolEmpty() { > I would put the "if (macsStorage.noAvailableMacs()) {" inside, since it's p nice observation. DONE. Line 82: AuditLogableBase logable = new AuditLogableBase(); Line 83: AuditLogDirector.log(logable, AuditLogType.MAC_POOL_EMPTY); Line 84: } Line 85: Line 84: } Line 85: Line 86: @Override Line 87: public String allocateNewMac() { Line 88: checkInitialized(); > This isn't thread safe Done Line 89: lockObj.writeLock().lock(); Line 90: try { Line 91: return allocateNewMacsWithoutLocking(1).get(0); Line 92: } finally { Line 94: } Line 95: } Line 96: Line 97: private List<String> allocateNewMacsWithoutLocking(int numberOfMacs) { Line 98: if (!initialized) { > Why do you need this if you already checked if initialized in both places c Done Line 99: logInitializationError("Failed to allocate new Mac address."); Line 100: throw new VdcBLLException(VdcBllErrors.MAC_POOL_NOT_INITIALIZED); Line 101: } Line 102: Line 110: } Line 111: Line 112: @Override Line 113: public int getAvailableMacsCount() { Line 114: checkInitialized(); > This isn't thread safe Done Line 115: lockObj.readLock().lock(); Line 116: try { Line 117: if (!initialized) { Line 118: logInitializationError("Failed to get available Macs count."); Line 113: public int getAvailableMacsCount() { Line 114: checkInitialized(); Line 115: lockObj.readLock().lock(); Line 116: try { Line 117: if (!initialized) { > Why check again if initialized? Done Line 118: logInitializationError("Failed to get available Macs count."); Line 119: throw new VdcBLLException(VdcBllErrors.MAC_POOL_NOT_INITIALIZED); Line 120: } Line 121: Line 128: } Line 129: Line 130: @Override Line 131: public void freeMac(String mac) { Line 132: checkInitialized(); > This isn't thread safe Done Line 133: lockObj.writeLock().lock(); Line 134: try { Line 135: if (!initialized) { Line 136: logInitializationError("Failed to free mac address " + mac + " ."); Line 131: public void freeMac(String mac) { Line 132: checkInitialized(); Line 133: lockObj.writeLock().lock(); Line 134: try { Line 135: if (!initialized) { > Why check again if initialized? Done Line 136: logInitializationError("Failed to free mac address " + mac + " ."); Line 137: } else { Line 138: macsStorage.freeMac(MacAddressRangeUtils.macToLong(mac)); Line 139: } Line 150: } Line 151: Line 152: @Override Line 153: public boolean addMac(String mac) { Line 154: checkInitialized(); > This isn't thread safe Done Line 155: lockObj.writeLock().lock(); Line 156: try { Line 157: boolean added = this.macsStorage.useMac(MacAddressRangeUtils.macToLong(mac)); Line 158: if (macsStorage.noAvailableMacs()) { Line 153: public boolean addMac(String mac) { Line 154: checkInitialized(); Line 155: lockObj.writeLock().lock(); Line 156: try { Line 157: boolean added = this.macsStorage.useMac(MacAddressRangeUtils.macToLong(mac)); > Don't call with this Done Line 158: if (macsStorage.noAvailableMacs()) { Line 159: logMacPoolEmpty(); Line 160: } Line 161: return added; Line 167: } Line 168: Line 169: @Override Line 170: public void forceAddMac(String mac) { Line 171: checkInitialized(); > This isn't thread safe Done Line 172: lockObj.writeLock().lock(); Line 173: try { Line 174: this.macsStorage.useMacNoDuplicityCheck(MacAddressRangeUtils.macToLong(mac)); Line 175: if (macsStorage.noAvailableMacs()) { Line 170: public void forceAddMac(String mac) { Line 171: checkInitialized(); Line 172: lockObj.writeLock().lock(); Line 173: try { Line 174: this.macsStorage.useMacNoDuplicityCheck(MacAddressRangeUtils.macToLong(mac)); > Why not call forceAddMacWithoutLocking? Done Line 175: if (macsStorage.noAvailableMacs()) { Line 176: logMacPoolEmpty(); Line 177: } Line 178: } finally { Line 180: } Line 181: } Line 182: Line 183: private void forceAddMacWithoutLocking(String mac) { Line 184: this.macsStorage.useMacNoDuplicityCheck(MacAddressRangeUtils.macToLong(mac)); > Don't call with this Done Line 185: if (macsStorage.noAvailableMacs()) { Line 186: logMacPoolEmpty(); Line 187: } Line 188: } Line 188: } Line 189: Line 190: @Override Line 191: public boolean isMacInUse(String mac) { Line 192: checkInitialized(); > This isn't thread safe Done Line 193: lockObj.readLock().lock(); Line 194: try { Line 195: return this.macsStorage.isMacInUse(MacAddressRangeUtils.macToLong(mac)); Line 196: Line 191: public boolean isMacInUse(String mac) { Line 192: checkInitialized(); Line 193: lockObj.readLock().lock(); Line 194: try { Line 195: return this.macsStorage.isMacInUse(MacAddressRangeUtils.macToLong(mac)); > Don't call with this Done Line 196: Line 197: } finally { Line 198: lockObj.readLock().unlock(); Line 199: } Line 199: } Line 200: } Line 201: Line 202: @Override Line 203: public void freeMacs(List<String> macs) { //TODO MM: how about some duplicities here? Release it twice or what? > What did original code do? released duplicate macs number of times. Preserving behavior, todo removed. Line 204: checkInitialized(); Line 205: if (!macs.isEmpty()) { Line 206: lockObj.writeLock().lock(); Line 207: try { Line 200: } Line 201: Line 202: @Override Line 203: public void freeMacs(List<String> macs) { //TODO MM: how about some duplicities here? Release it twice or what? Line 204: checkInitialized(); > This isn't thread safe Done Line 205: if (!macs.isEmpty()) { Line 206: lockObj.writeLock().lock(); Line 207: try { Line 208: for (String mac : macs) { Line 216: } Line 217: Line 218: @Override Line 219: public List<String> allocateMacAddresses(int numberOfAddresses) { Line 220: checkInitialized(); > This isn't thread safe Done Line 221: lockObj.writeLock().lock(); Line 222: try { Line 223: List<String> macAddresses = this.allocateNewMacsWithoutLocking(numberOfAddresses); Line 224: return macAddresses; Line 219: public List<String> allocateMacAddresses(int numberOfAddresses) { Line 220: checkInitialized(); Line 221: lockObj.writeLock().lock(); Line 222: try { Line 223: List<String> macAddresses = this.allocateNewMacsWithoutLocking(numberOfAddresses); > Don't call with this Done Line 224: return macAddresses; Line 225: } finally { Line 226: lockObj.writeLock().unlock(); Line 227: } Line 220: checkInitialized(); Line 221: lockObj.writeLock().lock(); Line 222: try { Line 223: List<String> macAddresses = this.allocateNewMacsWithoutLocking(numberOfAddresses); Line 224: return macAddresses; > You can return immediately, no need for variable Done Line 225: } finally { Line 226: lockObj.writeLock().unlock(); Line 227: } Line 228: } Line 233: throw new IllegalStateException("This instance was already initialized."); Line 234: } Line 235: } Line 236: Line 237: private void checkInitialized() { > You should call logInitializationError and also throw a VdcBLLException(Vdc I hope I did not overlook something but I think it's not called where it formerly wasn't. Line 238: if (!initialized) { Line 239: throw new IllegalStateException("This instance not yet initialized."); Line 240: } Line 241: Line 241: Line 242: } Line 243: Line 244: @Override Line 245: public void copyContent(MacPoolManagerStrategy macPoolManagerStrategy) { > This method is unused.. Done Line 246: macsStorage.copyAllocatedCustomMacs(macPoolManagerStrategy); Line 247: macsStorage.copyAllocatedMacs(macPoolManagerStrategy); Line 248: } Line 249: http://gerrit.ovirt.org/#/c/26405/18/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/network/MacPoolManagerStrategy.java File backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/network/MacPoolManagerStrategy.java: Line 59: * @throws org.ovirt.engine.core.common.errors.VdcBLLException if mac address cannot be allocated. Line 60: */ Line 61: List<String> allocateMacAddresses(int numberOfAddresses); Line 62: Line 63: void copyContent(MacPoolManagerStrategy macPoolManagerStrategy); > Why add unused method? 1. I've moved method to another patchset 2. I've renamed it to copyContentInto — I cannot satisfy your requested parameter to act as source, since there are no public method for iterating over MACs and user-macs; in fact public api does not reveal there's is such distinction among macs. I do believe this is better, but this comes at price parameter being target, not source. Line 64: Line 65: http://gerrit.ovirt.org/#/c/26405/18/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/network/MacsStorage.java File backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/network/MacsStorage.java: Line 28: } Line 29: } Line 30: Line 31: long size = i - rangeStart; Line 32: if (size > Integer.MAX_VALUE) { > If you're already limiting to Integer.MAX_VALUE, there is no sense to look you're right it can be done this way, but this is refactor — i just left what was formerly there. Looping for multicasts removal is fixed in following changeset by fixing input ranges. I think this should be ok. Line 33: throw new IllegalArgumentException("Not supported that wide ranges(" + size + ")."); Line 34: } Line 35: Line 36: if (numberOfNonMultiCasts > 0) { Line 29: } Line 30: Line 31: long size = i - rangeStart; Line 32: if (size > Integer.MAX_VALUE) { Line 33: throw new IllegalArgumentException("Not supported that wide ranges(" + size + ")."); > Since you decided to limit this, please take care of upgrade so that if the I did not decide to introduce this "limitation". I decided to check this. This was always a "limitation". You cannot stick more entries into java collections. Next. Engine hw requirements are 16GB of RAM (fow webapp, wow). Just to use system to this 'limitation' you would need 2^32 of 64b pointers (hashset is backed by hashmap, so take it twice) + 2^32 of 17B representation of MAC. If I'm not mistaken this sums up to 142GB of RAM minimum just for pool. Is there any chance that there exist customer with such deployment? Never heard a java program using 30GB of ram, although there exist JVM claiming they can handle 0.5TB or RAM. My point: if somebody had used such setting, app was not able to start or run. Now he got better exception than OutOfMemory. I can revert that if needed, ok, but it's pointless, from mine point of view. NOBODY could have use that settings. Line 34: } Line 35: Line 36: if (numberOfNonMultiCasts > 0) { Line 37: //java. arrays/collections can not be bigger than 2^32. Line 33: throw new IllegalArgumentException("Not supported that wide ranges(" + size + ")."); Line 34: } Line 35: Line 36: if (numberOfNonMultiCasts > 0) { Line 37: //java. arrays/collections can not be bigger than 2^32. > Not sure why this comment is relevant it relates to casting long to int. User supplies range can contain more MACs than fits to integer. For that reason there's check, cast and explanation in comment. Line 38: ranges.add(new Range(rangeStart, (int)size, numberOfNonMultiCasts)); Line 39: } Line 40: return numberOfNonMultiCasts; Line 41: } Line 43: public boolean useMac(long mac) { Line 44: return useMac(mac, allowDuplicates); Line 45: } Line 46: Line 47: private boolean useMac(long mac, Boolean allowDuplicates) { > What is the significance of a null allowDuplicates? Done Line 48: testForMultiCastMac(mac); Line 49: Line 50: Range range = findIncludingRange(mac); Line 51: if (range == null) { Line 48: testForMultiCastMac(mac); Line 49: Line 50: Range range = findIncludingRange(mac); Line 51: if (range == null) { Line 52: return this.customMacs.add(mac); > Don't use this Done Line 53: } else { Line 54: return range.use(mac, allowDuplicates); Line 55: } Line 56: } Line 62: public boolean isMacInUse(long mac) { Line 63: testForMultiCastMac(mac); Line 64: Line 65: Range range = findIncludingRange(mac); Line 66: return range == null ? this.customMacs.contains(mac) : range.isAllocated(mac); > Don't use this Done Line 67: } Line 68: Line 69: public void freeMac(long mac) { Line 70: testForMultiCastMac(mac); Line 70: testForMultiCastMac(mac); Line 71: Line 72: Range range = findIncludingRange(mac); Line 73: if (range == null) { Line 74: this.customMacs.remove(mac); > Don't use this Done Line 75: } else { Line 76: range.freeMac(mac); Line 77: } Line 78: } Line 76: range.freeMac(mac); Line 77: } Line 78: } Line 79: Line 80: public boolean noAvailableMacs() { > Please change to positive method, as double negative is harder to maintain Done Line 81: for (Range range : ranges) { Line 82: if (range.getAvailableCount() > 0) { Line 83: return false; Line 84: } Line 85: } Line 86: return true; Line 87: } Line 88: Line 89: public List<Long> allocateAvailableMac(int numberOfMacs) { > Should be allocateAvailableMacs Done Line 90: if (getAvailableMacsCount() < numberOfMacs) { //TODO MM: allocate just those remaining or none? Line 91: throw new VdcBLLException(VdcBllErrors.MAC_POOL_NO_MACS_LEFT); Line 92: } Line 93: Line 86: return true; Line 87: } Line 88: Line 89: public List<Long> allocateAvailableMac(int numberOfMacs) { Line 90: if (getAvailableMacsCount() < numberOfMacs) { //TODO MM: allocate just those remaining or none? > Don't allocate any MACs if there aren't enough Done Line 91: throw new VdcBLLException(VdcBllErrors.MAC_POOL_NO_MACS_LEFT); Line 92: } Line 93: Line 94: return getRangeWithAvailableMac().allocateMac(numberOfMacs); Line 90: if (getAvailableMacsCount() < numberOfMacs) { //TODO MM: allocate just those remaining or none? Line 91: throw new VdcBLLException(VdcBllErrors.MAC_POOL_NO_MACS_LEFT); Line 92: } Line 93: Line 94: return getRangeWithAvailableMac().allocateMac(numberOfMacs); > What if there is no one range with the free amount of MACs, but across seve Done Line 95: } Line 96: Line 97: private Range getRangeWithAvailableMac() { Line 98: for (Range range : ranges) { Line 110: } Line 111: return count; Line 112: } Line 113: Line 114: private void testForMultiCastMac(long mac) { > No need for this method I don't get why. It block user from supplying multicast address. Which should be blocked, no? Line 115: if (MacAddressRangeUtils.macIsMulticast(mac)) { Line 116: throw new IllegalArgumentException("You're trying to work with multicast address."); //TODO MM: should this be prohibited? Line 117: } Line 118: } Line 125: } Line 126: return null; Line 127: } Line 128: Line 129: public void copyAllocatedCustomMacs(MacPoolManagerStrategy macPoolManagerStrategy) { > Please remove and add when used Done Line 130: for (Long mac : customMacs) { Line 131: final int count = customMacs.count(mac); Line 132: final String macString = MacAddressRangeUtils.macToString(mac); Line 133: Line 136: } Line 137: } Line 138: } Line 139: Line 140: public void copyAllocatedMacs(MacPoolManagerStrategy macPoolManagerStrategy) { > Please remove and add when used Done Line 141: for (Range range : ranges) { Line 142: range.copyAllocatedMacs(macPoolManagerStrategy); Line 143: } Line 144: } http://gerrit.ovirt.org/#/c/26405/18/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/network/Range.java File backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/network/Range.java: Line 12: private int notUsedCount; Line 13: Line 14: private UsedMacs usedMacs; Line 15: Line 16: public boolean contains(long mac) { > Why is this before the c'tor? Done Line 17: return offset <= mac && (offset + size) >= mac; Line 18: } Line 19: Line 20: public Range(long offset, int size, int numberOfNonMultiCasts) { Line 21: this.offset = offset; Line 22: this.size = size; Line 23: this.notUsedCount = numberOfNonMultiCasts; Line 24: Line 25: macUsageCount = new int[size]; > This seems very problematic to me, if user defines a range of same OUI (i.e yes, you're right. I don't have idea how to make it any better and keep the code clean. If you have idea, let me know. Comment: as I got it Collections are out of game (wrappers, pointers) and so are common data structures since 64b pointers are really expensive (even 32b pointers are when used with CompressedOops). Unless we know threshold for maximum MAC duplicate usage or unless we block duplicate usage, I don't know how to improve that. Line 26: this.usedMacs = new UsedMacsBitSet(size); Line 27: } Line 28: Line 29: /** Line 29: /** Line 30: * Line 31: * @param mac mac to add Line 32: * @return if mac was used (it's usage count was increased). I.e. if it was not used, it's used now, or Line 33: * it was used and duplicates are allowed so it's not used some more. > "so it's not used some more"? Done Line 34: */ Line 35: public boolean use(long mac, boolean allowDuplicates) { Line 36: try { Line 37: int index = macToArrayIndex(mac); Line 34: */ Line 35: public boolean use(long mac, boolean allowDuplicates) { Line 36: try { Line 37: int index = macToArrayIndex(mac); Line 38: int currentCount = currentCount(index); > Why assign to variable that is used only once? Done Line 39: Line 40: if (currentCount == 0) { Line 41: notUsedCount--; Line 42: this.usedMacs.removeMacFromNotUsed(macToArrayIndex(mac)); Line 49: return true; Line 50: } Line 51: Line 52: return false; Line 53: } catch (Exception e) { > What exception do you expect to happen? can't remember why I put that in. Removed. Line 54: throw new RuntimeException("failed use during adding mac: " + mac + ", index = " + (mac - offset), e); Line 55: } Line 56: Line 57: } Line 55: } Line 56: Line 57: } Line 58: Line 59: private int currentCount(int index) { > what is the necessity of this method? Done Line 60: return macUsageCount[index]; Line 61: } Line 62: Line 63: private int macToArrayIndex(long mac) { Line 65: } Line 66: Line 67: public boolean isAllocated(long mac) { Line 68: int index = macToArrayIndex(mac); Line 69: int currentCount = macUsageCount[index]; > This can all be inlined don't you think it's more readable this way? Line 70: return currentCount > 0; Line 71: } Line 72: Line 73: public void freeMac(long mac) { Line 70: return currentCount > 0; Line 71: } Line 72: Line 73: public void freeMac(long mac) { Line 74: int index = macToArrayIndex(mac); > This can be inlined don't you think it's more readable this way? Line 75: int currentCount = macUsageCount[index]; Line 76: if (currentCount == 0) { Line 77: return; Line 78: } Line 89: public int getAvailableCount() { Line 90: return notUsedCount; Line 91: } Line 92: Line 93: public List<Long> allocateMac(int numberOfMacs) { > Should be called allocateMacs who told you that? what's wrong with 'result'? 'Result' of function computation ... Why that seems odd? (Actually this is recommended way in many languagues; http://www.javapractices.com/topic/TopicAction.do?Id=63) Line 94: List<Long> result = new ArrayList<>(numberOfMacs); Line 95: Line 96: int count = 0; Line 97: while (count < numberOfMacs) { Line 93: public List<Long> allocateMac(int numberOfMacs) { Line 94: List<Long> result = new ArrayList<>(numberOfMacs); Line 95: Line 96: int count = 0; Line 97: while (count < numberOfMacs) { > Why not for loop? Done Line 98: final long mac = usedMacs.unusedMac(offset); Line 99: use(mac, false); //well duplicates may be allowed, but we're using unallocated mac. Line 100: count++; Line 101: result.add(mac); Line 95: Line 96: int count = 0; Line 97: while (count < numberOfMacs) { Line 98: final long mac = usedMacs.unusedMac(offset); Line 99: use(mac, false); //well duplicates may be allowed, but we're using unallocated mac. > Please write comment before code. Done Line 100: count++; Line 101: result.add(mac); Line 102: } Line 103: http://gerrit.ovirt.org/#/c/26405/18/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/network/UsedMacsBitSet.java File backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/network/UsedMacsBitSet.java: Line 3: import java.util.BitSet; Line 4: Line 5: import org.ovirt.engine.core.utils.MacAddressRangeUtils; Line 6: Line 7: class UsedMacsBitSet implements UsedMacs { > This class is unnecessary and confusing, please remove it why is unnecessary? If I'm not mistaken, then this class is used to search unused mac, because linear search for MAC with usage count == 0 is very slow in large ranges. (introduced after actual measuring pool performance — after lots of fixes the measuring is of course gone, but still. This improved overall performance a lot). Line 8: Line 9: private BitSet bitSet; Line 10: Line 11: public UsedMacsBitSet(int size) { -- To view, visit http://gerrit.ovirt.org/26405 To unsubscribe, visit http://gerrit.ovirt.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: I69a5c1b3b43966e49fa6039597c06966ce514618 Gerrit-PatchSet: 18 Gerrit-Project: ovirt-engine Gerrit-Branch: master Gerrit-Owner: Martin Mucha <mmu...@redhat.com> Gerrit-Reviewer: Martin Mucha <mmu...@redhat.com> Gerrit-Reviewer: Mike Kolesnik <mkole...@redhat.com> Gerrit-Reviewer: Moti Asayag <masa...@redhat.com> Gerrit-Reviewer: Yevgeny Zaspitsky <yzasp...@redhat.com> Gerrit-Reviewer: automat...@ovirt.org Gerrit-Reviewer: oVirt Jenkins CI Server Gerrit-HasComments: Yes _______________________________________________ Engine-patches mailing list Engine-patches@ovirt.org http://lists.ovirt.org/mailman/listinfo/engine-patches