예제 #1
0
        private void TimerCallback(bool fullBackup)
		{
			if (currentTask != null)
				return;

            // we have shared lock for both incremental and full backup.
			lock (this)
			{
				if (currentTask != null)
					return;
				currentTask = Task.Factory.StartNew(async () =>
				{
					var documentDatabase = Database;
					if (documentDatabase == null)
						return;
					using (LogContext.WithDatabase(documentDatabase.Name))
					{
						try
						{
                            var dataDumper = new DataDumper(documentDatabase);
							var localBackupConfigs = exportConfigs;
							var localBackupStatus = exportStatus;
							if (localBackupConfigs == null)
								return;

                            if (fullBackup == false)
                            {
                                var currentEtags = dataDumper.FetchCurrentMaxEtags();
							// No-op if nothing has changed
                                if (currentEtags.LastDocsEtag == localBackupStatus.LastDocsEtag &&
                                    currentEtags.LastAttachmentsEtag == localBackupStatus.LastAttachmentsEtag &&
                                    currentEtags.LastDocDeleteEtag == localBackupStatus.LastDocsDeletionEtag &&
                                    currentEtags.LastAttachmentsDeleteEtag == localBackupStatus.LastAttachmentDeletionEtag)
							{
								return;
							}
                            }

							var backupPath = localBackupConfigs.LocalFolderName ??
							                 Path.Combine(documentDatabase.Configuration.DataDirectory, "PeriodicExport-Temp");
                            if (fullBackup)
                            {
                                // create filename for full dump
                                backupPath = Path.Combine(backupPath, SystemTime.UtcNow.ToString("yyyy-MM-dd-HH-mm", CultureInfo.InvariantCulture) + ".ravendb-full-dump");
                                if (File.Exists(backupPath))
							{
                                    var counter = 1;
                                    while (true)
						    {
                                        backupPath = Path.Combine(Path.GetDirectoryName(backupPath), SystemTime.UtcNow.ToString("yyyy-MM-dd-HH-mm", CultureInfo.InvariantCulture) + " - " + counter + ".ravendb-full-dump");

                                        if (File.Exists(backupPath) == false)
                                            break;
                                        counter++;
                                    }
                                }
						    }

                            var smugglerOptions = (fullBackup)
                                                      ? new SmugglerOptions()
                                                      : new SmugglerOptions
						    {
                                                          StartDocsEtag = localBackupStatus.LastDocsEtag,
                                                          StartAttachmentsEtag = localBackupStatus.LastAttachmentsEtag,
                                                          StartDocsDeletionEtag = localBackupStatus.LastDocsDeletionEtag,
                                                          StartAttachmentsDeletionEtag = localBackupStatus.LastAttachmentDeletionEtag,
                                                          Incremental = true,
                                                          ExportDeletions = true
                                                      };

                            var exportResult = await dataDumper.ExportData(new SmugglerExportOptions { ToFile = backupPath }, smugglerOptions);

                            if (fullBackup == false)
                                {
						    // No-op if nothing has changed
                                if (exportResult.LastDocsEtag == localBackupStatus.LastDocsEtag &&
                                    exportResult.LastAttachmentsEtag == localBackupStatus.LastAttachmentsEtag &&
                                    exportResult.LastDocDeleteEtag == localBackupStatus.LastDocsDeletionEtag &&
                                    exportResult.LastAttachmentsDeleteEtag == localBackupStatus.LastAttachmentDeletionEtag)
							{
                                    logger.Info(
                                        "Periodic export returned prematurely, nothing has changed since last export");
								return;
							}
                            }

							try
							{
								if (!localBackupConfigs.Disabled)
								{
									UploadToServer(exportResult.FilePath, localBackupConfigs, fullBackup);
								}
							}
							finally
							{
                                // if user did not specify local folder we delete temporary file.
                                if (String.IsNullOrEmpty(localBackupConfigs.LocalFolderName))
                                {
                                    IOExtensions.DeleteFile(exportResult.FilePath);
                                }
							}

                            if (fullBackup)
                            {
                                localBackupStatus.LastFullBackup = SystemTime.UtcNow;
                            }
                            else
                            {
                                localBackupStatus.LastAttachmentsEtag = exportResult.LastAttachmentsEtag;
                                localBackupStatus.LastDocsEtag = exportResult.LastDocsEtag;
                                localBackupStatus.LastDocsDeletionEtag = exportResult.LastDocDeleteEtag;
                                localBackupStatus.LastAttachmentDeletionEtag = exportResult.LastAttachmentsDeleteEtag;
							localBackupStatus.LastBackup = SystemTime.UtcNow;
                            }
                            

							var ravenJObject = JsonExtensions.ToJObject(localBackupStatus);
							ravenJObject.Remove("Id");
                            var putResult = documentDatabase.Documents.Put(PeriodicExportStatus.RavenDocumentKey, null, ravenJObject,
								new RavenJObject(), null);

							// this result in exportStatus being refreshed
							localBackupStatus = exportStatus;
							if (localBackupStatus != null)
							{
								if (localBackupStatus.LastDocsEtag.IncrementBy(1) == putResult.ETag) // the last etag is with just us
									localBackupStatus.LastDocsEtag = putResult.ETag; // so we can skip it for the next time
							}
						}
						catch (ObjectDisposedException)
						{
							// shutting down, probably
						}
						catch (Exception e)
						{
							logger.ErrorException("Error when performing periodic export", e);
							Database.AddAlert(new Alert
							{
								AlertLevel = AlertLevel.Error,
								CreatedAt = SystemTime.UtcNow,
								Message = e.Message,
								Title = "Error in Periodic Export",
								Exception = e.ToString(),
								UniqueKey = "Periodic Export Error",
							});
						}
					}
				})
				.Unwrap();

				currentTask.ContinueWith(_ =>
				{
					currentTask = null;
				});
			}
		}