Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 73 additions & 18 deletions usage/src/main/java/com/cloud/usage/parser/BackupUsageParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

package com.cloud.usage.parser;

import java.text.DecimalFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
Expand All @@ -25,6 +26,7 @@
import javax.annotation.PostConstruct;
import javax.inject.Inject;

import com.cloud.utils.Pair;
import org.apache.cloudstack.backup.Backup;
import org.apache.cloudstack.usage.UsageTypes;
import org.apache.log4j.Logger;
Expand Down Expand Up @@ -68,38 +70,91 @@ public static boolean parse(AccountVO account, Date startDate, Date endDate) {
return true;
}

final Map<Long, BackupInfo> vmUsageMap = new HashMap<>();
Map<String, Pair<Long, Long>> bkpUsageMap = new HashMap<String, Pair<Long, Long>>();
final Map<String, BackupInfo> vmUsageMap = new HashMap<>();
for (final UsageBackupVO usageBackup : usageBackups) {
final Long vmId = usageBackup.getVmId();
final Long zoneId = usageBackup.getZoneId();
String key = vmId + "-" + usageBackup.getBackupOfferingId() + "-" + zoneId;
final Long offeringId = usageBackup.getBackupOfferingId();
if (vmUsageMap.get(vmId) == null) {
vmUsageMap.put(vmId, new BackupUsageParser.BackupInfo(new Backup.Metric(0L, 0L), zoneId, vmId, offeringId));
if (vmUsageMap.get(key) == null) {
vmUsageMap.put(key, new BackupUsageParser.BackupInfo(new Backup.Metric(0L, 0L), zoneId, vmId, offeringId));
}
final Backup.Metric metric = vmUsageMap.get(vmId).getMetric();
final Backup.Metric metric = vmUsageMap.get(key).getMetric();
metric.setBackupSize(metric.getBackupSize() + usageBackup.getSize());
metric.setDataSize(metric.getDataSize() + usageBackup.getProtectedSize());
long duration = getUsageDuration(usageBackup, startDate, endDate);
updateBackupUsageData(bkpUsageMap, key, vmId, duration);
}

for (final BackupInfo backupInfo : vmUsageMap.values()) {
final Long vmId = backupInfo.getVmId();
final Long zoneId = backupInfo.getZoneId();
final Long offeringId = backupInfo.getOfferingId();
final Double rawUsage = (double) backupInfo.getMetric().getBackupSize();
final Double sizeGib = rawUsage / (1024.0 * 1024.0 * 1024.0);
final String description = String.format("Backup usage VM ID: %d", vmId);
final String usageDisplay = String.format("%.4f GiB", sizeGib);

final UsageVO usageRecord =
new UsageVO(zoneId, account.getAccountId(), account.getDomainId(), description, usageDisplay,
UsageTypes.BACKUP, rawUsage, vmId, null, offeringId, null, vmId,
backupInfo.getMetric().getBackupSize(), backupInfo.getMetric().getDataSize(), startDate, endDate);
s_usageDao.persist(usageRecord);
for (String bkpIdKey : bkpUsageMap.keySet()) {
Pair<Long, Long> bkptimeInfo = bkpUsageMap.get(bkpIdKey);
long useTime = bkptimeInfo.second();

// Only create a usage record if we have a runningTime of bigger than zero.
if (useTime > 0L) {
BackupUsageParser.BackupInfo info = vmUsageMap.get(bkpIdKey);
createUsageRecord(UsageTypes.BACKUP, account, useTime, startDate, endDate, info);
}
}

return true;
}

private static void createUsageRecord(int type, AccountVO account, long runningTime, Date startDate, Date endDate, BackupInfo backupInfo) {
// Our smallest increment is hourly for now
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Total running time " + runningTime + "ms");
}
final Long vmId = backupInfo.getVmId();
final Long zoneId = backupInfo.getZoneId();
final Long offeringId = backupInfo.getOfferingId();
float usage = runningTime / 1000f / 60f / 60f;
Copy link
Copy Markdown
Contributor

@GutoVeronezi GutoVeronezi May 10, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Pearl1594 as this calculation is done several times in the code, we could create an utility to it.


DecimalFormat dFormat = new DecimalFormat("#.######");
String usageDisplay = dFormat.format(usage);

final String description = String.format("Backup usage VM ID: %d", vmId);

final UsageVO usageRecord =
new UsageVO(zoneId, account.getAccountId(), account.getDomainId(), description, usageDisplay + " Hrs",
type, (double) usage, vmId, null, offeringId, null, vmId,
backupInfo.getMetric().getBackupSize(), backupInfo.getMetric().getDataSize(), startDate, endDate);
s_usageDao.persist(usageRecord);
}

private static long getUsageDuration(UsageBackupVO usageBackup, Date startDate, Date endDate) {
Date backupCreateDate = usageBackup.getCreated();
Date backupDeleteDate = usageBackup.getRemoved();

if ((backupDeleteDate == null) || backupDeleteDate.after(endDate)) {
backupDeleteDate = endDate;
}

// clip the start date to the beginning of our aggregation range if the vm has been running for a while
if (backupCreateDate.before(startDate)) {
backupCreateDate = startDate;
}

if (backupCreateDate.after(endDate)) {
//Ignore records created after endDate
return 0L;
}
return (backupDeleteDate.getTime() - backupCreateDate.getTime()) + 1; // make sure this is an inclusive check for milliseconds (i.e. use n - m + 1 to find total number of millis to charge)
}

private static void updateBackupUsageData(Map<String, Pair<Long, Long>> usageDataMap, String key, long vmId, long duration) {
Pair<Long, Long> backupUsageInfo = usageDataMap.get(key);
if (backupUsageInfo == null) {
backupUsageInfo = new Pair<Long, Long>(vmId, duration);
} else {
Long runningTime = backupUsageInfo.second();
runningTime = runningTime + duration;
backupUsageInfo = new Pair<Long, Long>(backupUsageInfo.first(), runningTime);
}
usageDataMap.put(key, backupUsageInfo);
}

static class BackupInfo {
Backup.Metric metric;
Long zoneId;
Expand Down