-
Notifications
You must be signed in to change notification settings - Fork 99
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix getNextAvailableAddress to use local maximums instead of just last a... #168
Changes from 1 commit
1ec999d
8a5408e
eee92c3
5b878c0
3be2e75
f706731
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -27,7 +27,7 @@ trait IpAddressable extends ValidatedEntity[Long] { | |
def getId(): Long = id | ||
def getAssetId(): Long = asset_id | ||
def getAsset(): Asset = Asset.findById(getAssetId()).get | ||
|
||
} | ||
|
||
trait IpAddressStorage[T <: IpAddressable] extends Schema with AnormAdapter[T] { | ||
|
@@ -75,15 +75,15 @@ trait IpAddressStorage[T <: IpAddressable] extends Schema with AnormAdapter[T] { | |
} | ||
|
||
def getNextAvailableAddress(overrideStart: Option[String] = None)(implicit scope: Option[String]): Tuple3[Long,Long,Long] = { | ||
//this is used by ip allocation without pools (i.e. IPMI) | ||
val network = getNetwork | ||
val startAt = overrideStart.orElse(getStartAddress) | ||
val calc = IpAddressCalc(network, startAt) | ||
val gateway: Long = getGateway().getOrElse(calc.minAddressAsLong) | ||
val netmask: Long = calc.netmaskAsLong | ||
val currentMax: Option[Long] = getCurrentMaxAddress( | ||
calc.minAddressAsLong, calc.maxAddressAsLong | ||
) | ||
val address: Long = calc.nextAvailableAsLong(currentMax) | ||
// look for the local maximum address (i.e. the last used address in a continuous sequence from startAddress) | ||
val localMax: Option[Long] = getCurrentLowestLocalMaxAddress(calc.minAddressAsLong, calc.maxAddressAsLong) | ||
val address: Long = calc.nextAvailableAsLong(localMax) | ||
(gateway, address, netmask) | ||
} | ||
|
||
|
@@ -95,7 +95,7 @@ trait IpAddressStorage[T <: IpAddressable] extends Schema with AnormAdapter[T] { | |
var i = 0 | ||
do { | ||
try { | ||
res = Some(f(i)) | ||
res = Some(f(i)) | ||
} catch { | ||
case e: SQLException => | ||
logger.info("createAddressWithRetry attempt %d: %s".format((i + 1), e.getMessage)) | ||
|
@@ -115,14 +115,39 @@ trait IpAddressStorage[T <: IpAddressable] extends Schema with AnormAdapter[T] { | |
) | ||
} | ||
|
||
protected def getCurrentMaxAddress(minAddress: Long, maxAddress: Long)(implicit scope: Option[String]): Option[Long] = inTransaction { | ||
from(tableDef)(t => | ||
/* | ||
* returns the lowest last used address in a continuous sequence from minAddress | ||
* If maxAddress is the same as the lowest last used address, we return None which signifies | ||
* that you should start allocating addresses from the start of the range. | ||
* | ||
* Ex: For a range 0L..20L, used addresses List(1,2,3,4,5,13,14,15,19,20), the result will be Some(5) | ||
* For a range 0L..20L, used addresses List(5,6,7,8,19,20), the result will be Some(8) | ||
* For a range 0L..20L, used addresses List(17,18,19,20), the result will be None (allocate from beginning) | ||
*/ | ||
protected def getCurrentLowestLocalMaxAddress(minAddress: Long, maxAddress: Long)(implicit scope: Option[String]): Option[Long] = { | ||
val sortedAddresses = from(tableDef)(t => | ||
where( | ||
(t.address gte minAddress) and | ||
(t.address lte maxAddress) | ||
) | ||
compute(max(t.address)) | ||
) | ||
select(t.address) | ||
orderBy(t.address asc) | ||
).toList | ||
val localMaximaAddresses = for ( | ||
localMax <- sortedAddresses if !sortedAddresses.contains(localMax + 1) | ||
) yield localMax | ||
|
||
localMaximaAddresses.isEmpty match { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. localMaximaAddresses.headOption.flatMap( localMax => ...) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah awesome. I knew there had to be something like that, but totally forgot about this method. Thanks, that will clean this up |
||
case true => None | ||
case false => { | ||
val localMax = localMaximaAddresses.head | ||
localMax match { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is possibly better off as an if, you aren't using limit anywhere. Code generated for pattern matching especially with guards is worse than an if stmt
|
||
//if we are at the end of our range, start from the beginning | ||
case limit if localMax == maxAddress => None | ||
case _ => Some(localMax) | ||
} | ||
} | ||
} | ||
} | ||
|
||
protected def getGateway()(implicit scope: Option[String]): Option[Long] = getConfig() match { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is probably the way to write this entire function
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I use a SortedSet, this doesnt work, as apply() on a SortedSet is a boolean (contains). I suppose though there isnt a need for a sorted set though, so Ill use your solution with normal lists that are sorted by the DB.
O(n) is better than O(nlog(n)) :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So this comprehension doesnt cover the case where sortedAddresses.size<=2 (meaning the range is 0..0) when using
Stream.range
, because it is not inclusive. Interestingly:I havent been able to find out how to make a Stream range be inclusive. Any ideas? This current iteration of code eats it after allocating the first address, because it thinks there are no localMaxima still :(