Backup: refactoring
This commit is contained in:
parent
a4146fcce7
commit
0ff1f8249d
@ -54,7 +54,7 @@ namespace ASC.Data.Backup
|
||||
if (action == null)
|
||||
throw new ArgumentNullException("action");
|
||||
|
||||
int countAttempts = 0;
|
||||
var countAttempts = 0;
|
||||
while (countAttempts++ < maxAttempts)
|
||||
{
|
||||
try
|
||||
|
@ -146,7 +146,7 @@ namespace ASC.Data.Backup
|
||||
var errors = 0;
|
||||
var timeout = TimeSpan.FromSeconds(1);
|
||||
var tables = dbHelper.GetTables();
|
||||
for (int i = 0; i < tables.Count; i++)
|
||||
for (var i = 0; i < tables.Count; i++)
|
||||
{
|
||||
var table = tables[i];
|
||||
OnProgressChanged(table, (int)(i / (double)tables.Count * 100));
|
||||
@ -203,7 +203,7 @@ namespace ASC.Data.Backup
|
||||
if (dbElement == null) return;
|
||||
|
||||
var tables = dbHelper.GetTables();
|
||||
for (int i = 0; i < tables.Count; i++)
|
||||
for (var i = 0; i < tables.Count; i++)
|
||||
{
|
||||
var table = tables[i];
|
||||
OnProgressChanged(table, (int)(i / (double)tables.Count * 100));
|
||||
|
@ -226,7 +226,7 @@ namespace ASC.Data.Backup
|
||||
|
||||
public List<string> ExecuteList(DbCommand command)
|
||||
{
|
||||
List<string> list = new List<string>();
|
||||
var list = new List<string>();
|
||||
using (var result = command.ExecuteReader())
|
||||
{
|
||||
while (result.Read())
|
||||
|
@ -253,7 +253,7 @@ namespace ASC.Data.Backup
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
int result = (Module != null ? Module.GetHashCode() : 0);
|
||||
var result = (Module != null ? Module.GetHashCode() : 0);
|
||||
result = (result * 397) ^ (Domain != null ? Domain.GetHashCode() : 0);
|
||||
result = (result * 397) ^ (Path != null ? Path.GetHashCode() : 0);
|
||||
return result;
|
||||
|
@ -26,55 +26,124 @@
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading;
|
||||
|
||||
using ASC.Common;
|
||||
using ASC.Common.Logging;
|
||||
using ASC.Data.Backup.Storage;
|
||||
using ASC.Data.Backup.Storage;
|
||||
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace ASC.Data.Backup.Service
|
||||
{
|
||||
internal class BackupCleanerHelperService
|
||||
{
|
||||
private readonly ILog log;
|
||||
|
||||
public BackupRepository BackupRepository { get; }
|
||||
public BackupStorageFactory BackupStorageFactory { get; }
|
||||
|
||||
public BackupCleanerHelperService(
|
||||
IOptionsMonitor<ILog> options,
|
||||
BackupRepository backupRepository,
|
||||
BackupStorageFactory backupStorageFactory)
|
||||
{
|
||||
log = options.CurrentValue;
|
||||
BackupRepository = backupRepository;
|
||||
BackupStorageFactory = backupStorageFactory;
|
||||
}
|
||||
|
||||
|
||||
internal void DeleteExpiredBackups(BackupCleanerService backupCleanerService)
|
||||
{
|
||||
log.Debug("started to clean expired backups");
|
||||
|
||||
var backupsToRemove = BackupRepository.GetExpiredBackupRecords();
|
||||
log.DebugFormat("found {0} backups which are expired", backupsToRemove.Count);
|
||||
|
||||
if (!backupCleanerService.IsStarted) return;
|
||||
foreach (var scheduledBackups in BackupRepository.GetScheduledBackupRecords().GroupBy(r => r.TenantId))
|
||||
{
|
||||
if (!backupCleanerService.IsStarted) return;
|
||||
var schedule = BackupRepository.GetBackupSchedule(scheduledBackups.Key);
|
||||
if (schedule != null)
|
||||
{
|
||||
var scheduledBackupsToRemove = scheduledBackups.OrderByDescending(r => r.CreatedOn).Skip(schedule.BackupsStored).ToList();
|
||||
if (scheduledBackupsToRemove.Any())
|
||||
{
|
||||
log.DebugFormat("only last {0} scheduled backup records are to keep for tenant {1} so {2} records must be removed", schedule.BackupsStored, schedule.TenantId, scheduledBackupsToRemove.Count);
|
||||
backupsToRemove.AddRange(scheduledBackupsToRemove);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
backupsToRemove.AddRange(scheduledBackups);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var backupRecord in backupsToRemove)
|
||||
{
|
||||
if (!backupCleanerService.IsStarted) return;
|
||||
try
|
||||
{
|
||||
var backupStorage = BackupStorageFactory.GetBackupStorage(backupRecord);
|
||||
if (backupStorage == null) continue;
|
||||
|
||||
backupStorage.Delete(backupRecord.StoragePath);
|
||||
|
||||
BackupRepository.DeleteBackupRecord(backupRecord.Id);
|
||||
}
|
||||
catch (Exception error)
|
||||
{
|
||||
log.Warn("can't remove backup record: {0}", error);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
public class BackupCleanerService
|
||||
{
|
||||
private readonly object cleanerLock = new object();
|
||||
private Timer cleanTimer;
|
||||
private bool isStarted;
|
||||
private readonly ILog log;
|
||||
public TimeSpan Period { get; set; }
|
||||
private readonly BackupStorageFactory backupStorageFactory;
|
||||
public BackupCleanerService(IOptionsMonitor<ILog> options, BackupStorageFactory backupStorageFactory)
|
||||
{
|
||||
this.backupStorageFactory = backupStorageFactory;
|
||||
log = options.CurrentValue;
|
||||
private Timer CleanTimer { get; set; }
|
||||
internal bool IsStarted { get; set; }
|
||||
private ILog Log { get; set; }
|
||||
public TimeSpan Period { get; set; }
|
||||
private IServiceProvider ServiceProvider { get; set; }
|
||||
|
||||
public BackupCleanerService(
|
||||
IOptionsMonitor<ILog> options,
|
||||
IServiceProvider serviceProvider)
|
||||
{
|
||||
ServiceProvider = serviceProvider;
|
||||
Log = options.CurrentValue;
|
||||
Period = TimeSpan.FromMinutes(15);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void Start()
|
||||
{
|
||||
if (!isStarted && Period > TimeSpan.Zero)
|
||||
if (!IsStarted && Period > TimeSpan.Zero)
|
||||
{
|
||||
log.Info("starting backup cleaner service...");
|
||||
cleanTimer = new Timer(_ => DeleteExpiredBackups(), null, TimeSpan.Zero, Period);
|
||||
log.Info("backup cleaner service started");
|
||||
isStarted = true;
|
||||
Log.Info("starting backup cleaner service...");
|
||||
CleanTimer = new Timer(_ => DeleteExpiredBackups(), null, TimeSpan.Zero, Period);
|
||||
Log.Info("backup cleaner service started");
|
||||
IsStarted = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
if (isStarted)
|
||||
if (IsStarted)
|
||||
{
|
||||
log.Info("stopping backup cleaner service...");
|
||||
if (cleanTimer != null)
|
||||
Log.Info("stopping backup cleaner service...");
|
||||
if (CleanTimer != null)
|
||||
{
|
||||
cleanTimer.Change(Timeout.Infinite, Timeout.Infinite);
|
||||
cleanTimer.Dispose();
|
||||
cleanTimer = null;
|
||||
CleanTimer.Change(Timeout.Infinite, Timeout.Infinite);
|
||||
CleanTimer.Dispose();
|
||||
CleanTimer = null;
|
||||
}
|
||||
log.Info("backup cleaner service stopped");
|
||||
isStarted = false;
|
||||
Log.Info("backup cleaner service stopped");
|
||||
IsStarted = false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -83,55 +152,15 @@ namespace ASC.Data.Backup.Service
|
||||
if (Monitor.TryEnter(cleanerLock))
|
||||
{
|
||||
try
|
||||
{
|
||||
log.Debug("started to clean expired backups");
|
||||
|
||||
var backupRepository = backupStorageFactory.GetBackupRepository();
|
||||
|
||||
var backupsToRemove = backupRepository.GetExpiredBackupRecords();
|
||||
log.DebugFormat("found {0} backups which are expired", backupsToRemove.Count);
|
||||
|
||||
if (!isStarted) return;
|
||||
foreach (var scheduledBackups in backupRepository.GetScheduledBackupRecords().GroupBy(r => r.TenantId))
|
||||
{
|
||||
if (!isStarted) return;
|
||||
var schedule = backupRepository.GetBackupSchedule(scheduledBackups.Key);
|
||||
if (schedule != null)
|
||||
{
|
||||
var scheduledBackupsToRemove = scheduledBackups.OrderByDescending(r => r.CreatedOn).Skip(schedule.BackupsStored).ToList();
|
||||
if (scheduledBackupsToRemove.Any())
|
||||
{
|
||||
log.DebugFormat("only last {0} scheduled backup records are to keep for tenant {1} so {2} records must be removed", schedule.BackupsStored, schedule.TenantId, scheduledBackupsToRemove.Count);
|
||||
backupsToRemove.AddRange(scheduledBackupsToRemove);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
backupsToRemove.AddRange(scheduledBackups);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var backupRecord in backupsToRemove)
|
||||
{
|
||||
if (!isStarted) return;
|
||||
try
|
||||
{
|
||||
var backupStorage = backupStorageFactory.GetBackupStorage(backupRecord);
|
||||
if (backupStorage == null) continue;
|
||||
|
||||
backupStorage.Delete(backupRecord.StoragePath);
|
||||
|
||||
backupRepository.DeleteBackupRecord(backupRecord.Id);
|
||||
}
|
||||
catch (Exception error)
|
||||
{
|
||||
log.Warn("can't remove backup record: {0}", error);
|
||||
}
|
||||
}
|
||||
{
|
||||
|
||||
using var scope = ServiceProvider.CreateScope();
|
||||
var backupCleanerHelperService = scope.ServiceProvider.GetService<BackupCleanerHelperService>();
|
||||
backupCleanerHelperService.DeleteExpiredBackups(this);
|
||||
}
|
||||
catch (Exception error)
|
||||
{
|
||||
log.Error("error while cleaning expired backup records: {0}", error);
|
||||
Log.Error("error while cleaning expired backup records: {0}", error);
|
||||
}
|
||||
finally
|
||||
{
|
||||
@ -144,8 +173,11 @@ namespace ASC.Data.Backup.Service
|
||||
{
|
||||
public static DIHelper AddBackupCleanerService(this DIHelper services)
|
||||
{
|
||||
services.TryAddScoped<BackupCleanerService>();
|
||||
return services;
|
||||
services.TryAddScoped<BackupCleanerHelperService>();
|
||||
services.TryAddSingleton<BackupCleanerService>();
|
||||
return services
|
||||
.AddBackupStorageFactory()
|
||||
.AddBackupRepositoryService();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -24,61 +24,119 @@
|
||||
*/
|
||||
|
||||
|
||||
using ASC.Core.Billing;
|
||||
using ASC.Data.Backup.Storage;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using ASC.Common.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using ASC.Core;
|
||||
|
||||
using ASC.Common;
|
||||
using ASC.Common.Logging;
|
||||
using ASC.Core;
|
||||
using ASC.Core.Billing;
|
||||
using ASC.Data.Backup.Storage;
|
||||
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace ASC.Data.Backup.Service
|
||||
{
|
||||
internal class BackupSchedulerServiceHelper
|
||||
{
|
||||
private ILog Log { get; }
|
||||
private PaymentManager PaymentManager { get; }
|
||||
private BackupWorker BackupWorker { get; }
|
||||
public BackupRepository BackupRepository { get; }
|
||||
private Schedule Schedule { get; }
|
||||
|
||||
public BackupSchedulerServiceHelper(
|
||||
IOptionsMonitor<ILog> options,
|
||||
PaymentManager paymentManager,
|
||||
BackupWorker backupWorker,
|
||||
BackupRepository backupRepository,
|
||||
Schedule schedule)
|
||||
{
|
||||
PaymentManager = paymentManager;
|
||||
BackupWorker = backupWorker;
|
||||
BackupRepository = backupRepository;
|
||||
Schedule = schedule;
|
||||
Log = options.CurrentValue;
|
||||
}
|
||||
|
||||
public void ScheduleBackupTasks(BackupSchedulerService backupSchedulerService)
|
||||
{
|
||||
Log.DebugFormat("started to schedule backups");
|
||||
var backupsToSchedule = BackupRepository.GetBackupSchedules().Where(schedule => Schedule.IsToBeProcessed(schedule)).ToList();
|
||||
Log.DebugFormat("{0} backups are to schedule", backupsToSchedule.Count);
|
||||
foreach (var schedule in backupsToSchedule)
|
||||
{
|
||||
if (!backupSchedulerService.IsStarted)
|
||||
{
|
||||
return;
|
||||
}
|
||||
try
|
||||
{
|
||||
var tariff = PaymentManager.GetTariff(schedule.TenantId);
|
||||
if (tariff.State < TariffState.Delay)
|
||||
{
|
||||
schedule.LastBackupTime = DateTime.UtcNow;
|
||||
BackupRepository.SaveBackupSchedule(schedule);
|
||||
Log.DebugFormat("Start scheduled backup: {0}, {1}, {2}, {3}", schedule.TenantId, schedule.BackupMail, schedule.StorageType, schedule.StorageBasePath);
|
||||
BackupWorker.StartScheduledBackup(schedule);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.DebugFormat("Skip portal {0} not paid", schedule.TenantId);
|
||||
}
|
||||
}
|
||||
catch (Exception error)
|
||||
{
|
||||
Log.Error("error while scheduling backups: {0}", error);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class BackupSchedulerService
|
||||
{
|
||||
private readonly object schedulerLock = new object();
|
||||
private Timer schedulerTimer;
|
||||
private bool isStarted;
|
||||
private readonly ILog log;
|
||||
private readonly PaymentManager paymentManager;
|
||||
private BackupStorageFactory backupStorageFactory;
|
||||
private BackupWorker backupWorker;
|
||||
public BackupSchedulerService(IOptionsMonitor<ILog> options, PaymentManager paymentManager, BackupStorageFactory backupStorageFactory, BackupWorker backupWorker)
|
||||
{
|
||||
this.paymentManager = paymentManager;
|
||||
this.backupStorageFactory = backupStorageFactory;
|
||||
this.backupWorker = backupWorker;
|
||||
log = options.CurrentValue;
|
||||
Period = TimeSpan.FromMinutes(15);
|
||||
}
|
||||
private Timer SchedulerTimer { get; set; }
|
||||
internal bool IsStarted { get; set; }
|
||||
public TimeSpan Period { get; set; }
|
||||
|
||||
private ILog Log { get; }
|
||||
public IServiceProvider ServiceProvider { get; }
|
||||
|
||||
public BackupSchedulerService(
|
||||
IOptionsMonitor<ILog> options,
|
||||
IServiceProvider serviceProvider)
|
||||
{
|
||||
Log = options.CurrentValue;
|
||||
Period = TimeSpan.FromMinutes(15);
|
||||
ServiceProvider = serviceProvider;
|
||||
}
|
||||
|
||||
public void Start()
|
||||
{
|
||||
if (!isStarted && Period > TimeSpan.Zero)
|
||||
if (!IsStarted && Period > TimeSpan.Zero)
|
||||
{
|
||||
log.Info("staring backup scheduler service...");
|
||||
schedulerTimer = new Timer(_ => ScheduleBackupTasks(), null, TimeSpan.Zero, Period);
|
||||
log.Info("backup scheduler service service started");
|
||||
isStarted = true;
|
||||
Log.Info("staring backup scheduler service...");
|
||||
SchedulerTimer = new Timer(_ => ScheduleBackupTasks(), null, TimeSpan.Zero, Period);
|
||||
Log.Info("backup scheduler service service started");
|
||||
IsStarted = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
if (isStarted)
|
||||
if (IsStarted)
|
||||
{
|
||||
log.Info("stoping backup scheduler service...");
|
||||
if (schedulerTimer != null)
|
||||
Log.Info("stoping backup scheduler service...");
|
||||
if (SchedulerTimer != null)
|
||||
{
|
||||
schedulerTimer.Change(Timeout.Infinite, Timeout.Infinite);
|
||||
schedulerTimer.Dispose();
|
||||
schedulerTimer = null;
|
||||
SchedulerTimer.Change(Timeout.Infinite, Timeout.Infinite);
|
||||
SchedulerTimer.Dispose();
|
||||
SchedulerTimer = null;
|
||||
}
|
||||
log.Info("backup scheduler service stoped");
|
||||
isStarted = false;
|
||||
Log.Info("backup scheduler service stoped");
|
||||
IsStarted = false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -87,41 +145,14 @@ namespace ASC.Data.Backup.Service
|
||||
if (Monitor.TryEnter(schedulerLock))
|
||||
{
|
||||
try
|
||||
{
|
||||
log.DebugFormat("started to schedule backups");
|
||||
var backupRepostory = backupStorageFactory.GetBackupRepository();
|
||||
var backupsToSchedule = backupRepostory.GetBackupSchedules().Where(schedule => schedule.IsToBeProcessed()).ToList();
|
||||
log.DebugFormat("{0} backups are to schedule", backupsToSchedule.Count);
|
||||
foreach (var schedule in backupsToSchedule)
|
||||
{
|
||||
if (!isStarted)
|
||||
{
|
||||
return;
|
||||
}
|
||||
try
|
||||
{
|
||||
var tariff = paymentManager.GetTariff(schedule.TenantId);
|
||||
if (tariff.State < TariffState.Delay)
|
||||
{
|
||||
schedule.LastBackupTime = DateTime.UtcNow;
|
||||
backupRepostory.SaveBackupSchedule(schedule);
|
||||
log.DebugFormat("Start scheduled backup: {0}, {1}, {2}, {3}", schedule.TenantId, schedule.BackupMail, schedule.StorageType, schedule.StorageBasePath);
|
||||
backupWorker.StartScheduledBackup(schedule);
|
||||
}
|
||||
else
|
||||
{
|
||||
log.DebugFormat("Skip portal {0} not paid", schedule.TenantId);
|
||||
}
|
||||
}
|
||||
catch (Exception error)
|
||||
{
|
||||
log.Error("error while scheduling backups: {0}", error);
|
||||
}
|
||||
}
|
||||
{
|
||||
using var scope = ServiceProvider.CreateScope();
|
||||
var backupSchedulerServiceHelper = scope.ServiceProvider.GetService<BackupSchedulerServiceHelper>();
|
||||
backupSchedulerServiceHelper.ScheduleBackupTasks(this);
|
||||
}
|
||||
catch (Exception error)
|
||||
{
|
||||
log.Error("error while scheduling backups: {0}", error);
|
||||
Log.Error("error while scheduling backups: {0}", error);
|
||||
}
|
||||
finally
|
||||
{
|
||||
@ -129,14 +160,21 @@ namespace ASC.Data.Backup.Service
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class BackupSchedulerServiceExtension
|
||||
{
|
||||
public static DIHelper AddBackupSchedulerService(this DIHelper services)
|
||||
{
|
||||
services.TryAddScoped<BackupSchedulerService>();
|
||||
services.TryAddSingleton<BackupSchedulerService>();
|
||||
services.TryAddScoped<BackupSchedulerServiceHelper>();
|
||||
|
||||
return services
|
||||
.AddPaymentManagerService();
|
||||
.AddPaymentManagerService()
|
||||
.AddScheduleService()
|
||||
.AddBackupStorageFactory()
|
||||
.AddBackupWorkerService()
|
||||
.AddBackupRepositoryService();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -24,63 +24,76 @@
|
||||
*/
|
||||
|
||||
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using ASC.Common;
|
||||
using ASC.Common.Module;
|
||||
|
||||
|
||||
using Microsoft.Extensions.Hosting;
|
||||
|
||||
namespace ASC.Data.Backup.Service
|
||||
{
|
||||
public class BackupServiceLauncher : IServiceController
|
||||
internal class BackupServiceLauncher : IHostedService
|
||||
{
|
||||
private BackupCleanerService cleanerService;
|
||||
private BackupSchedulerService schedulerService;
|
||||
private BackupWorker backupWorker;
|
||||
private BackupCleanerService CleanerService { get; set; }
|
||||
private BackupSchedulerService SchedulerService { get; set; }
|
||||
private BackupWorker BackupWorker { get; set; }
|
||||
|
||||
public BackupServiceLauncher(BackupCleanerService cleanerService, BackupSchedulerService schedulerService, BackupWorker backupWorker)
|
||||
{
|
||||
this.cleanerService = cleanerService;
|
||||
this.schedulerService = schedulerService;
|
||||
this.backupWorker = backupWorker;
|
||||
}
|
||||
public void Start()
|
||||
public BackupServiceLauncher(
|
||||
BackupCleanerService cleanerService,
|
||||
BackupSchedulerService schedulerService,
|
||||
BackupWorker backupWorker)
|
||||
{
|
||||
CleanerService = cleanerService;
|
||||
SchedulerService = schedulerService;
|
||||
BackupWorker = backupWorker;
|
||||
}
|
||||
|
||||
public Task StartAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
var config = BackupConfigurationSection.GetSection();
|
||||
|
||||
backupWorker.Start(config);
|
||||
|
||||
|
||||
BackupWorker.Start(config);
|
||||
|
||||
if (config.Cleaner.ElementInformation.IsPresent)
|
||||
{
|
||||
cleanerService.Period = config.Cleaner.Period ;
|
||||
cleanerService.Start();
|
||||
CleanerService.Period = config.Cleaner.Period;
|
||||
CleanerService.Start();
|
||||
}
|
||||
if (config.Scheduler.ElementInformation.IsPresent)
|
||||
{
|
||||
schedulerService.Period = config.Scheduler.Period ;
|
||||
schedulerService.Start();
|
||||
}
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
backupWorker.Stop();
|
||||
if (cleanerService != null)
|
||||
SchedulerService.Period = config.Scheduler.Period;
|
||||
SchedulerService.Start();
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task StopAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
BackupWorker.Stop();
|
||||
if (CleanerService != null)
|
||||
{
|
||||
cleanerService.Stop();
|
||||
cleanerService = null;
|
||||
CleanerService.Stop();
|
||||
CleanerService = null;
|
||||
}
|
||||
if (schedulerService != null)
|
||||
if (SchedulerService != null)
|
||||
{
|
||||
schedulerService.Stop();
|
||||
schedulerService = null;
|
||||
}
|
||||
}
|
||||
SchedulerService.Stop();
|
||||
SchedulerService = null;
|
||||
}
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
public static class BackupServiceLauncherExtension
|
||||
{
|
||||
public static DIHelper AddBackupServiceLauncher(this DIHelper services)
|
||||
{
|
||||
services.TryAddScoped<BackupServiceLauncher>();
|
||||
return services;
|
||||
return services
|
||||
.AddBackupCleanerService()
|
||||
.AddBackupSchedulerService()
|
||||
.AddBackupWorkerService();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,16 +1,18 @@
|
||||
|
||||
|
||||
using System;
|
||||
|
||||
using ASC.Common;
|
||||
using ASC.Common.Logging;
|
||||
using ASC.Common.Threading.Progress;
|
||||
using ASC.Data.Backup.Service;
|
||||
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using System;
|
||||
using ASC.Common.Logging;
|
||||
|
||||
using static ASC.Data.Backup.Service.BackupWorker;
|
||||
using ASC.Data.Backup.Tasks.Modules;
|
||||
using ASC.Data.Backup.Service;
|
||||
|
||||
namespace ASC.Data.Backup
|
||||
{
|
||||
@ -29,20 +31,7 @@ namespace ASC.Data.Backup
|
||||
|
||||
var diHelper = new DIHelper(services);
|
||||
|
||||
diHelper.AddBackupHelperService()
|
||||
.AddBackupManager()
|
||||
.AddDbBackupProvider()
|
||||
.AddDbHelper()
|
||||
.AddFileBackupProviderService()
|
||||
.AddNotifyHelperService()
|
||||
.AddHelpers()
|
||||
.AddModuleProvider()
|
||||
.AddBackupAjaxHandler()
|
||||
.AddBackupServiceLauncher()
|
||||
.AddBackupWorkerService()
|
||||
.AddBackupService()
|
||||
.AddBackupSchedulerService()
|
||||
.AddBackupCleanerService();
|
||||
diHelper.AddBackupServiceLauncher();
|
||||
diHelper.AddNLogManager("ASC.Data.Backup");
|
||||
|
||||
diHelper.Configure<ProgressQueue<BackupProgressItem>>(r =>
|
||||
@ -80,8 +69,8 @@ namespace ASC.Data.Backup
|
||||
}
|
||||
|
||||
public void Configure(IApplicationBuilder app)
|
||||
{
|
||||
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -25,62 +25,48 @@
|
||||
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using ASC.Common;
|
||||
using ASC.Common.Logging;
|
||||
using ASC.Core;
|
||||
using ASC.Core.Common.Contracts;
|
||||
using ASC.Core.Tenants;
|
||||
using ASC.Data.Backup.EF.Context;
|
||||
using ASC.Data.Backup.EF.Model;
|
||||
using ASC.Data.Backup.Service;
|
||||
using ASC.Data.Backup.Utils;
|
||||
using ASC.Data.Storage;
|
||||
using ASC.Files.Core;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
using ASC.Files.Core;
|
||||
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace ASC.Data.Backup.Storage
|
||||
{
|
||||
public class BackupStorageFactory
|
||||
{
|
||||
|
||||
private TenantManager tenantManager;
|
||||
private SecurityContext securityContext;
|
||||
private IDaoFactory daoFactory;
|
||||
private StorageFactory storageFactory;
|
||||
private BackupsContext backupContext;
|
||||
private IOptionsMonitor<ILog> options;
|
||||
private TenantUtil tenantUtil;
|
||||
private BackupHelper backupHelper;
|
||||
|
||||
public BackupStorageFactory(TenantManager tenantManager, SecurityContext securityContext, IDaoFactory daoFactory, StorageFactory storageFactory, BackupsContext backupContext, IOptionsMonitor<ILog> options, TenantUtil tenantUtil, BackupHelper backupHelper)
|
||||
{
|
||||
this.tenantManager = tenantManager;
|
||||
this.securityContext = securityContext;
|
||||
this.daoFactory = daoFactory;
|
||||
this.storageFactory = storageFactory;
|
||||
this.backupContext = backupContext;
|
||||
this.options = options;
|
||||
this.tenantUtil = tenantUtil;
|
||||
this.backupHelper = backupHelper;
|
||||
}
|
||||
public IBackupStorage GetBackupStorage(BackupRecord record)
|
||||
{
|
||||
return GetBackupStorage(record.StorageType, record.TenantId, record.StorageParams);
|
||||
}
|
||||
|
||||
{
|
||||
public IServiceProvider ServiceProvider { get; }
|
||||
public BackupStorageFactory(IServiceProvider serviceProvider)
|
||||
{
|
||||
ServiceProvider = serviceProvider;
|
||||
}
|
||||
}
|
||||
|
||||
public IBackupStorage GetBackupStorage(BackupRecord record)
|
||||
{
|
||||
return GetBackupStorage(record.StorageType, record.TenantId, JsonConvert.DeserializeObject<Dictionary<string, string>>(record.StorageParams));
|
||||
}
|
||||
|
||||
public IBackupStorage GetBackupStorage(BackupStorageType type, int tenantId, Dictionary<string, string> storageParams)
|
||||
{
|
||||
var config = BackupConfigurationSection.GetSection();
|
||||
var webConfigPath = PathHelper.ToRootedConfigPath(config.WebConfigs.CurrentPath);
|
||||
var webConfigPath = PathHelper.ToRootedConfigPath(config.WebConfigs.CurrentPath);
|
||||
|
||||
using var scope = ServiceProvider.CreateScope();
|
||||
var tenantManager = scope.ServiceProvider.GetService<TenantManager>();
|
||||
var tenantManager = scope.ServiceProvider.GetService<TenantManager>();
|
||||
var securityContext = scope.ServiceProvider.GetService<SecurityContext>();
|
||||
var daoFactory = scope.ServiceProvider.GetService<IDaoFactory>();
|
||||
var storageFactory = scope.ServiceProvider.GetService<StorageFactory>();
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case BackupStorageType.Documents:
|
||||
@ -98,11 +84,6 @@ namespace ASC.Data.Backup.Storage
|
||||
throw new InvalidOperationException("Unknown storage type.");
|
||||
}
|
||||
}
|
||||
|
||||
public IBackupRepository GetBackupRepository()
|
||||
{
|
||||
return new BackupRepository(backupContext, options, tenantManager, tenantUtil, backupHelper);
|
||||
}
|
||||
}
|
||||
public static class BackupStorageFactoryExtension
|
||||
{
|
||||
|
@ -57,7 +57,7 @@ namespace ASC.Data.Backup.Storage
|
||||
|
||||
public string Upload(string storageBasePath, string localPath, Guid userId)
|
||||
{
|
||||
String key = String.Empty;
|
||||
var key = String.Empty;
|
||||
|
||||
if (String.IsNullOrEmpty(storageBasePath))
|
||||
key = "backup/" + Path.GetFileName(localPath);
|
||||
|
@ -297,8 +297,8 @@ namespace ASC.Data.Backup.Tasks
|
||||
Logger.DebugFormat("dump table data start {0}", t);
|
||||
var searchWithPrimary = false;
|
||||
string primaryIndex;
|
||||
int primaryIndexStep = 0;
|
||||
int primaryIndexStart = 0;
|
||||
var primaryIndexStep = 0;
|
||||
var primaryIndexStart = 0;
|
||||
|
||||
List<string> columns;
|
||||
var dbFactory = new DbFactory(ConfigPath);
|
||||
@ -390,7 +390,7 @@ namespace ASC.Data.Backup.Tasks
|
||||
using (var connection = dbFactory.OpenConnection())
|
||||
{
|
||||
var command = connection.CreateCommand();
|
||||
string selects = "";
|
||||
var selects = "";
|
||||
foreach(var column in columns)
|
||||
{
|
||||
selects = column + ", ";
|
||||
@ -414,7 +414,7 @@ namespace ASC.Data.Backup.Tasks
|
||||
using (var connection = dbFactory.OpenConnection())
|
||||
{
|
||||
var command = connection.CreateCommand();
|
||||
string selects = "";
|
||||
var selects = "";
|
||||
foreach (var column in columns)
|
||||
{
|
||||
selects = column + ", ";
|
||||
@ -712,12 +712,12 @@ namespace ASC.Data.Backup.Tasks
|
||||
}
|
||||
public List<object[]> ExecuteList(DbCommand command)
|
||||
{
|
||||
List<object[]> list = new List<object[]>();
|
||||
var list = new List<object[]>();
|
||||
using (var result = command.ExecuteReader())
|
||||
{
|
||||
while (result.Read())
|
||||
{
|
||||
object[] objects = new object[result.FieldCount];
|
||||
var objects = new object[result.FieldCount];
|
||||
result.GetValues(objects);
|
||||
list.Add(objects);
|
||||
}
|
||||
|
@ -82,7 +82,7 @@ namespace ASC.Data.Backup.Tasks.Data
|
||||
|
||||
var sb = new StringBuilder(maxStrLength);
|
||||
|
||||
int i = 0;
|
||||
var i = 0;
|
||||
while (i < _values.Count && sb.Length <= maxStrLength)
|
||||
{
|
||||
var strVal = Convert.ToString(_values[i]);
|
||||
|
@ -72,7 +72,7 @@ namespace ASC.Data.Backup.Tasks.Data
|
||||
var dataRowInfo = new DataRowInfo(el.Name.LocalName);
|
||||
foreach (var column in schema)
|
||||
{
|
||||
object value = ConvertToType(el.Element(column.Key).ValueOrDefault(), column.Value);
|
||||
var value = ConvertToType(el.Element(column.Key).ValueOrDefault(), column.Value);
|
||||
dataRowInfo.SetValue(column.Key, value);
|
||||
}
|
||||
|
||||
|
@ -51,7 +51,7 @@ namespace ASC.Data.Backup.Tasks
|
||||
public override void RunJob()
|
||||
{
|
||||
Logger.DebugFormat("begin delete {0}", TenantId);
|
||||
List<IModuleSpecifics> modulesToProcess = GetModulesToProcess().Reverse().ToList();
|
||||
var modulesToProcess = GetModulesToProcess().Reverse().ToList();
|
||||
SetStepsCount(ProcessStorage ? modulesToProcess.Count + 1 : modulesToProcess.Count);
|
||||
var dbFactory = new DbFactory(ConfigPath);
|
||||
foreach (var module in modulesToProcess)
|
||||
@ -68,8 +68,8 @@ namespace ASC.Data.Backup.Tasks
|
||||
private void DoDeleteModule(DbFactory dbFactory, IModuleSpecifics module)
|
||||
{
|
||||
Logger.DebugFormat("begin delete data for module ({0})", module.ModuleName);
|
||||
int tablesCount = module.Tables.Count();
|
||||
int tablesProcessed = 0;
|
||||
var tablesCount = module.Tables.Count();
|
||||
var tablesProcessed = 0;
|
||||
using (var connection = dbFactory.OpenConnection())
|
||||
{
|
||||
foreach (var table in module.GetTablesOrdered().Reverse().Where(t => !IgnoredTables.Contains(t.Name)))
|
||||
@ -88,12 +88,12 @@ namespace ASC.Data.Backup.Tasks
|
||||
private void DoDeleteStorage()
|
||||
{
|
||||
Logger.Debug("begin delete storage");
|
||||
List<string> storageModules = storageFactoryConfig.GetModuleList(ConfigPath).Where(IsStorageModuleAllowed).ToList();
|
||||
int modulesProcessed = 0;
|
||||
foreach (string module in storageModules)
|
||||
var storageModules = storageFactoryConfig.GetModuleList(ConfigPath).Where(IsStorageModuleAllowed).ToList();
|
||||
var modulesProcessed = 0;
|
||||
foreach (var module in storageModules)
|
||||
{
|
||||
IDataStore storage = storageFactory.GetStorage(ConfigPath, TenantId.ToString(), module);
|
||||
List<string> domains = storageFactoryConfig.GetDomainList(ConfigPath, module).ToList();
|
||||
var storage = storageFactory.GetStorage(ConfigPath, TenantId.ToString(), module);
|
||||
var domains = storageFactoryConfig.GetDomainList(ConfigPath, module).ToList();
|
||||
foreach (var domain in domains)
|
||||
{
|
||||
ActionInvoker.Try(state => storage.DeleteFiles((string)state, "\\", "*.*", true), domain, 5,
|
||||
|
@ -236,7 +236,7 @@ namespace ASC.Data.Backup.Tasks.Modules
|
||||
{
|
||||
var strValue = Convert.ToString(value);
|
||||
|
||||
string start = GetStart(strValue);
|
||||
var start = GetStart(strValue);
|
||||
if (start == null)
|
||||
return false;
|
||||
|
||||
|
@ -56,13 +56,13 @@ namespace ASC.Data.Backup.Tasks.Modules
|
||||
{
|
||||
var notOrderedTables = new List<TableInfo>(Tables);
|
||||
|
||||
int totalTablesCount = notOrderedTables.Count;
|
||||
int orderedTablesCount = 0;
|
||||
var totalTablesCount = notOrderedTables.Count;
|
||||
var orderedTablesCount = 0;
|
||||
while (orderedTablesCount < totalTablesCount)
|
||||
{
|
||||
int orderedTablesCountBeforeIter = orderedTablesCount; // ensure we not in infinite loop...
|
||||
var orderedTablesCountBeforeIter = orderedTablesCount; // ensure we not in infinite loop...
|
||||
|
||||
int i = 0;
|
||||
var i = 0;
|
||||
while (i < notOrderedTables.Count)
|
||||
{
|
||||
var table = notOrderedTables[i];
|
||||
@ -220,7 +220,7 @@ namespace ASC.Data.Backup.Tasks.Modules
|
||||
{
|
||||
if (columnName.Equals(table.TenantColumn, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
int tenantMapping = columnMapper.GetTenantMapping();
|
||||
var tenantMapping = columnMapper.GetTenantMapping();
|
||||
if (tenantMapping < 1)
|
||||
return false;
|
||||
value = tenantMapping;
|
||||
@ -230,7 +230,7 @@ namespace ASC.Data.Backup.Tasks.Modules
|
||||
if (table.UserIDColumns.Any(x => columnName.Equals(x, StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
var strVal = Convert.ToString(value);
|
||||
string userMapping = columnMapper.GetUserMapping(strVal);
|
||||
var userMapping = columnMapper.GetUserMapping(strVal);
|
||||
if (userMapping == null)
|
||||
return helpers.IsEmptyOrSystemUser(strVal);
|
||||
value = userMapping;
|
||||
|
@ -142,7 +142,7 @@ namespace ASC.Data.Backup.Tasks
|
||||
if (!allowedStorageModules.Contains(storageModuleName))
|
||||
return false;
|
||||
|
||||
IModuleSpecifics moduleSpecifics = moduleProvider.GetByStorageModule(storageModuleName);
|
||||
var moduleSpecifics = moduleProvider.GetByStorageModule(storageModuleName);
|
||||
return moduleSpecifics == null || !IgnoredModules.Contains(moduleSpecifics.ModuleName);
|
||||
}
|
||||
|
||||
|
@ -115,15 +115,15 @@ namespace ASC.Data.Backup.Tasks
|
||||
.ToList();
|
||||
|
||||
foreach (
|
||||
IEnumerable<DataRowInfo> rows in
|
||||
var rows in
|
||||
GetRows(tableInfo, stream)
|
||||
.Skip(transactionsCommited*TransactionLength)
|
||||
.MakeParts(TransactionLength))
|
||||
{
|
||||
using (var transaction = connection.BeginTransaction())
|
||||
{
|
||||
int rowsSuccess = 0;
|
||||
foreach (DataRowInfo row in rows)
|
||||
var rowsSuccess = 0;
|
||||
foreach (var row in rows)
|
||||
{
|
||||
if (_replaceDate)
|
||||
{
|
||||
@ -182,7 +182,7 @@ namespace ASC.Data.Backup.Tasks
|
||||
|
||||
_columnMapper.Commit();
|
||||
|
||||
foreach (Tuple<RelationInfo, TableInfo> relation in lowImportanceRelations)
|
||||
foreach (var relation in lowImportanceRelations)
|
||||
{
|
||||
if (!relation.Item2.HasTenantColumn())
|
||||
{
|
||||
@ -192,8 +192,8 @@ namespace ASC.Data.Backup.Tasks
|
||||
continue;
|
||||
}
|
||||
|
||||
object oldValue = row[relation.Item1.ParentColumn];
|
||||
object newValue = _columnMapper.GetMapping(relation.Item1.ParentTable,
|
||||
var oldValue = row[relation.Item1.ParentColumn];
|
||||
var newValue = _columnMapper.GetMapping(relation.Item1.ParentTable,
|
||||
relation.Item1.ParentColumn, oldValue);
|
||||
var command = connection.CreateCommand();
|
||||
command.CommandText = string.Format("update {0} set {1} = {2} where {1} = {3} and {4} = {5}",
|
||||
@ -250,7 +250,7 @@ namespace ASC.Data.Backup.Tasks
|
||||
|
||||
public string[] ExecuteArray(DbCommand command)
|
||||
{
|
||||
List<string> list = new List<string>();
|
||||
var list = new List<string>();
|
||||
using (var result = command.ExecuteReader())
|
||||
{
|
||||
while (result.Read())
|
||||
|
@ -86,8 +86,8 @@ namespace ASC.Data.Backup.Tasks
|
||||
Logger.DebugFormat("begin transfer {0}", TenantId);
|
||||
var fromDbFactory = new DbFactory(ConfigPath);
|
||||
var toDbFactory = new DbFactory(ToConfigPath);
|
||||
string tenantAlias = GetTenantAlias(fromDbFactory);
|
||||
string backupFilePath = GetBackupFilePath(tenantAlias);
|
||||
var tenantAlias = GetTenantAlias(fromDbFactory);
|
||||
var backupFilePath = GetBackupFilePath(tenantAlias);
|
||||
var columnMapper = new ColumnMapper();
|
||||
try
|
||||
{
|
||||
@ -158,18 +158,18 @@ namespace ASC.Data.Backup.Tasks
|
||||
{
|
||||
Logger.Debug("begin transfer storage");
|
||||
var fileGroups = GetFilesToProcess(TenantId).GroupBy(file => file.Module).ToList();
|
||||
int groupsProcessed = 0;
|
||||
var groupsProcessed = 0;
|
||||
foreach (var group in fileGroups)
|
||||
{
|
||||
var baseStorage = storageFactory.GetStorage(ConfigPath, TenantId.ToString(), group.Key);
|
||||
var destStorage = storageFactory.GetStorage(ToConfigPath, columnMapper.GetTenantMapping().ToString(), group.Key);
|
||||
var utility = new CrossModuleTransferUtility(options, baseStorage, destStorage);
|
||||
|
||||
foreach (BackupFileInfo file in group)
|
||||
foreach (var file in group)
|
||||
{
|
||||
string adjustedPath = file.Path;
|
||||
var adjustedPath = file.Path;
|
||||
|
||||
IModuleSpecifics module = moduleProvider.GetByStorageModule(file.Module, file.Domain);
|
||||
var module = moduleProvider.GetByStorageModule(file.Module, file.Domain);
|
||||
if (module == null || module.TryAdjustFilePath(false, columnMapper, ref adjustedPath))
|
||||
{
|
||||
try
|
||||
|
Loading…
Reference in New Issue
Block a user