3232import java .util .TimeZone ;
3333import java .util .Timer ;
3434import java .util .TimerTask ;
35+ import java .util .concurrent .ConcurrentHashMap ;
3536import java .util .stream .Collectors ;
3637import java .util .stream .Stream ;
3738
@@ -249,6 +250,12 @@ public class BackupManagerImpl extends ManagerBase implements BackupManager {
249250 private static Map <String , BackupProvider > backupProvidersMap = new HashMap <>();
250251 private List <BackupProvider > backupProviders ;
251252
253+ // Per zone, the backup usage metric last published for each (VM, backup offering) pair, as (size,
254+ // protected size). The backup sync runs every few minutes but the usage server only needs the
255+ // metric when it changes. After a restart or on another management server each value is
256+ // published once more, which the usage server ignores as the size is unchanged.
257+ private final Map <Long , Map <Pair <Long , Long >, Pair <Long , Long >>> lastPublishedBackupUsageMetrics = new ConcurrentHashMap <>();
258+
252259 public AsyncJobDispatcher getAsyncJobDispatcher () {
253260 return asyncJobDispatcher ;
254261 }
@@ -2014,7 +2021,7 @@ private void syncOutOfBandBackups(final BackupProvider backupProvider, DataCente
20142021 }
20152022 }
20162023
2017- private void updateBackupUsageRecords (final BackupProvider backupProvider , DataCenter dataCenter ) {
2024+ protected void updateBackupUsageRecords (final BackupProvider backupProvider , DataCenter dataCenter ) {
20182025 List <Long > vmIdsWithBackups = backupDao .listVmIdsWithBackupsInZone (dataCenter .getId ());
20192026 List <VMInstanceVO > vmsWithBackups ;
20202027 if (vmIdsWithBackups .size () == 0 ) {
@@ -2025,6 +2032,8 @@ private void updateBackupUsageRecords(final BackupProvider backupProvider, DataC
20252032 List <VMInstanceVO > vmsWithBackupOffering = vmInstanceDao .listByZoneAndBackupOffering (dataCenter .getId (), null ); //should return including removed
20262033 Set <VMInstanceVO > vms = Stream .concat (vmsWithBackups .stream (), vmsWithBackupOffering .stream ()) .collect (Collectors .toSet ());
20272034
2035+ Map <Pair <Long , Long >, Pair <Long , Long >> lastPublished = lastPublishedBackupUsageMetrics .getOrDefault (dataCenter .getId (), Collections .emptyMap ());
2036+ Map <Pair <Long , Long >, Pair <Long , Long >> published = new HashMap <>();
20282037 for (final VirtualMachine vm : vms ) {
20292038
20302039 Map <Long , Pair <Long , Long >> backupOfferingToSizeMap = new HashMap <>();
@@ -2055,12 +2064,20 @@ private void updateBackupUsageRecords(final BackupProvider backupProvider, DataC
20552064 Pair <Long , Long > sizes = entry .getValue ();
20562065 Long backupSize = sizes .first ();
20572066 Long protectedSize = sizes .second ();
2067+ Pair <Long , Long > key = new Pair <>(vm .getId (), offeringId );
2068+ Pair <Long , Long > metric = new Pair <>(backupSize , protectedSize );
2069+ published .put (key , metric );
2070+ if (metric .equals (lastPublished .get (key ))) {
2071+ continue ;
2072+ }
20582073 UsageEventUtils .publishUsageEvent (EventTypes .EVENT_VM_BACKUP_USAGE_METRIC , vm .getAccountId (),
20592074 vm .getDataCenterId (), vm .getId (), "Backup-" + vm .getHostName () + "-" + vm .getUuid (),
20602075 offeringId , null , backupSize , protectedSize ,
20612076 Backup .class .getSimpleName (), vm .getUuid ());
20622077 }
20632078 }
2079+ // Replacing the map also drops pairs that are no longer reported, e.g. expunged VMs.
2080+ lastPublishedBackupUsageMetrics .put (dataCenter .getId (), published );
20642081 }
20652082
20662083 private Backup checkAndUpdateIfBackupEntryExistsForRestorePoint (Backup .RestorePoint restorePoint , List <Backup > backupsInDb , VirtualMachine vm ) {
0 commit comments