-
Notifications
You must be signed in to change notification settings - Fork 1.3k
CLOUDSTACK-9473: storage pool capacity check when volume is resized or migrated #2829
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
Changes from all commits
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 |
|---|---|---|
|
|
@@ -1788,8 +1788,8 @@ public boolean storagePoolHasEnoughSpace(List<Volume> volumes, StoragePool pool, | |
| if (s_logger.isDebugEnabled()) { | ||
| s_logger.debug("Destination pool id: " + pool.getId()); | ||
| } | ||
|
|
||
| StoragePoolVO poolVO = _storagePoolDao.findById(pool.getId()); | ||
| // allocated space includes templates | ||
| final StoragePoolVO poolVO = _storagePoolDao.findById(pool.getId()); | ||
| long allocatedSizeWithTemplate = _capacityMgr.getAllocatedPoolCapacity(poolVO, null); | ||
| long totalAskingSize = 0; | ||
|
|
||
|
|
@@ -1830,12 +1830,37 @@ public boolean storagePoolHasEnoughSpace(List<Volume> volumes, StoragePool pool, | |
| } | ||
| } | ||
|
|
||
| return checkPoolforSpace(pool, allocatedSizeWithTemplate, totalAskingSize); | ||
| } | ||
|
|
||
| @Override | ||
| public boolean storagePoolHasEnoughSpaceForResize(StoragePool pool, long currentSize, long newSiz) { | ||
| if (!checkUsagedSpace(pool)) { | ||
| return false; | ||
| } | ||
| if (s_logger.isDebugEnabled()) { | ||
| s_logger.debug("Destination pool id: " + pool.getId()); | ||
| } | ||
| long totalAskingSize = newSiz - currentSize; | ||
|
|
||
| if (totalAskingSize <= 0) { | ||
|
DaanHoogland marked this conversation as resolved.
|
||
| return true; | ||
| } else { | ||
| final StoragePoolVO poolVO = _storagePoolDao.findById(pool.getId()); | ||
| final long allocatedSizeWithTemplate = _capacityMgr.getAllocatedPoolCapacity(poolVO, null); | ||
| return checkPoolforSpace(pool, allocatedSizeWithTemplate, totalAskingSize); | ||
| } | ||
| } | ||
|
|
||
| private boolean checkPoolforSpace(StoragePool pool, long allocatedSizeWithTemplate, long totalAskingSize) { | ||
| // allocated space includes templates | ||
| StoragePoolVO poolVO = _storagePoolDao.findById(pool.getId()); | ||
|
|
||
| long totalOverProvCapacity; | ||
|
|
||
| if (pool.getPoolType().supportsOverProvisioning()) { | ||
| BigDecimal overProvFactor = getStorageOverProvisioningFactor(pool.getId()); | ||
| totalOverProvCapacity = overProvFactor.multiply(new BigDecimal(pool.getCapacityBytes())).longValue(); | ||
|
|
||
| s_logger.debug("Found storage pool " + poolVO.getName() + " of type " + pool.getPoolType().toString() + " with overprovisioning factor " + overProvFactor.toString()); | ||
| s_logger.debug("Total over provisioned capacity calculated is " + overProvFactor + " * " + pool.getCapacityBytes()); | ||
| } else { | ||
|
|
@@ -1847,21 +1872,26 @@ public boolean storagePoolHasEnoughSpace(List<Volume> volumes, StoragePool pool, | |
| s_logger.debug("Total capacity of the pool " + poolVO.getName() + " with ID " + pool.getId() + " is " + totalOverProvCapacity); | ||
|
|
||
| double storageAllocatedThreshold = CapacityManager.StorageAllocatedCapacityDisableThreshold.valueIn(pool.getDataCenterId()); | ||
|
|
||
| s_logger.debug("Checking pool: " + pool.getId() + " for volume allocation " + volumes.toString() + ", maxSize : " + totalOverProvCapacity + ", totalAllocatedSize : " | ||
| + allocatedSizeWithTemplate + ", askingSize : " + totalAskingSize + ", allocated disable threshold: " + storageAllocatedThreshold); | ||
| if (s_logger.isDebugEnabled()) { | ||
|
Member
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. Why checking before logging? We are removing this from other places. Let's remove conditionals from our code base.
Contributor
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. please let's always check before logging any lower priority (below error)
Member
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. I still see no real benefits of adding this log level checks in our context. On the other hand, I do see problems with readability of the code. I cannot object though, if you want to proceed with this ;) |
||
| s_logger.debug("Checking pool: " + pool.getId() + " for storage allocation , maxSize : " + totalOverProvCapacity + ", totalAllocatedSize : " + allocatedSizeWithTemplate | ||
| + ", askingSize : " + totalAskingSize + ", allocated disable threshold: " + storageAllocatedThreshold); | ||
| } | ||
|
|
||
| double usedPercentage = (allocatedSizeWithTemplate + totalAskingSize) / (double)(totalOverProvCapacity); | ||
|
|
||
| if (usedPercentage > storageAllocatedThreshold) { | ||
| s_logger.debug("Insufficient un-allocated capacity on: " + pool.getId() + " for volume allocation: " + volumes.toString() + " since its allocated percentage: " + usedPercentage | ||
| + " has crossed the allocated pool.storage.allocated.capacity.disablethreshold: " + storageAllocatedThreshold + ", skipping this pool"); | ||
| if (s_logger.isDebugEnabled()) { | ||
| s_logger.debug("Insufficient un-allocated capacity on: " + pool.getId() + " for storage allocation since its allocated percentage: " + usedPercentage | ||
| + " has crossed the allocated pool.storage.allocated.capacity.disablethreshold: " + storageAllocatedThreshold + ", skipping this pool"); | ||
| } | ||
| return false; | ||
| } | ||
|
|
||
| if (totalOverProvCapacity < (allocatedSizeWithTemplate + totalAskingSize)) { | ||
| s_logger.debug("Insufficient un-allocated capacity on: " + pool.getId() + " for volume allocation: " + volumes.toString() + ", not enough storage, maxSize : " + totalOverProvCapacity | ||
| + ", totalAllocatedSize : " + allocatedSizeWithTemplate + ", askingSize : " + totalAskingSize); | ||
| if (s_logger.isDebugEnabled()) { | ||
| s_logger.debug("Insufficient un-allocated capacity on: " + pool.getId() + " for storage allocation, not enough storage, maxSize : " + totalOverProvCapacity | ||
| + ", totalAllocatedSize : " + allocatedSizeWithTemplate + ", askingSize : " + totalAskingSize); | ||
| } | ||
| return false; | ||
| } | ||
|
|
||
|
|
||
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.
Is this if really needed? Can't you just log to debug and let the filter of log4j handle it?
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 log4j does not have debug enabled, then the string concat operation will still be performed by the JVM only when the string is passed to the
debug()method it will be ignored. So, it depends if we can afford the CPU/time spent on the operation.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.
I think we can afford this tiny bit of extra CPU.
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.
I think as a matter of principle we should alwas add the check. You never no for what reason someone will alter the message. I like using String.format to construct the message, btw, and then pass the single resulting string to the logger
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.
What principle?
I also use String.format, and I do not see the problem.
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.
"bla" + "blob" is a costly operation, basically to memcpy()s. String.format() as well in comparison. We don't want those operations performed if we don't end up using the result in a log statement. so the boolean check potentially saves us a lot of cpu cycles, especially in the debug() and trace() cases.
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.
Yes, I do know that. However, we should ask ourselves, if the addition of a if conditions (it will clutter the code) is worth the CPU cycles. For me, I would not trade readability for this small CPU cost in a web system (ACS is a at the end of the day a Java web application).