ofri masad has posted comments on this change. Change subject: core: Quota refactor - QuotaManager ......................................................................
Patch Set 15: (27 inline comments) .................................................... File backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/CommandBase.java Line 640: QuotaConsumptionParametersWrapper quotaConsumptionParametersWrapper = new QuotaConsumptionParametersWrapper(this, Line 641: getReturnValue().getCanDoActionMessages()); Line 642: quotaConsumptionParametersWrapper.setParameters(getQuotaConsumptionParameters()); Line 643: Line 644: return quotaConsumptionParametersWrapper.getParameters().isEmpty() || getQuotaManager().consume(quotaConsumptionParametersWrapper); Done Line 645: } Line 646: Line 647: /** Line 648: * @return true if all parameters class and its inner members passed .................................................... File backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/quota/QuotaManagerAuditLogger.java Line 6: import org.ovirt.engine.core.dal.dbbroker.auditloghandling.AuditLogableBase; Line 7: Line 8: import java.text.DecimalFormat; Line 9: Line 10: public class QuotaManagerAuditLogger { Done Line 11: private final DecimalFormat percentageFormatter = new DecimalFormat("#.##"); Line 12: Line 13: protected void auditLogStorage(AuditLogableBase auditLogableBase, AuditLogType auditLogType, String quotaName, Line 14: double storageUsagePercentage, Line 50: auditLog(auditLogableBase, auditLogType); Line 51: } Line 52: Line 53: protected void auditLog(AuditLogableBase auditLogableBase, AuditLogType auditLogType) { Line 54: if (auditLogType != null) { Done Line 55: AuditLogDirector.log(auditLogableBase, auditLogType); Line 56: } Line 57: } Line 58: .................................................... File backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/quota/QuotaManager.java Line 31: private final static QuotaManager INSTANCE = new QuotaManager(); Line 32: private final static ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); Line 33: private final static Log log = LogFactory.getLog(QuotaManager.class); Line 34: private final static DecimalFormat percentageFormatter = new DecimalFormat("#.##"); Line 35: private static QuotaManagerAuditLogger quotaManagerAuditLogger = new QuotaManagerAuditLogger(); QuotaManagerAuditLogger is not final and have setter in order to allow mock inject in the test. I'll add a comment here and on line 43 Line 36: private final ConcurrentHashMap<Guid, Map<Guid, Quota>> storagePoolQuotaMap = Line 37: new ConcurrentHashMap<Guid, Map<Guid, Quota>>(); Line 38: private final ConcurrentMap<Guid, Quota> directQuotaMap = new ConcurrentHashMap<Guid, Quota>(); Line 39: Line 39: Line 40: public static QuotaManager getInstance() { Line 41: return INSTANCE; Line 42: } Line 43: Done Line 44: public static QuotaManagerAuditLogger getQuotaManagerAuditLogger() { Line 45: return quotaManagerAuditLogger; Line 46: } Line 47: Line 331: } Line 332: } Line 333: Line 334: private boolean validateAndSetStorageQuotaHelper(QuotaConsumptionParametersWrapper parameters) { Line 335: lock.readLock().lock(); I'm editing an object from the map and not the map itself. to avoid data corruption of the object itself - synchronized is used. Line 336: try { Line 337: synchronized (storagePoolQuotaMap.get(parameters.getAuditLogable().getStoragePool().getId())) { Line 338: if (storagePoolQuotaMap.get(parameters.getAuditLogable().getStoragePool().getId()) == null) { Line 339: return false; Line 332: } Line 333: Line 334: private boolean validateAndSetStorageQuotaHelper(QuotaConsumptionParametersWrapper parameters) { Line 335: lock.readLock().lock(); Line 336: try { Done Line 337: synchronized (storagePoolQuotaMap.get(parameters.getAuditLogable().getStoragePool().getId())) { Line 338: if (storagePoolQuotaMap.get(parameters.getAuditLogable().getStoragePool().getId()) == null) { Line 339: return false; Line 340: } Line 333: Line 334: private boolean validateAndSetStorageQuotaHelper(QuotaConsumptionParametersWrapper parameters) { Line 335: lock.readLock().lock(); Line 336: try { Line 337: synchronized (storagePoolQuotaMap.get(parameters.getAuditLogable().getStoragePool().getId())) { Done Line 338: if (storagePoolQuotaMap.get(parameters.getAuditLogable().getStoragePool().getId()) == null) { Line 339: return false; Line 340: } Line 341: Map<Guid, Quota> quotaMap = storagePoolQuotaMap.get(parameters.getAuditLogable().getStoragePool().getId()); Line 334: private boolean validateAndSetStorageQuotaHelper(QuotaConsumptionParametersWrapper parameters) { Line 335: lock.readLock().lock(); Line 336: try { Line 337: synchronized (storagePoolQuotaMap.get(parameters.getAuditLogable().getStoragePool().getId())) { Line 338: if (storagePoolQuotaMap.get(parameters.getAuditLogable().getStoragePool().getId()) == null) { Done Line 339: return false; Line 340: } Line 341: Map<Guid, Quota> quotaMap = storagePoolQuotaMap.get(parameters.getAuditLogable().getStoragePool().getId()); Line 342: Map<Guid, Map<Guid, Double>> desiredStorageSizeQuotaMap = new HashMap<Guid, Map<Guid, Double>>(); Line 337: synchronized (storagePoolQuotaMap.get(parameters.getAuditLogable().getStoragePool().getId())) { Line 338: if (storagePoolQuotaMap.get(parameters.getAuditLogable().getStoragePool().getId()) == null) { Line 339: return false; Line 340: } Line 341: Map<Guid, Quota> quotaMap = storagePoolQuotaMap.get(parameters.getAuditLogable().getStoragePool().getId()); Done Line 342: Map<Guid, Map<Guid, Double>> desiredStorageSizeQuotaMap = new HashMap<Guid, Map<Guid, Double>>(); Line 343: Line 344: Map<Guid, Double> newUsedGlobalStorageSize = new HashMap<Guid, Double>(); Line 345: Map<Guid, Map<Guid, Double>> newUsedSpecificStorageSize = new HashMap<Guid, Map<Guid, Double>>(); Line 346: Line 347: generateDesiredStorageSizeQuotaMap(parameters, desiredStorageSizeQuotaMap); Line 348: Line 349: for (Guid quotaId : desiredStorageSizeQuotaMap.keySet()) { Line 350: Quota quota = quotaMap.get(quotaId); quotaId is taken from desiredStorageSizeQuotaMap.keySet() while Quota is taken from quotaMap.valueSet(). (not same Map) Line 351: if (quota.getGlobalQuotaStorage() != null) { Line 352: if (checkConsumptionForGlobalStorageQuota(parameters, Line 353: desiredStorageSizeQuotaMap, Line 354: newUsedGlobalStorageSize, Line 408: } Line 409: if (!hasStorageId) { Line 410: parameters.getCanDoActionMessages() Line 411: .add(VdcBllMessages.ACTION_TYPE_FAILED_NO_QUOTA_SET_FOR_DOMAIN.toString()); Line 412: return true; Done Line 413: } Line 414: } Line 415: return false; Line 416: } Line 436: quota.getGlobalQuotaStorage().getStorageSizeGB(), Line 437: storageUsagePercentage, storageRequestPercentage, Line 438: parameters.getCanDoActionMessages(), Line 439: parameters.getAuditLogable())) { Line 440: return true; Done Line 441: } Line 442: newUsedGlobalStorageSize.put(quotaId, sum Line 443: + quota.getGlobalQuotaStorage().getStorageSizeGBUsage()); Line 444: } Line 565: double storageRequestPercentage, Line 566: List<String> canDoActionMessages, Line 567: AuditLogableBase auditLogableBase) { Line 568: double storageTotalPercentage = storageUsagePercentage + storageRequestPercentage; Line 569: Done Line 570: if (limit == QuotaStorage.UNLIMITED || storageTotalPercentage <= quota.getThresholdStoragePercentage()) { Line 571: return true; Line 572: } else if (storageTotalPercentage <= 100) { Line 573: quotaManagerAuditLogger.auditLogStorage(auditLogableBase, Line 582: storageUsagePercentage + storageRequestPercentage, Line 583: storageRequestPercentage); Line 584: } else { Line 585: quotaManagerAuditLogger.auditLogStorage(auditLogableBase, Line 586: AuditLogType.USER_EXCEEDED_QUOTA_STORAGE_GRACE_LIMIT, Done Line 587: quota.getQuotaName(), Line 588: storageUsagePercentage, Line 589: storageRequestPercentage); Line 590: if (QuotaEnforcementTypeEnum.HARD_ENFORCEMENT.equals(quotaEnforcementTypeEnum)) { Line 693: int newVcpu = vcpuToAdd + quotaVdsGroup.getVirtualCpuUsage(); Line 694: Line 695: long memLimit = quotaVdsGroup.getMemSizeMB(); Line 696: int cpuLimit = quotaVdsGroup.getVirtualCpu(); Line 697: Done Line 698: if (memLimit == QuotaVdsGroup.UNLIMITED_MEM && cpuLimit == QuotaVdsGroup.UNLIMITED_VCPU) { // if both cpu and Line 699: // mem are unlimited Line 700: // cache Line 701: cacheNewValues(quotaVdsGroup, newMemory, newVcpu); Line 823: } Line 824: Line 825: } Line 826: Line 827: public boolean validateAndSetClusterQuota(QuotaConsumptionParametersWrapper parameters) { Done Line 828: List<QuotaVdsGroupConsumptionParameter> vdsGroupConsumptionParameters = Line 829: filterQuotaVdsGroupConsumptionParameter(parameters.getParameters()); Line 830: synchronized (storagePoolQuotaMap.get(parameters.getAuditLogable().getStoragePool().getId())) { Line 831: for (QuotaVdsGroupConsumptionParameter parameter : vdsGroupConsumptionParameters) { Line 826: Line 827: public boolean validateAndSetClusterQuota(QuotaConsumptionParametersWrapper parameters) { Line 828: List<QuotaVdsGroupConsumptionParameter> vdsGroupConsumptionParameters = Line 829: filterQuotaVdsGroupConsumptionParameter(parameters.getParameters()); Line 830: synchronized (storagePoolQuotaMap.get(parameters.getAuditLogable().getStoragePool().getId())) { Done Line 831: for (QuotaVdsGroupConsumptionParameter parameter : vdsGroupConsumptionParameters) { Line 832: Quota quota = parameter.getQuota(); Line 833: QuotaVdsGroup quotaVdsGroup = null; Line 834: Line 1038: * @return - true if the request was validated and set Line 1039: */ Line 1040: public boolean consume(QuotaConsumptionParametersWrapper parameters) { Line 1041: if (!validateAndCompleteParameters(parameters)) { Line 1042: throw new InvalidQuotaParametersException(); Done Line 1043: } Line 1044: Line 1045: return internalConsumeAndReleaseHandler(parameters); Line 1046: } Line 1116: * - Quota consumption parameters Line 1117: */ Line 1118: Line 1119: private boolean validateAndCompleteParameters(QuotaConsumptionParametersWrapper parameters) { Line 1120: Done Line 1121: if (QuotaEnforcementTypeEnum.DISABLED.equals(parameters.getAuditLogable().getStoragePool().getQuotaEnforcementType())) { Line 1122: return true; Line 1123: } Line 1124: Line 1127: Line 1128: // for each parameter - check and complete Line 1129: for (QuotaConsumptionParameter param : parameters.getParameters()) { Line 1130: // check that quota id is valid and fetch the quota from db (or cache). add the quota to the param Line 1131: boolean validQuotaId = checkAndFetchQuota(parameters, param); Done Line 1132: Line 1133: // In case this param is a QuotaVdsConsumptionParameter - check that it has a valid Line 1134: // vds group id which is handled by this quota Line 1135: boolean validVdsGroup = true; Line 1181: return true; Line 1182: } Line 1183: Line 1184: // In case this param is a QuotaVdsConsumptionParameter - check that it has a valid Line 1185: // vds group id which is handled by this quota Done Line 1186: private boolean checkVdsGroupMatchQuota(QuotaConsumptionParametersWrapper parameters, QuotaConsumptionParameter param) { Line 1187: Quota quota = param.getQuota(); Line 1188: QuotaVdsGroupConsumptionParameter paramVds = (QuotaVdsGroupConsumptionParameter) param; Line 1189: Line 1185: // vds group id which is handled by this quota Line 1186: private boolean checkVdsGroupMatchQuota(QuotaConsumptionParametersWrapper parameters, QuotaConsumptionParameter param) { Line 1187: Quota quota = param.getQuota(); Line 1188: QuotaVdsGroupConsumptionParameter paramVds = (QuotaVdsGroupConsumptionParameter) param; Line 1189: The parameters are passed from the Command. the getVdsGroupConsumptionParameters() method is implemented by the command and thus getVdsGroupId() can be null. Line 1190: if (paramVds.getVdsGroupId() == null) { Line 1191: parameters.getCanDoActionMessages().add(VdcBllMessages.ACTION_TYPE_FAILED_QUOTA_IS_NOT_VALID.toString()); Line 1192: log.errorFormat("Quota Vds parameters from command: {0} are missing vds group id", Line 1193: parameters.getAuditLogable().getClass().getName()); Line 1218: // storage domain id which is handled by this quota Line 1219: private boolean checkStoragePoolMatchQuota(QuotaConsumptionParametersWrapper parameters, QuotaConsumptionParameter param) { Line 1220: Quota quota = param.getQuota(); Line 1221: QuotaStorageConsumptionParameter paramstorage = (QuotaStorageConsumptionParameter) param; Line 1222: The parameters are passed from the Command. the getStorageConsumptionParameters() method is implemented by the command and thus getStorageDomainId() can be null. Line 1223: if (paramstorage.getStorageDomainId() == null) { Line 1224: parameters.getCanDoActionMessages().add(VdcBllMessages.ACTION_TYPE_FAILED_QUOTA_IS_NOT_VALID.toString()); Line 1225: log.errorFormat("Quota storage parameters from command: {0} are missing storage domain id", Line 1226: parameters.getAuditLogable().getClass().getName()); Line 1252: * @param quotaId - quota id Line 1253: * @return - found quota. null if not found. Line 1254: */ Line 1255: private Quota fetchQuotaFromDB(Guid quotaId) { Line 1256: // if the id is valid Done Line 1257: if (quotaId != null && quotaId != Guid.Empty) { Line 1258: if (!directQuotaMap.containsKey(quotaId)) { Line 1259: // cache in direct quota map Line 1260: Quota quota = getQuotaDAO().getById(quotaId); Line 1253: * @return - found quota. null if not found. Line 1254: */ Line 1255: private Quota fetchQuotaFromDB(Guid quotaId) { Line 1256: // if the id is valid Line 1257: if (quotaId != null && quotaId != Guid.Empty) { Done Line 1258: if (!directQuotaMap.containsKey(quotaId)) { Line 1259: // cache in direct quota map Line 1260: Quota quota = getQuotaDAO().getById(quotaId); Line 1261: if (quota == null) { Line 1264: } Line 1265: lock.readLock().lock(); Line 1266: try { Line 1267: directQuotaMap.put(quotaId, quota); Line 1268: // cache in storage-pool->quota map Done. added a warning about locks in the documentation Line 1269: storagePoolQuotaMap.putIfAbsent(quota.getStoragePoolId(), new HashMap<Guid, Quota>()); Line 1270: storagePoolQuotaMap.get(quota.getStoragePoolId()).put(quotaId, quota); Line 1271: } finally { Line 1272: lock.readLock().unlock(); -- To view, visit http://gerrit.ovirt.org/8776 To unsubscribe, visit http://gerrit.ovirt.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Ibb100467a55b26e4219d1a2562da86b81ffdc032 Gerrit-PatchSet: 15 Gerrit-Project: ovirt-engine Gerrit-Branch: master Gerrit-Owner: ofri masad <oma...@redhat.com> Gerrit-Reviewer: Allon Mureinik <amure...@redhat.com> Gerrit-Reviewer: Doron Fediuck <dfedi...@redhat.com> Gerrit-Reviewer: Gilad Chaplik <gchap...@redhat.com> Gerrit-Reviewer: Laszlo Hornyak <lhorn...@redhat.com> Gerrit-Reviewer: Michael Kublin <mkub...@redhat.com> Gerrit-Reviewer: Sharad Mishra <snmis...@linux.vnet.ibm.com> Gerrit-Reviewer: Yair Zaslavsky <yzasl...@redhat.com> Gerrit-Reviewer: ofri masad <oma...@redhat.com> _______________________________________________ Engine-patches mailing list Engine-patches@ovirt.org http://lists.ovirt.org/mailman/listinfo/engine-patches