6969import org .apache .cloudstack .backup .dao .BackupDetailsDao ;
7070import org .apache .cloudstack .backup .dao .BackupOfferingDao ;
7171import org .apache .cloudstack .backup .dao .BackupScheduleDao ;
72+ import org .apache .cloudstack .backup .dao .BackupUsageMetricDao ;
7273import org .apache .cloudstack .context .CallContext ;
7374import org .apache .cloudstack .framework .config .ConfigKey ;
7475import org .apache .cloudstack .framework .jobs .AsyncJobDispatcher ;
@@ -182,6 +183,8 @@ public class BackupManagerImpl extends ManagerBase implements BackupManager {
182183 @ Inject
183184 private BackupDetailsDao backupDetailsDao ;
184185 @ Inject
186+ private BackupUsageMetricDao backupUsageMetricDao ;
187+ @ Inject
185188 private BackupScheduleDao backupScheduleDao ;
186189 @ Inject
187190 private BackupOfferingDao backupOfferingDao ;
@@ -546,6 +549,7 @@ public boolean removeVMFromBackupOffering(final Long vmId, final boolean forced)
546549 UsageEventUtils .publishUsageEvent (EventTypes .EVENT_VM_BACKUP_OFFERING_REMOVED_AND_BACKUPS_DELETED , vm .getAccountId (), vm .getDataCenterId (), vm .getId (),
547550 "Backup-" + vm .getHostName () + "-" + vm .getUuid (), backupOfferingId , null , null ,
548551 Backup .class .getSimpleName (), vm .getUuid ());
552+ backupUsageMetricDao .removeByVmAndOffering (vm .getId (), backupOfferingId );
549553 }
550554 final List <BackupScheduleVO > backupSchedules = backupScheduleDao .listByVM (vm .getId ());
551555 for (BackupSchedule backupSchedule : backupSchedules ) {
@@ -1656,6 +1660,7 @@ private void checkAndGenerateUsageForLastBackupDeletedAfterOfferingRemove(Virtua
16561660 UsageEventUtils .publishUsageEvent (EventTypes .EVENT_VM_BACKUP_OFFERING_REMOVED_AND_BACKUPS_DELETED , vm .getAccountId (),
16571661 vm .getDataCenterId (), vm .getId (), "Backup-" + vm .getHostName () + "-" + vm .getUuid (),
16581662 backup .getBackupOfferingId (), null , null , Backup .class .getSimpleName (), vm .getUuid ());
1663+ backupUsageMetricDao .removeByVmAndOffering (vm .getId (), backup .getBackupOfferingId ());
16591664 }
16601665 }
16611666 }
@@ -1985,11 +1990,7 @@ protected void runInContext() {
19851990 continue ;
19861991 }
19871992
1988- backupProvider .syncBackupStorageStats (dataCenter .getId ());
1989-
1990- syncOutOfBandBackups (backupProvider , dataCenter );
1991-
1992- updateBackupUsageRecords (backupProvider , dataCenter );
1993+ syncZone (backupProvider , dataCenter );
19931994 }
19941995 } catch (final Throwable t ) {
19951996 logger .error (String .format ("Error trying to run backup-sync background task due to: [%s]." , t .getMessage ()), t );
@@ -2014,7 +2015,30 @@ private void syncOutOfBandBackups(final BackupProvider backupProvider, DataCente
20142015 }
20152016 }
20162017
2017- private void updateBackupUsageRecords (final BackupProvider backupProvider , DataCenter dataCenter ) {
2018+ private void syncZone (final BackupProvider backupProvider , final DataCenter dataCenter ) {
2019+ // Every management server runs this task. The lock lets one of them at a time sync a zone, so out-of-band
2020+ // backups are not added or removed twice and the usage metrics are compared against the last published ones.
2021+ GlobalLock lock = GlobalLock .getInternLock ("backup.sync." + dataCenter .getId ());
2022+ try {
2023+ if (!lock .lock (5 )) {
2024+ logger .debug ("Backups of zone {} are being synced by another management server, skipping." , dataCenter );
2025+ return ;
2026+ }
2027+ try {
2028+ backupProvider .syncBackupStorageStats (dataCenter .getId ());
2029+
2030+ syncOutOfBandBackups (backupProvider , dataCenter );
2031+
2032+ updateBackupUsageRecords (backupProvider , dataCenter );
2033+ } finally {
2034+ lock .unlock ();
2035+ }
2036+ } finally {
2037+ lock .releaseRef ();
2038+ }
2039+ }
2040+
2041+ protected void updateBackupUsageRecords (final BackupProvider backupProvider , DataCenter dataCenter ) {
20182042 List <Long > vmIdsWithBackups = backupDao .listVmIdsWithBackupsInZone (dataCenter .getId ());
20192043 List <VMInstanceVO > vmsWithBackups ;
20202044 if (vmIdsWithBackups .size () == 0 ) {
@@ -2029,7 +2053,7 @@ private void updateBackupUsageRecords(final BackupProvider backupProvider, DataC
20292053
20302054 Map <Long , Pair <Long , Long >> backupOfferingToSizeMap = new HashMap <>();
20312055 List <Backup > backups = backupDao .listByVmId (null , vm .getId ());
2032- if (backups . isEmpty () && vm .getBackupOfferingId () != null ) {
2056+ if (vm .getBackupOfferingId () != null ) {
20332057 backupOfferingToSizeMap .put (vm .getBackupOfferingId (), new Pair <>(0L , 0L ));
20342058 }
20352059 for (final Backup backup : backups ) {
@@ -2053,14 +2077,34 @@ private void updateBackupUsageRecords(final BackupProvider backupProvider, DataC
20532077 for (final Map .Entry <Long , Pair <Long , Long >> entry : backupOfferingToSizeMap .entrySet ()) {
20542078 Long offeringId = entry .getKey ();
20552079 Pair <Long , Long > sizes = entry .getValue ();
2056- Long backupSize = sizes .first ();
2057- Long protectedSize = sizes .second ();
2080+ publishBackupUsageMetricIfChanged (vm , offeringId , sizes .first (), sizes .second ());
2081+ }
2082+ }
2083+ }
2084+
2085+ protected void publishBackupUsageMetricIfChanged (final VirtualMachine vm , final long offeringId , final long size , final long protectedSize ) {
2086+ final BackupUsageMetricVO lastPublished = backupUsageMetricDao .findByVmAndOffering (vm .getId (), offeringId );
2087+ if (lastPublished != null && lastPublished .getSize () == size && lastPublished .getProtectedSize () == protectedSize ) {
2088+ return ;
2089+ }
2090+ // The event and the value the next sync compares against are committed together.
2091+ Transaction .execute (new TransactionCallbackNoReturn () {
2092+ @ Override
2093+ public void doInTransactionWithoutResult (TransactionStatus status ) {
20582094 UsageEventUtils .publishUsageEvent (EventTypes .EVENT_VM_BACKUP_USAGE_METRIC , vm .getAccountId (),
20592095 vm .getDataCenterId (), vm .getId (), "Backup-" + vm .getHostName () + "-" + vm .getUuid (),
2060- offeringId , null , backupSize , protectedSize ,
2096+ offeringId , null , size , protectedSize ,
20612097 Backup .class .getSimpleName (), vm .getUuid ());
2098+ if (lastPublished == null ) {
2099+ backupUsageMetricDao .persist (new BackupUsageMetricVO (vm .getId (), offeringId , size , protectedSize , new Date ()));
2100+ } else {
2101+ lastPublished .setSize (size );
2102+ lastPublished .setProtectedSize (protectedSize );
2103+ lastPublished .setUpdated (new Date ());
2104+ backupUsageMetricDao .update (lastPublished .getId (), lastPublished );
2105+ }
20622106 }
2063- }
2107+ });
20642108 }
20652109
20662110 private Backup checkAndUpdateIfBackupEntryExistsForRestorePoint (Backup .RestorePoint restorePoint , List <Backup > backupsInDb , VirtualMachine vm ) {
0 commit comments