ofri masad has uploaded a new change for review.

Change subject: core: Quota refactor - QuotaManager step 3
......................................................................

core: Quota refactor - QuotaManager step 3

Refactor ValidateAndSetStorageQuota

Change-Id: Ic771fa422d745e9ace3970df931d3b65ca2706e0
Signed-off-by: Ofri Masad <[email protected]>
---
M 
backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/quota/QuotaManager.java
M 
backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/quota/QuotaManagerAuditLogger.java
2 files changed, 226 insertions(+), 11 deletions(-)


  git pull ssh://gerrit.ovirt.org:29418/ovirt-engine refs/changes/78/8778/1

diff --git 
a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/quota/QuotaManager.java
 
b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/quota/QuotaManager.java
index b088be3..08ce434 100644
--- 
a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/quota/QuotaManager.java
+++ 
b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/quota/QuotaManager.java
@@ -322,6 +322,168 @@
         }
     }
 
+    private boolean 
validateAndSetStorageQuotaHelper(QuotaConsumptionParameters parameters) {
+        lock.readLock().lock();
+        try {
+            synchronized 
(storagePoolQuotaMap.get(parameters.getStoragePoolGuid())) {
+                if (storagePoolQuotaMap.get(parameters.getStoragePoolGuid()) 
== null) {
+                    return false;
+                }
+                Map<Guid, Quota> quotaMap = 
storagePoolQuotaMap.get(parameters.getStoragePoolGuid());
+                Map<Guid, Map<Guid, Double>> desiredStorageSizeQuotaMap = new 
HashMap<Guid, Map<Guid, Double>>();
+
+                Map<Guid, Double> newUsedGlobalStorageSize = new HashMap<Guid, 
Double>();
+                Map<Guid, Map<Guid, Double>> newUsedSpecificStorageSize = new 
HashMap<Guid, Map<Guid, Double>>();
+
+                generateDesiredStorageSizeQuotaMap(parameters, 
desiredStorageSizeQuotaMap);
+
+                for (Guid quotaId : desiredStorageSizeQuotaMap.keySet()) {
+                    Quota quota = quotaMap.get(quotaId);
+                    if (quota.getGlobalQuotaStorage() != null) {
+                        if (checkConsumptionForGlobalStorageQuota(parameters,
+                                desiredStorageSizeQuotaMap,
+                                newUsedGlobalStorageSize,
+                                quotaId,
+                                quota))
+                            return false;
+                    } else {
+                        if (checkConsumptionForSpecificSorageQuota(parameters,
+                                desiredStorageSizeQuotaMap,
+                                newUsedSpecificStorageSize,
+                                quotaId,
+                                quota))
+                            return false;
+                    }
+                }
+                saveNewConsumptionValues(quotaMap, newUsedGlobalStorageSize, 
newUsedSpecificStorageSize);
+
+            }
+            return true;
+        } finally {
+            lock.readLock().unlock();
+        }
+    }
+
+    private boolean 
checkConsumptionForSpecificSorageQuota(QuotaConsumptionParameters parameters,
+            Map<Guid, Map<Guid, Double>> desiredStorageSizeQuotaMap,
+            Map<Guid, Map<Guid, Double>> newUsedSpecificStorageSize,
+            Guid quotaId,
+            Quota quota) {
+        newUsedSpecificStorageSize.put(quotaId, new HashMap<Guid, Double>());
+        for (Guid storageId : 
desiredStorageSizeQuotaMap.get(quotaId).keySet()) {
+            boolean hasStorageId = false;
+            for (QuotaStorage quotaStorage : quota.getQuotaStorages()) {
+                if (quotaStorage.getStorageId().equals(storageId)) {
+                    hasStorageId = true;
+                    if (quotaStorage.getStorageSizeGB() != 
QuotaStorage.UNLIMITED) {
+                        double storageUsagePercentage = 
quotaStorage.getStorageSizeGBUsage()
+                                / quotaStorage.getStorageSizeGB() * 100;
+                        double storageRequestPercentage =
+                                desiredStorageSizeQuotaMap.get(quotaId)
+                                        .get(storageId)
+                                        / quotaStorage.getStorageSizeGB() * 
100;
+
+                        if 
(!checkQuotaStorageLimits(parameters.getStorage_pool().getQuotaEnforcementType(),
+                                quota,
+                                quotaStorage.getStorageSizeGB(),
+                                storageUsagePercentage, 
storageRequestPercentage,
+                                parameters.getCanDoActionMessages(),
+                                parameters.getAuditLogable())) {
+                            return true;
+                        }
+                        newUsedSpecificStorageSize.get(quotaId).put(storageId,
+                                quotaStorage.getStorageSizeGBUsage()
+                                        + 
desiredStorageSizeQuotaMap.get(quotaId).get(storageId));
+                    }
+                }
+            }
+            if (!hasStorageId) {
+                parameters.getCanDoActionMessages()
+                        
.add(VdcBllMessages.ACTION_TYPE_FAILED_NO_QUOTA_SET_FOR_DOMAIN.toString());
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private boolean 
checkConsumptionForGlobalStorageQuota(QuotaConsumptionParameters parameters,
+            Map<Guid, Map<Guid, Double>> desiredStorageSizeQuotaMap,
+            Map<Guid, Double> newUsedGlobalStorageSize,
+            Guid quotaId,
+            Quota quota) {
+        if (quota.getGlobalQuotaStorage().getStorageSizeGB() != 
QuotaStorage.UNLIMITED) {
+            double sum = 0.0;
+            for (Double size : 
desiredStorageSizeQuotaMap.get(quotaId).values()) {
+                sum += size;
+            }
+
+            double storageUsagePercentage = 
quota.getGlobalQuotaStorage().getStorageSizeGBUsage()
+                    / quota.getGlobalQuotaStorage().getStorageSizeGB() * 100;
+            double storageRequestPercentage = sum
+                    / quota.getGlobalQuotaStorage().getStorageSizeGB() * 100;
+
+            if 
(!checkQuotaStorageLimits(parameters.getStorage_pool().getQuotaEnforcementType(),
+                    quota,
+                    quota.getGlobalQuotaStorage().getStorageSizeGB(),
+                    storageUsagePercentage, storageRequestPercentage,
+                    parameters.getCanDoActionMessages(),
+                    parameters.getAuditLogable())) {
+                return true;
+            }
+            newUsedGlobalStorageSize.put(quotaId, sum
+                    + quota.getGlobalQuotaStorage().getStorageSizeGBUsage());
+        }
+        return false;
+    }
+
+    private void saveNewConsumptionValues(Map<Guid, Quota> quotaMap,
+            Map<Guid, Double> newUsedGlobalStorageSize,
+            Map<Guid, Map<Guid, Double>> newUsedSpecificStorageSize) {
+        // cache new storage size.
+        for (Guid quotaId : newUsedGlobalStorageSize.keySet()) {
+            Quota quota = quotaMap.get(quotaId);
+            double value = newUsedGlobalStorageSize.get(quotaId);
+            if (value < 0) {
+                log.errorFormat("Quota id {0} cached storage size is negative, 
removing from cache", quotaId);
+                quotaMap.remove(quotaId);
+                continue;
+            }
+            quota.getGlobalQuotaStorage().setStorageSizeGBUsage(value);
+        }
+        for (Guid quotaId : newUsedSpecificStorageSize.keySet()) {
+            Quota quota = quotaMap.get(quotaId);
+            for (QuotaStorage quotaStorage : quota.getQuotaStorages()) {
+                if 
(newUsedSpecificStorageSize.get(quotaId).containsKey(quotaStorage.getStorageId()))
 {
+                    double value = newUsedSpecificStorageSize.get(quotaId)
+                            .get(quotaStorage.getStorageId());
+                    if (value < 0) {
+                        log.errorFormat("Quota id {0} cached storage size is 
negative, removing from cache",
+                                quotaId);
+                        quotaMap.remove(quotaId);
+                        continue;
+                    }
+                    quotaStorage.setStorageSizeGBUsage(value);
+                }
+            }
+        }
+    }
+
+    private void generateDesiredStorageSizeQuotaMap(QuotaConsumptionParameters 
parameters,
+            Map<Guid, Map<Guid, Double>> desiredStorageSizeQuotaMap) {
+        for (QuotaStorageConsumptionParameter param : 
parameters.getQuotaStorageConsumptionParameters()) {
+            if (!desiredStorageSizeQuotaMap.containsKey(param.getQuotaGuid())) 
{
+                desiredStorageSizeQuotaMap.put(param.getQuotaGuid(), new 
HashMap<Guid, Double>());
+            }
+            Map<Guid, Double> quotaStorageMap = 
desiredStorageSizeQuotaMap.get(param.getQuotaGuid());
+            if (!quotaStorageMap.containsKey(param.getStorageDomainId())) {
+                quotaStorageMap.put(param.getStorageDomainId(), 0.0);
+            }
+            quotaStorageMap.put(param.getStorageDomainId(), 
quotaStorageMap.get(param.getStorageDomainId())
+                    + param.getRequestedStorageGB());
+
+        }
+    }
+
     /**
      * This method is protected for testing use only
      */
@@ -362,6 +524,43 @@
                 return false;
             }
         }
+        return true;
+    }
+
+    private boolean checkQuotaStorageLimits(QuotaEnforcementTypeEnum 
quotaEnforcementTypeEnum,
+            Quota quota,
+            double limit,
+            double storageUsagePercentage,
+            double storageRequestPercentage,
+            ArrayList<String> canDoActionMessages,
+            AuditLogableBase auditLogableBase) {
+        double storageTotalPercentage = storageUsagePercentage + 
storageRequestPercentage;
+
+        if (limit == QuotaStorage.UNLIMITED || storageTotalPercentage <= 
quota.getThresholdStoragePercentage()) {
+            return true;
+        } else if (storageTotalPercentage <= 100) {
+            AUDIT_LOGGER.auditLogStorage(auditLogableBase,
+                    AuditLogType.USER_EXCEEDED_QUOTA_STORAGE_THRESHOLD,
+                    quota.getQuotaName(),
+                    storageUsagePercentage + storageRequestPercentage,
+                    storageRequestPercentage);
+        } else if (storageTotalPercentage <= quota.getGraceStoragePercentage() 
+ 100) {
+            AUDIT_LOGGER.auditLogStorage(auditLogableBase,
+                    AuditLogType.USER_EXCEEDED_QUOTA_STORAGE_LIMIT,
+                    quota.getQuotaName(),
+                    storageUsagePercentage + storageRequestPercentage,
+                    storageRequestPercentage);
+        } else {
+            AUDIT_LOGGER.auditLogStorage(auditLogableBase,
+                    AuditLogType.USER_EXCEEDED_QUOTA_STORAGE_GRACE_LIMIT,
+                    quota.getQuotaName(),
+                    storageUsagePercentage,
+                    storageRequestPercentage);
+            if 
(QuotaEnforcementTypeEnum.HARD_ENFORCEMENT.equals(quotaEnforcementTypeEnum)) {
+                
canDoActionMessages.add(VdcBllMessages.ACTION_TYPE_FAILED_QUOTA_STORAGE_LIMIT_EXCEEDED.toString());
+                return false;
+            }
+    }
         return true;
     }
 
@@ -622,7 +821,7 @@
 
     /**
      * Check if the quota exceeded the storage limit (ether for global limit 
or one of the specific limits).
-     * 
+     *
      * @param quotaId
      *            - quota id
      * @return - true if the quota exceeded the storage limitation. false if 
quota was not found, limit was not defined
@@ -661,10 +860,10 @@
      * This will create a new storage_pool object and set its ID and 
QuotaEnforcementType. If the quota was located in
      * the DB these values will be taken from the quota. If not these values 
will be set ID=Guid.Empty,
      * QuotaEnforcementType=DISABLED.
-     * 
+     *
      * Notice: The storage_pool object is not the full object obtained from DB 
but only a synthetic object to hold this
      * two fields.
-     * 
+     *
      * @param quotaId
      *            - the id of the quota to locate in DB
      * @return - the new synthetic storage_pool
@@ -685,7 +884,7 @@
 
     /**
      * Consume from quota according to the parameters.
-     * 
+     *
      * @param parameters
      *            - Quota consumption parameters
      * @return - true if the request was validated and set
@@ -701,7 +900,7 @@
     /**
      * Release quota according to the parameters. No need to revert the 
numbers of the request. for example: in order to
      * release 8GB - enter 8 in the requestedStorageGB field
-     * 
+     *
      * @param parameters
      *            - Quota consumption parameters
      */
@@ -717,20 +916,37 @@
     /**
      * This is the start point for all quota consumption and release. This 
method is called after the parameters were
      * validated and competed, and the cache was updated to support all the 
requests in the parameters.
-     * 
+     *
      * @param parameters
      *            - Quota consumption parameters
      * @return - true if the request was validated and set
      */
     private boolean 
internalConsumeAndReleaseHandler(QuotaConsumptionParameters parameters) {
+        boolean needRollBack = false;
 
-        // TODO
-        return true;
+        boolean result = validateAndSetStorageQuotaHelper(parameters);
+        if (result) {
+            //TODO  result = validate and set for vds
+            if (result) {
+                return true;
+            } else {
+                QuotaConsumptionParameters revertedParams = 
revertParametersQuantities(parameters);
+                validateAndSetStorageQuotaHelper(revertedParams);
+                //TODO validate and set for vds
+            }
+        } else {
+            //roll back storage request
+            QuotaConsumptionParameters revertedParams = 
revertParametersQuantities(parameters);
+            validateAndSetStorageQuotaHelper(revertedParams);
+        }
+
+
+        return result;
     }
 
     /**
      * Revert the quantities of the storage, cpu and mem So that a request for 
5GB storage is reverted to (-5)GB request
-     * 
+     *
      * @param parameters
      *            the consumption properties. This object would not be mutated.
      * @return new QuotaConsumptionParameters object with reverted quantities,
@@ -744,7 +960,7 @@
     /**
      * Validate parameters. Look for null pointers and missing data Complete 
the missing data in the parameters from DB
      * and cache all the needed entities.
-     * 
+     *
      * @param parameters
      *            - Quota consumption parameters
      */
diff --git 
a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/quota/QuotaManagerAuditLogger.java
 
b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/quota/QuotaManagerAuditLogger.java
index 8aa2434..413291e 100644
--- 
a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/quota/QuotaManagerAuditLogger.java
+++ 
b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/quota/QuotaManagerAuditLogger.java
@@ -4,7 +4,6 @@
 import org.ovirt.engine.core.common.AuditLogType;
 import org.ovirt.engine.core.dal.dbbroker.auditloghandling.AuditLogDirector;
 import org.ovirt.engine.core.dal.dbbroker.auditloghandling.AuditLogableBase;
-import org.ovirt.engine.core.utils.Pair;
 
 import java.text.DecimalFormat;
 


--
To view, visit http://gerrit.ovirt.org/8778
To unsubscribe, visit http://gerrit.ovirt.org/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: Ic771fa422d745e9ace3970df931d3b65ca2706e0
Gerrit-PatchSet: 1
Gerrit-Project: ovirt-engine
Gerrit-Branch: master
Gerrit-Owner: ofri masad <[email protected]>
_______________________________________________
Engine-patches mailing list
[email protected]
http://lists.ovirt.org/mailman/listinfo/engine-patches

Reply via email to