@@ -1728,6 +1728,11 @@ public HypervisorType getHypervisorTypeFromFormat(ImageFormat format) {
17281728 }
17291729
17301730 private boolean checkUsagedSpace (StoragePool pool ) {
1731+ // Managed storage does not currently deal with accounting for physically used space (only provisioned space). Just return true if "pool" is managed.
1732+ if (pool .isManaged ()) {
1733+ return true ;
1734+ }
1735+
17311736 StatsCollector sc = StatsCollector .getInstance ();
17321737 double storageUsedThreshold = CapacityManager .StorageCapacityDisableThreshold .valueIn (pool .getDataCenterId ());
17331738 if (sc != null ) {
@@ -1803,9 +1808,10 @@ public boolean storagePoolHasEnoughSpace(List<Volume> volumes, StoragePool pool,
18031808 }
18041809
18051810 // allocated space includes templates
1806- if (s_logger .isDebugEnabled ()) {
1811+ if (s_logger .isDebugEnabled ()) {
18071812 s_logger .debug ("Destination pool id: " + pool .getId ());
18081813 }
1814+
18091815 StoragePoolVO poolVO = _storagePoolDao .findById (pool .getId ());
18101816 long allocatedSizeWithTemplate = _capacityMgr .getAllocatedPoolCapacity (poolVO , null );
18111817 long totalAskingSize = 0 ;
@@ -1833,70 +1839,99 @@ public boolean storagePoolHasEnoughSpace(List<Volume> volumes, StoragePool pool,
18331839 allocatedSizeWithTemplate = _capacityMgr .getAllocatedPoolCapacity (poolVO , tmpl );
18341840 }
18351841 }
1836- // A ready state volume is already allocated in a pool. so the asking size is zero for it.
1837- // In case the volume is moving across pools or is not ready yet, the asking size has to be computed
1842+
18381843 if (s_logger .isDebugEnabled ()) {
1839- s_logger .debug ("pool id for the volume with id: " + volumeVO .getId () + " is " + volumeVO .getPoolId ());
1844+ s_logger .debug ("Pool ID for the volume with ID " + volumeVO .getId () + " is " + volumeVO .getPoolId ());
18401845 }
1841- if ((volumeVO .getState () != Volume .State .Ready ) || (volumeVO .getPoolId () != pool .getId ())) {
1842- if (ScopeType .ZONE .equals (poolVO .getScope ()) && volumeVO .getTemplateId () != null ) {
1843- VMTemplateVO tmpl = _templateDao .findByIdIncludingRemoved (volumeVO .getTemplateId ());
18441846
1845- if (tmpl != null && !ImageFormat .ISO .equals (tmpl .getFormat ())) {
1846- // Storage plug-ins for zone-wide primary storage can be designed in such a way as to store a template on the
1847- // primary storage once and make use of it in different clusters (via cloning).
1848- // This next call leads to CloudStack asking how many more bytes it will need for the template (if the template is
1849- // already stored on the primary storage, then the answer is 0).
1847+ // A ready-state volume is already allocated in a pool, so the asking size is zero for it.
1848+ // In case the volume is moving across pools or is not ready yet, the asking size has to be computed.
1849+ if ((volumeVO .getState () != Volume .State .Ready ) || (volumeVO .getPoolId () != pool .getId ())) {
1850+ totalAskingSize += getDataObjectSizeIncludingHypervisorSnapshotReserve (volumeVO , poolVO );
18501851
1851- if (clusterId != null && _clusterDao .getSupportsResigning (clusterId )) {
1852- totalAskingSize += getBytesRequiredForTemplate (tmpl , pool );
1853- }
1854- }
1855- }
1852+ totalAskingSize += getAskingSizeForTemplateBasedOnClusterAndStoragePool (volumeVO .getTemplateId (), clusterId , poolVO );
18561853 }
18571854 }
18581855
18591856 long totalOverProvCapacity ;
1857+
18601858 if (pool .getPoolType ().supportsOverProvisioning ()) {
18611859 BigDecimal overProvFactor = getStorageOverProvisioningFactor (pool .getId ());
1860+
18621861 totalOverProvCapacity = overProvFactor .multiply (new BigDecimal (pool .getCapacityBytes ())).longValue ();
1863- s_logger .debug ("Found storage pool " + poolVO .getName () + " of type " + pool .getPoolType ().toString () + " with overprovisioning factor "
1864- + overProvFactor .toString ());
1865- s_logger .debug ("Total over provisioned capacity calculated is " + overProvFactor + " * " + pool .getCapacityBytes ());
1862+
1863+ s_logger .debug ("Found storage pool " + poolVO .getName () + " of type " + pool .getPoolType ().toString () + " with over-provisioning factor " +
1864+ overProvFactor .toString ());
1865+ s_logger .debug ("Total over-provisioned capacity calculated is " + overProvFactor + " * " + pool .getCapacityBytes ());
18661866 } else {
18671867 totalOverProvCapacity = pool .getCapacityBytes ();
1868+
18681869 s_logger .debug ("Found storage pool " + poolVO .getName () + " of type " + pool .getPoolType ().toString ());
18691870 }
18701871
1871- s_logger .debug ("Total capacity of the pool " + poolVO .getName () + " id: " + pool .getId () + " is " + totalOverProvCapacity );
1872+ s_logger .debug ("Total capacity of the pool " + poolVO .getName () + " with ID " + pool .getId () + " is " + totalOverProvCapacity );
1873+
18721874 double storageAllocatedThreshold = CapacityManager .StorageAllocatedCapacityDisableThreshold .valueIn (pool .getDataCenterId ());
1875+
18731876 if (s_logger .isDebugEnabled ()) {
1874- s_logger .debug ("Checking pool: " + pool .getId () + " for volume allocation " + volumes .toString () + ", maxSize : " + totalOverProvCapacity +
1875- ", totalAllocatedSize : " + allocatedSizeWithTemplate + ", askingSize : " + totalAskingSize + ", allocated disable threshold: " +
1876- storageAllocatedThreshold );
1877+ s_logger .debug ("Checking pool with ID " + pool .getId () + " for volume allocation " + volumes .toString () + ", maxSize: " +
1878+ totalOverProvCapacity + ", totalAllocatedSize: " + allocatedSizeWithTemplate + ", askingSize: " + totalAskingSize +
1879+ ", allocated disable threshold: " + storageAllocatedThreshold );
18771880 }
18781881
18791882 double usedPercentage = (allocatedSizeWithTemplate + totalAskingSize ) / (double )(totalOverProvCapacity );
1883+
18801884 if (usedPercentage > storageAllocatedThreshold ) {
18811885 if (s_logger .isDebugEnabled ()) {
1882- s_logger .debug ("Insufficient un-allocated capacity on: " + pool .getId () + " for volume allocation: " + volumes .toString () +
1883- " since its allocated percentage: " + usedPercentage + " has crossed the allocated pool.storage.allocated.capacity.disablethreshold: " +
1886+ s_logger .debug ("Insufficient un-allocated capacity on the pool with ID " + pool .getId () + " for volume allocation: " + volumes .toString () +
1887+ " since its allocated percentage " + usedPercentage + " has crossed the allocated pool.storage.allocated.capacity.disablethreshold " +
18841888 storageAllocatedThreshold + ", skipping this pool" );
18851889 }
1890+
18861891 return false ;
18871892 }
18881893
18891894 if (totalOverProvCapacity < (allocatedSizeWithTemplate + totalAskingSize )) {
18901895 if (s_logger .isDebugEnabled ()) {
1891- s_logger .debug ("Insufficient un-allocated capacity on: " + pool .getId () + " for volume allocation: " + volumes .toString () +
1892- ", not enough storage, maxSize : " + totalOverProvCapacity + ", totalAllocatedSize : " + allocatedSizeWithTemplate + ", askingSize : " +
1896+ s_logger .debug ("Insufficient un-allocated capacity on the pool with ID " + pool .getId () + " for volume allocation: " + volumes .toString () +
1897+ "; not enough storage, maxSize: " + totalOverProvCapacity + ", totalAllocatedSize: " + allocatedSizeWithTemplate + ", askingSize: " +
18931898 totalAskingSize );
18941899 }
1900+
18951901 return false ;
18961902 }
1903+
18971904 return true ;
18981905 }
18991906
1907+ /**
1908+ * Storage plug-ins for managed storage can be designed in such a way as to store a template on the primary storage once and
1909+ * make use of it via storage-side cloning.
1910+ *
1911+ * This method determines how many more bytes it will need for the template (if the template is already stored on the primary storage,
1912+ * then the answer is 0).
1913+ */
1914+ private long getAskingSizeForTemplateBasedOnClusterAndStoragePool (Long templateId , Long clusterId , StoragePoolVO storagePoolVO ) {
1915+ if (templateId == null || clusterId == null || storagePoolVO == null || !storagePoolVO .isManaged ()) {
1916+ return 0 ;
1917+ }
1918+
1919+ VMTemplateVO tmpl = _templateDao .findByIdIncludingRemoved (templateId );
1920+
1921+ if (tmpl == null || ImageFormat .ISO .equals (tmpl .getFormat ())) {
1922+ return 0 ;
1923+ }
1924+
1925+ HypervisorType hypervisorType = tmpl .getHypervisorType ();
1926+
1927+ // The getSupportsResigning method is applicable for XenServer as a UUID-resigning patch may or may not be installed on those hypervisor hosts.
1928+ if (_clusterDao .getSupportsResigning (clusterId ) || HypervisorType .VMware .equals (hypervisorType ) || HypervisorType .KVM .equals (hypervisorType )) {
1929+ return getBytesRequiredForTemplate (tmpl , storagePoolVO );
1930+ }
1931+
1932+ return 0 ;
1933+ }
1934+
19001935 private DiskOfferingVO getDiskOfferingVO (Volume volume ) {
19011936 Long diskOfferingId = volume .getDiskOfferingId ();
19021937
0 commit comments