private void logCapacityChange() { if (logger.isTraceEnabled()) { StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace(); int index = 0; String fileName = BackupStorageCapacityUpdater.class.getSimpleName() + ".java"; for (int i=0; i<stackTraceElements.length; i++) { if (fileName.equals(stackTraceElements[i].getFileName())) { index = i; } } StackTraceElement caller = stackTraceElements[index+1]; logger.trace(String.format("[Backup Storage Capacity] %s:%s:%s changed the capacity of the backup storage[uuid:%s] as:\n" + "total: %s --> %s\n" + "available: %s --> %s\n" , caller.getFileName(), caller.getMethodName(), caller.getLineNumber(), capacityVO.getUuid(), totalForLog, capacityVO.getTotalCapacity(), availForLog, capacityVO.getAvailableCapacity())); } }
@Transactional private boolean reserve(String bsUuid, long size) { BackupStorageVO vo = dbf.getEntityManager().find(BackupStorageVO.class, bsUuid, LockModeType.PESSIMISTIC_WRITE); if (vo == null) { logger.warn(String.format("reservation failure, cannot find backup storage[uuid:%s]", bsUuid)); return false; } if (vo.getAvailableCapacity() < size) { logger.warn(String.format("reservation failure, cannot reserve capacity[%s bytes] on backup storage[uuid:%s]", size, bsUuid)); return false; } long avail = vo.getAvailableCapacity() - size; vo.setAvailableCapacity(avail); dbf.getEntityManager().merge(vo); logger.debug(String.format("reserve %s bytes on backup storage[uuid:%s, total capacity:%s, available capacity:%s]", size, bsUuid, vo.getTotalCapacity(), avail)); return true; }
@Transactional private boolean _reserveCapacity(long size, boolean exceptionOnFailure) { if (!lockCapacity()) { logDeletedBackupStorage(); return false; } if (capacityVO.getAvailableCapacity() < size) { if (!exceptionOnFailure) { return false; } else { throw new OperationFailureException(operr("cannot reserve %s on the backup storage[uuid:%s], it only has %s available", size, backupStorageUuid, capacityVO.getAvailableCapacity())); } } return _decreaseAvailableCapacity(size); }
private boolean lockCapacity() { if (backupStorageUuid != null) { capacityVO = dbf.getEntityManager().find(BackupStorageVO.class, backupStorageUuid, LockModeType.PESSIMISTIC_WRITE); } if (capacityVO != null) { totalForLog = capacityVO.getTotalCapacity(); availForLog = capacityVO.getAvailableCapacity(); originalCopy = new BackupStorageVO(); originalCopy.setAvailableCapacity(capacityVO.getAvailableCapacity()); originalCopy.setTotalCapacity(capacityVO.getTotalCapacity()); } return capacityVO != null; }
@Transactional private boolean _decreaseAvailableCapacity(long size) { if (!lockCapacity()) { logDeletedBackupStorage(); return false; } capacityVO.setAvailableCapacity(capacityVO.getAvailableCapacity() - size); merge(); return true; }
protected void exceptionIfImageSizeGreaterThanAvailableCapacity(String url) { if (CoreGlobalProperty.UNIT_TEST_ON) { return; } url = url.trim(); if (!url.startsWith("http") && !url.startsWith("https")) { return; } String len; try { HttpHeaders header = restf.getRESTTemplate().headForHeaders(URI.create(url)); len = header.getFirst("Content-Length"); } catch (Exception e) { throw new OperationFailureException(operr("cannot get image. The image url is %s. Exception is %s", url, e.toString())); } if (len == null) { return; } long size = Long.valueOf(len); if (size > self.getAvailableCapacity()) { throw new OperationFailureException(operr("the backup storage[uuid:%s, name:%s] has not enough capacity to download the image[%s]." + "Required size:%s, available size:%s", self.getUuid(), self.getName(), url, size, self.getAvailableCapacity())); } }
@Override @Transactional(readOnly = true) public void run(FlowTrigger trigger, Map data) { BackupStorageAllocationSpec spec = (BackupStorageAllocationSpec) data.get(AllocatorParams.SPEC); List<BackupStorageVO> candidates = (List<BackupStorageVO>) data.get(AllocatorParams.CANDIDATES); DebugUtils.Assert(candidates != null && !candidates.isEmpty(), "BackupStorageReservedCapacityAllocatorFlow cannot be the first element in the allocator chain"); List<BackupStorageVO> ret = new ArrayList<BackupStorageVO>(); long reservedCapacity = SizeUtils.sizeStringToBytes(BackupStorageGlobalConfig.RESERVED_CAPACITY.value()); for (BackupStorageVO vo : candidates) { if (vo.getAvailableCapacity() - reservedCapacity > spec.getSize()) { ret.add(vo); } } if (ret.isEmpty()) { throw new OperationFailureException(operr("after subtracting reserved capacity[%s], no backup storage has required capacity[%s bytes]", BackupStorageGlobalConfig.RESERVED_CAPACITY.value(), spec.getSize())); } data.put(AllocatorParams.CANDIDATES, ret); trigger.next(); } }
@Transactional private void handle(ReturnBackupStorageMsg msg) { self = dbf.getEntityManager().find(BackupStorageVO.class, self.getUuid(), LockModeType.PESSIMISTIC_WRITE); long availSize = self.getAvailableCapacity() + msg.getSize(); if (availSize > self.getTotalCapacity()) { availSize = self.getTotalCapacity(); } self.setAvailableCapacity(availSize); dbf.getEntityManager().merge(self); bus.reply(msg, new ReturnBackupStorageReply()); }
@Transactional private boolean _increaseAvailableCapacity(long size) { if (!lockCapacity()) { logDeletedBackupStorage(); return false; } long n = capacityVO.getAvailableCapacity() + size; if (n > capacityVO.getTotalCapacity()) { throw new CloudRuntimeException(String.format("invalid backup storage[uuid:%s] capacity, available capacity[%s] > total capacity[%s]", capacityVO.getUuid(), n, capacityVO.getTotalCapacity())); } capacityVO.setAvailableCapacity(n); merge(); return true; }
@Transactional private boolean _run(BackupStorageCapacityUpdaterRunnable runnable) { if (!lockCapacity()) { logDeletedBackupStorage(); return false; } BackupStorageCapacity cap = new BackupStorageCapacity(); cap.setUuid(capacityVO.getUuid()); cap.setAvailableCapacity(capacityVO.getAvailableCapacity()); cap.setTotalCapacity(capacityVO.getTotalCapacity()); cap = runnable.call(cap); if (cap != null) { capacityVO.setTotalCapacity(cap.getTotalCapacity()); capacityVO.setAvailableCapacity(cap.getAvailableCapacity()); merge(); return true; } return false; }
protected BackupStorageInventory(BackupStorageVO vo) { this.setCreateDate(vo.getCreateDate()); this.setDescription(vo.getDescription()); this.setLastOpDate(vo.getLastOpDate()); this.setName(vo.getName()); this.setState(vo.getState().toString()); this.setStatus(vo.getStatus().toString()); this.setTotalCapacity(vo.getTotalCapacity()); this.setAvailableCapacity(vo.getAvailableCapacity()); this.setType(vo.getType()); this.setUrl(vo.getUrl()); this.setUuid(vo.getUuid()); this.attachedZoneUuids = new ArrayList<String>(vo.getAttachedZoneRefs().size()); for (BackupStorageZoneRefVO ref : vo.getAttachedZoneRefs()) { if (!this.attachedZoneUuids.contains(ref.getZoneUuid())) { this.attachedZoneUuids.add(ref.getZoneUuid()); } } }
@Override public void run(MessageReply reply) { if (reply.isSuccess()) { BackupStorageVO srcBS = dbf.findByUuid(self.getUuid(), BackupStorageVO.class); srcBS.setAvailableCapacity(srcBS.getAvailableCapacity() + spec.getSize()); dbf.update(srcBS); logger.info(String.format("Deleted image %s and returned space[size:%s] to BS[uuid:%s] after image migration", spec.getInstallPath(), spec.getSize(), self.getUuid())); trash.removeFromDb(spec.getTrashId()); result.setSize(spec.getSize()); result.setResourceUuids(CollectionDSL.list(spec.getResourceUuid())); completion.success(result); } else { logger.warn(String.format("Failed to delete image %s in image migration.", spec.getInstallPath())); completion.fail(reply.getError()); } } });
protected BackupStorageVO(BackupStorageVO vo) { this.setUuid(vo.getUuid()); this.setAttachedZoneRefs(vo.getAttachedZoneRefs()); this.setCreateDate(vo.getCreateDate()); this.setDescription(vo.getDescription()); this.setLastOpDate(vo.getLastOpDate()); this.setName(vo.getName()); this.setState(vo.getState()); this.setStatus(vo.getStatus()); this.setTotalCapacity(vo.getTotalCapacity()); this.setType(vo.getType()); this.setUrl(vo.getUrl()); this.setAvailableCapacity(vo.getAvailableCapacity()); }