public void Dispose() { IOExtensions.DeleteDirectory("Data"); IOExtensions.DeleteDirectory("NHibernate"); }
public override void Dispose() { IOExtensions.DeleteDirectory(path); base.Dispose(); }
public void Dispose() { IOExtensions.DeleteDirectory(path); }
public async Task MetadataIsPreserved() { using (var store = NewStore()) { var server = GetServer(); var outputDirectory = Path.Combine(server.Configuration.DataDirectory, "Export"); try { var dumper = new SmugglerFilesApi { Options = { Incremental = true } }; FileHeader originalFile; using (var session = store.OpenAsyncSession()) { session.RegisterUpload("test1.file", CreateRandomFileStream(12800)); await session.SaveChangesAsync(); // content update after a metadata change originalFile = await session.LoadFileAsync("test1.file"); originalFile.Metadata["Test"] = new RavenJValue("Value"); await session.SaveChangesAsync(); } using (new FilesStore { Url = server.Url }.Initialize()) { // now perform full backup await dumper.ExportData(new SmugglerExportOptions <FilesConnectionStringOptions> { ToFile = outputDirectory, From = new FilesConnectionStringOptions { Url = server.Url, DefaultFileSystem = store.DefaultFileSystem, } }); } await VerifyDump(store, outputDirectory, s => { using (var session = s.OpenAsyncSession()) { var file = session.LoadFileAsync("test1.file").Result; Assert.Equal(originalFile.CreationDate, file.CreationDate); Assert.Equal(originalFile.Directory, file.Directory); Assert.Equal(originalFile.Extension, file.Extension); Assert.Equal(originalFile.FullPath, file.FullPath); Assert.Equal(originalFile.Name, file.Name); Assert.Equal(originalFile.TotalSize, file.TotalSize); Assert.Equal(originalFile.UploadedSize, file.UploadedSize); Assert.Equal(originalFile.LastModified, file.LastModified); Assert.True(file.Metadata.ContainsKey("Test")); } }); } finally { IOExtensions.DeleteDirectory(outputDirectory); } } }
public override void Dispose() { base.Dispose(); IOExtensions.DeleteDirectory(BackupDir); }
private void DumpStacktrace(ZipArchive package) { var stacktraceRequsted = GetQueryStringValue("stacktrace"); if (stacktraceRequsted != null) { var stacktrace = package.CreateEntry("stacktraces.txt", CompressionLevel.Optimal); var jsonSerializer = new JsonSerializer { Formatting = Formatting.Indented }; jsonSerializer.Converters.Add(new EtagJsonConverter()); using (var stacktraceStream = stacktrace.Open()) { string ravenDebugDir = null; try { if (Debugger.IsAttached) { throw new InvalidOperationException("Cannot get stacktraces when debugger is attached"); } ravenDebugDir = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); var ravenDebugExe = Path.Combine(ravenDebugDir, "Raven.Debug.exe"); var ravenDebugOutput = Path.Combine(ravenDebugDir, "stacktraces.txt"); Directory.CreateDirectory(ravenDebugDir); if (Environment.Is64BitProcess) { ExtractResource("Raven.Database.Util.Raven.Debug.x64.Raven.Debug.exe", ravenDebugExe); } else { ExtractResource("Raven.Database.Util.Raven.Debug.x86.Raven.Debug.exe", ravenDebugExe); } var process = new Process { StartInfo = new ProcessStartInfo { Arguments = string.Format("-pid={0} /stacktrace -output={1}", Process.GetCurrentProcess().Id, ravenDebugOutput), FileName = ravenDebugExe, WindowStyle = ProcessWindowStyle.Hidden, } }; process.Start(); process.WaitForExit(); using (var stackDumpOutputStream = File.Open(ravenDebugOutput, FileMode.Open)) { stackDumpOutputStream.CopyTo(stacktraceStream); } } catch (Exception ex) { var streamWriter = new StreamWriter(stacktraceStream); jsonSerializer.Serialize(streamWriter, new { Error = "Exception occurred during getting stacktraces of the RavenDB process. Exception: " + ex }); streamWriter.Flush(); } finally { if (ravenDebugDir != null && Directory.Exists(ravenDebugDir)) { IOExtensions.DeleteDirectory(ravenDebugDir); } } stacktraceStream.Flush(); } } }
public async Task CanHandleFilesExceptionsGracefully() { using (var store = NewStore()) { var server = GetServer(); var outputDirectory = Path.Combine(server.Configuration.DataDirectory, "Export"); var alreadyReset = false; var proxyPort = 8070; var forwarder = new ProxyServer(ref proxyPort, server.Configuration.Port) { VetoTransfer = (totalRead, buffer) => { if (alreadyReset == false && totalRead > 28000) { alreadyReset = true; return(true); } return(false); } }; try { ReseedRandom(100); // Force a random distribution. await InitializeWithRandomFiles(store, 20, 30); // now perform full backup var dumper = new SmugglerFilesApi { Options = { Incremental = true } }; ExportFilesResult exportResult = null; try { // We will ensure this one will fail somewhere along the line. exportResult = await dumper.ExportData( new SmugglerExportOptions <FilesConnectionStringOptions> { ToFile = outputDirectory, From = new FilesConnectionStringOptions { Url = "http://localhost:" + proxyPort, DefaultFileSystem = store.DefaultFileSystem, } }); } catch (SmugglerExportException inner) { exportResult = new ExportFilesResult { FilePath = inner.File }; } Assert.NotNull(exportResult); Assert.True(!string.IsNullOrWhiteSpace(exportResult.FilePath)); // Continue with the incremental dump. exportResult = await dumper.ExportData( new SmugglerExportOptions <FilesConnectionStringOptions> { ToFile = outputDirectory, From = new FilesConnectionStringOptions { Url = server.Url, DefaultFileSystem = store.DefaultFileSystem, } }); // Import everything and verify all files are there. await VerifyDump(store, outputDirectory, s => { using (var session = s.OpenAsyncSession()) { var files = s.AsyncFilesCommands.BrowseAsync().Result; Assert.Equal(20, files.Count()); } }); } finally { forwarder.Dispose(); IOExtensions.DeleteDirectory(outputDirectory); } } }
public override void Dispose() { IOExtensions.DeleteDirectory("Data"); IOExtensions.DeleteDirectory("Test"); base.Dispose(); }
public async Task Execute(Action <IOperationProgress> onProgress, CompactionResult result) { if (_isCompactionInProgress) { throw new InvalidOperationException($"Database '{_database}' cannot be compacted because compaction is already in progress."); } result.AddMessage($"Started database compaction for {_database}"); onProgress?.Invoke(result.Progress); _isCompactionInProgress = true; bool done = false; string compactDirectory = null; string tmpDirectory = null; string compactTempDirectory = null; byte[] encryptionKey = null; try { var documentDatabase = await _serverStore.DatabasesLandlord.TryGetOrCreateResourceStore(_database); var configuration = _serverStore.DatabasesLandlord.CreateDatabaseConfiguration(_database); DatabaseRecord databaseRecord = documentDatabase.ReadDatabaseRecord(); // save the key before unloading the database (it is zeroed when disposing DocumentDatabase). if (documentDatabase.MasterKey != null) { encryptionKey = documentDatabase.MasterKey.ToArray(); } using (await _serverStore.DatabasesLandlord.UnloadAndLockDatabase(_database, "it is being compacted")) using (var src = DocumentsStorage.GetStorageEnvironmentOptionsFromConfiguration(configuration, new IoChangesNotifications { DisableIoMetrics = true }, new CatastrophicFailureNotification((endId, path, exception, stacktrace) => throw new InvalidOperationException($"Failed to compact database {_database} ({path}), StackTrace='{stacktrace}'", exception)))) { InitializeOptions(src, configuration, documentDatabase, encryptionKey); DirectoryExecUtils.SubscribeToOnDirectoryInitializeExec(src, configuration.Storage, documentDatabase.Name, DirectoryExecUtils.EnvironmentType.Compaction, Logger); var basePath = configuration.Core.DataDirectory.FullPath; compactDirectory = basePath + "-compacting"; tmpDirectory = basePath + "-old"; EnsureDirectoriesPermission(basePath, compactDirectory, tmpDirectory); IOExtensions.DeleteDirectory(compactDirectory); IOExtensions.DeleteDirectory(tmpDirectory); configuration.Core.DataDirectory = new PathSetting(compactDirectory); if (configuration.Storage.TempPath != null) { compactTempDirectory = configuration.Storage.TempPath.FullPath + "-temp-compacting"; EnsureDirectoriesPermission(compactTempDirectory); IOExtensions.DeleteDirectory(compactTempDirectory); configuration.Storage.TempPath = new PathSetting(compactTempDirectory); } var revisionsPrefix = CollectionName.GetTablePrefix(CollectionTableType.Revisions); var collectionsPrefix = CollectionName.GetTablePrefix(CollectionTableType.Documents); var compressedCollectionsTableNames = databaseRecord.DocumentsCompression?.Collections .Select(name => new CollectionName(name).GetTableName(CollectionTableType.Documents)) .ToHashSet(StringComparer.OrdinalIgnoreCase); using (var dst = DocumentsStorage.GetStorageEnvironmentOptionsFromConfiguration(configuration, new IoChangesNotifications { DisableIoMetrics = true }, new CatastrophicFailureNotification((envId, path, exception, stacktrace) => throw new InvalidOperationException($"Failed to compact database {_database} ({path}). StackTrace='{stacktrace}'", exception)))) { InitializeOptions(dst, configuration, documentDatabase, encryptionKey); DirectoryExecUtils.SubscribeToOnDirectoryInitializeExec(dst, configuration.Storage, documentDatabase.Name, DirectoryExecUtils.EnvironmentType.Compaction, Logger); _token.ThrowIfCancellationRequested(); StorageCompaction.Execute(src, (StorageEnvironmentOptions.DirectoryStorageEnvironmentOptions)dst, progressReport => { result.Progress.TreeProgress = progressReport.TreeProgress; result.Progress.TreeTotal = progressReport.TreeTotal; result.Progress.TreeName = progressReport.TreeName; result.Progress.GlobalProgress = progressReport.GlobalProgress; result.Progress.GlobalTotal = progressReport.GlobalTotal; result.AddMessage(progressReport.Message); onProgress?.Invoke(result.Progress); }, (name, schema) => { bool isRevision = name.StartsWith(revisionsPrefix, StringComparison.OrdinalIgnoreCase); bool isCollection = name.StartsWith(collectionsPrefix, StringComparison.OrdinalIgnoreCase); schema.Compressed = (isRevision && databaseRecord.DocumentsCompression?.CompressRevisions == true) || (isCollection && databaseRecord.DocumentsCompression?.CompressAllCollections == true) || compressedCollectionsTableNames?.Contains(name) == true; }, _token); } result.TreeName = null; _token.ThrowIfCancellationRequested(); EnsureDirectoriesPermission(basePath, compactDirectory, tmpDirectory); IOExtensions.DeleteDirectory(tmpDirectory); SwitchDatabaseDirectories(basePath, tmpDirectory, compactDirectory); done = true; } } catch (Exception e) { throw new InvalidOperationException($"Failed to execute compaction for {_database}", e); } finally { IOExtensions.DeleteDirectory(compactDirectory); if (done) { IOExtensions.DeleteDirectory(tmpDirectory); if (compactTempDirectory != null) { IOExtensions.DeleteDirectory(compactTempDirectory); } } _isCompactionInProgress = false; if (encryptionKey != null) { Sodium.ZeroBuffer(encryptionKey); } } }
public void CheckDirectoryPermissions() { if (Core.RunInMemory) { return; } Dictionary <string, KeyValuePair <string, string> > results = null; foreach (var configurationProperty in typeof(RavenConfiguration).GetProperties(BindingFlags.Instance | BindingFlags.Public)) { if (configurationProperty.PropertyType.IsSubclassOf(typeof(ConfigurationCategory)) == false) { continue; } var categoryValue = configurationProperty.GetValue(this); foreach (var categoryProperty in configurationProperty.PropertyType.GetProperties(BindingFlags.Instance | BindingFlags.Public)) { if (categoryProperty.PropertyType != typeof(PathSetting)) { continue; } var pathSettingValue = categoryProperty.GetValue(categoryValue) as PathSetting; if (pathSettingValue == null) { continue; } var readOnly = categoryProperty.GetCustomAttribute <ReadOnlyPathAttribute>(); if (readOnly != null) { continue; } var fileName = Guid.NewGuid().ToString("N"); var path = pathSettingValue.ToFullPath(); var fullPath = Path.Combine(path, fileName); var configEntry = categoryProperty.GetCustomAttributes <ConfigurationEntryAttribute>() .OrderBy(x => x.Order) .First(); if (configEntry.Scope == ConfigurationEntryScope.ServerWideOnly && ResourceType == ResourceType.Database) { continue; } var configurationKey = configEntry.Key; string createdDirectory = null; try { // if there is no 'path' directory, we are going to create a directory with a similar name, in order to avoid deleting a directory in use afterwards, // and write a sample file inside it, in order to check write permissions. if (Directory.Exists(path) == false) { var curPathCounterVal = Interlocked.Increment(ref _pathCounter); // test that we can create the directory, but // not actually create it createdDirectory = path + "$" + curPathCounterVal.ToString(); Directory.CreateDirectory(createdDirectory); var createdFile = Path.Combine(createdDirectory, "test.file"); File.WriteAllText(createdFile, string.Empty); File.Delete(createdFile); } // in case there is a 'path' directory, we are going to try and write to it some file, in order to check write permissions else { File.WriteAllText(fullPath, string.Empty); File.Delete(fullPath); } } catch (Exception e) { if (results == null) { results = new Dictionary <string, KeyValuePair <string, string> >(); } var errorousDirPath = createdDirectory ?? path; results[configurationKey] = new KeyValuePair <string, string>(errorousDirPath, e.Message); } finally { if (createdDirectory != null) { Interlocked.Decrement(ref _pathCounter); IOExtensions.DeleteDirectory(createdDirectory); } } } } if (results == null || results.Count == 0) { return; } var sb = new StringBuilder("Could not access some of the specified paths. Please check if you have sufficient privileges to access following paths:"); sb.Append(Environment.NewLine); foreach (var result in results) { sb.AppendLine($"Key: '{result.Key}' Path: '{result.Value.Key}' Error: '{result.Value.Value}'"); } throw new InvalidOperationException(sb.ToString()); }
protected void ClearDatabaseDirectory() { IOExtensions.DeleteDirectory(DbName); IOExtensions.DeleteDirectory(DbDirectory); }
private async Task RunPeriodicExport(bool fullExport) { if (_cancellationToken.IsCancellationRequested) { return; } try { DocumentsOperationContext context; using (_database.DocumentsStorage.ContextPool.AllocateOperationContext(out context)) { var sp = Stopwatch.StartNew(); using (var tx = context.OpenReadTransaction()) { var exportDirectory = _configuration.LocalFolderName ?? Path.Combine(_database.Configuration.Core.DataDirectory, "PeriodicExport-Temp"); if (Directory.Exists(exportDirectory) == false) { Directory.CreateDirectory(exportDirectory); } var now = SystemTime.UtcNow.ToString("yyyy-MM-dd-HH-mm", CultureInfo.InvariantCulture); if (_status.LastFullExportDirectory == null || IsDirectoryExistsOrContainsFiles() == false || fullExport) { fullExport = true; _status.LastFullExportDirectory = Path.Combine(exportDirectory, $"{now}.ravendb-{_database.Name}-backup"); Directory.CreateDirectory(_status.LastFullExportDirectory); } if (_logger.IsInfoEnabled) { _logger.Info($"Exporting a {(fullExport ? "full" : "incremental")} export"); } if (fullExport == false) { var currentLastEtag = DocumentsStorage.ReadLastEtag(tx.InnerTransaction); // No-op if nothing has changed if (currentLastEtag == _status.LastDocsEtag) { return; } } var dataExporter = new SmugglerExporter(_database) { Options = new DatabaseSmugglerOptions { RevisionDocumentsLimit = _exportLimit } }; string exportFilePath; string fileName; if (fullExport) { // create filename for full export fileName = $"{now}.ravendb-full-export"; exportFilePath = Path.Combine(_status.LastFullExportDirectory, fileName); if (File.Exists(exportFilePath)) { var counter = 1; while (true) { fileName = $"{now} - {counter}.${Constants.PeriodicExport.FullExportExtension}"; exportFilePath = Path.Combine(_status.LastFullExportDirectory, fileName); if (File.Exists(exportFilePath) == false) { break; } counter++; } } } else { // create filename for incremental export fileName = $"{now}-0.${Constants.PeriodicExport.IncrementalExportExtension}"; exportFilePath = Path.Combine(_status.LastFullExportDirectory, fileName); if (File.Exists(exportFilePath)) { var counter = 1; while (true) { fileName = $"{now}-{counter}.${Constants.PeriodicExport.IncrementalExportExtension}"; exportFilePath = Path.Combine(_status.LastFullExportDirectory, fileName); if (File.Exists(exportFilePath) == false) { break; } counter++; } } dataExporter.StartDocsEtag = _status.LastDocsEtag; if (dataExporter.StartDocsEtag == null) { IncrementalExport.ReadLastEtagsFromFile(_status.LastFullExportDirectory, context, dataExporter); } } var exportResult = dataExporter.Export(context, exportFilePath); if (fullExport == false) { // No-op if nothing has changed if (exportResult.LastDocsEtag == _status.LastDocsEtag) { if (_logger.IsInfoEnabled) { _logger.Info("Periodic export returned prematurely, nothing has changed since last export"); } return; } } try { await UploadToServer(exportFilePath, fileName, fullExport); } finally { // if user did not specify local folder we delete temporary file. if (string.IsNullOrEmpty(_configuration.LocalFolderName)) { IOExtensions.DeleteFile(exportFilePath); } } _status.LastDocsEtag = exportResult.LastDocsEtag; if (fullExport) { _status.LastFullExportAt = SystemTime.UtcNow; } else { _status.LastExportAt = SystemTime.UtcNow; } WriteStatus(); } if (_logger.IsInfoEnabled) { _logger.Info($"Successfully exported {(fullExport ? "full" : "incremental")} export in {sp.ElapsedMilliseconds:#,#;;0} ms."); } _exportLimit = null; } } catch (OperationCanceledException) { // shutting down, probably } catch (ObjectDisposedException) { // shutting down, probably } catch (Exception e) { _exportLimit = 100; if (_logger.IsOperationsEnabled) { _logger.Operations("Error when performing periodic export", e); } _database.Alerts.AddAlert(new Alert { Type = AlertType.PeriodicExport, Message = "Error in Periodic Export", CreatedAt = SystemTime.UtcNow, Severity = AlertSeverity.Error, Content = new ExceptionAlertContent { Message = e.Message, Exception = e.ToString() } }); } }
public async Task CanHandleAttachmentExceptionsGracefully_Smuggler() { var backupPath = NewDataPath("BackupFolder"); var server = GetNewServer(); int allowDownload = 0; var port = 8070; var forwarder = new ProxyServer(ref port, 8079) { VetoTransfer = (totalRead, buffer) => { var payload = System.Text.Encoding.UTF8.GetString(buffer.Array, buffer.Offset, buffer.Count); return(payload.Contains("GET /static/users/678 ") && Thread.VolatileRead(ref allowDownload) == 0); } }; try { string databaseName; using (var store = new DocumentStore { Url = "http://localhost:8079" }) { databaseName = store.DefaultDatabase; store.Initialize(); InsertAttachments(store, 2000); } var dumper = new SmugglerDatabaseApi { Options = { Limit = 1500, Incremental = true } }; var allAttachments = new List <RavenJObject>(); OperationState exportResult = null; try { exportResult = dumper.ExportData(new SmugglerExportOptions <RavenConnectionStringOptions> { ToFile = backupPath, From = new RavenConnectionStringOptions { Url = "http://localhost:" + port, DefaultDatabase = databaseName, } }).Result; Assert.False(true, "Previous op should throw."); } catch (AggregateException e) { var extractSingleInnerException = e.ExtractSingleInnerException() as SmugglerExportException; if (extractSingleInnerException == null) { throw; } var inner = extractSingleInnerException; exportResult = new OperationState { FilePath = inner.File }; } Interlocked.Increment(ref allowDownload); using (var fileStream = new FileStream(exportResult.FilePath, FileMode.Open)) using (var stream = new GZipStream(fileStream, CompressionMode.Decompress)) { var chunk1 = RavenJToken.TryLoad(stream) as RavenJObject; var att1 = chunk1["Attachments"] as RavenJArray; allAttachments.AddRange(att1.Values <RavenJObject>()); } exportResult = await dumper.ExportData(new SmugglerExportOptions <RavenConnectionStringOptions> { ToFile = backupPath, From = new RavenConnectionStringOptions { Url = "http://localhost:8070", DefaultDatabase = databaseName, } }); using (var fileStream = new FileStream(exportResult.FilePath, FileMode.Open)) using (var stream = new GZipStream(fileStream, CompressionMode.Decompress)) { var chunk2 = RavenJToken.TryLoad(stream) as RavenJObject; var attr2 = chunk2["Attachments"] as RavenJArray; allAttachments.AddRange(attr2.Values <RavenJObject>()); } Assert.Equal(2000, allAttachments.Count()); } finally { IOExtensions.DeleteDirectory(backupPath); forwarder.Dispose(); server.Dispose(); } }
public async Task CanHandleDocumentExceptionsGracefully_Smuggler() { var backupPath = NewDataPath("BackupFolder"); var server = GetNewServer(databaseName: Constants.SystemDatabase); var alreadyReset = false; var port = 8070; var forwarder = new ProxyServer(ref port, 8079) { VetoTransfer = (totalRead, buffer) => { if (alreadyReset == false && totalRead > 25000) { alreadyReset = true; return(true); } return(false); } }; try { string databaseName; using (var store = new DocumentStore { Url = "http://localhost:8079" }) { databaseName = store.DefaultDatabase; store.Initialize(); InsertUsers(store, 0, 2000); } var dumper = new SmugglerDatabaseApi { Options = { Limit = 1900, Incremental = true } }; var allDocs = new List <RavenJObject>(); OperationState exportResult = null; try { exportResult = await dumper.ExportData(new SmugglerExportOptions <RavenConnectionStringOptions> { ToFile = backupPath, From = new RavenConnectionStringOptions { Url = "http://localhost:" + port, DefaultDatabase = databaseName, } }); Assert.False(true, "Previous op should throw."); } catch (SmugglerExportException e) { exportResult = new OperationState { FilePath = e.File }; } using (var fileSteam = new FileStream(exportResult.FilePath, FileMode.Open)) using (var stream = new GZipStream(fileSteam, CompressionMode.Decompress)) { var chunk1 = RavenJToken.TryLoad(stream) as RavenJObject; var doc1 = chunk1["Docs"] as RavenJArray; allDocs.AddRange(doc1.Values <RavenJObject>()); } exportResult = await dumper.ExportData(new SmugglerExportOptions <RavenConnectionStringOptions> { ToFile = backupPath, From = new RavenConnectionStringOptions { Url = "http://localhost:8070", DefaultDatabase = databaseName, } }); using (var fileStream = new FileStream(exportResult.FilePath, FileMode.Open)) using (var stream = new GZipStream(fileStream, CompressionMode.Decompress)) { var chunk2 = RavenJToken.TryLoad(stream) as RavenJObject; var doc2 = chunk2["Docs"] as RavenJArray; allDocs.AddRange(doc2.Values <RavenJObject>()); } Assert.Equal(2000, allDocs.Count(d => (d.Value <string>("Name") ?? String.Empty).StartsWith("User"))); } finally { forwarder.Dispose(); server.Dispose(); IOExtensions.DeleteDirectory(backupPath); } }
public async Task <IOperationResult> Execute(Action <IOperationProgress> onProgress) { var databaseName = _restoreConfiguration.DatabaseName; var result = new RestoreResult { DataDirectory = _restoreConfiguration.DataDirectory }; try { if (onProgress == null) { onProgress = _ => { } } ; Stopwatch sw = null; RestoreSettings restoreSettings = null; var firstFile = _filesToRestore[0]; var lastFile = _filesToRestore.Last(); var extension = Path.GetExtension(firstFile); var snapshotRestore = false; if (extension == Constants.Documents.PeriodicBackup.SnapshotExtension) { onProgress.Invoke(result.Progress); snapshotRestore = true; sw = Stopwatch.StartNew(); // restore the snapshot restoreSettings = SnapshotRestore(firstFile, _restoreConfiguration.DataDirectory, onProgress, result); if (restoreSettings != null && _restoreConfiguration.SkipIndexes) { // remove all indexes from the database record restoreSettings.DatabaseRecord.AutoIndexes = null; restoreSettings.DatabaseRecord.Indexes = null; } // removing the snapshot from the list of files _filesToRestore.RemoveAt(0); } else { result.SnapshotRestore.Skipped = true; result.SnapshotRestore.Processed = true; onProgress.Invoke(result.Progress); } if (restoreSettings == null) { restoreSettings = new RestoreSettings { DatabaseRecord = new DatabaseRecord(databaseName) { // we only have a smuggler restore // use the encryption key to encrypt the database Encrypted = _hasEncryptionKey } }; DatabaseHelper.Validate(databaseName, restoreSettings.DatabaseRecord, _serverStore.Configuration); } var databaseRecord = restoreSettings.DatabaseRecord; if (databaseRecord.Settings == null) { databaseRecord.Settings = new Dictionary <string, string>(); } var runInMemoryConfigurationKey = RavenConfiguration.GetKey(x => x.Core.RunInMemory); databaseRecord.Settings.Remove(runInMemoryConfigurationKey); if (_serverStore.Configuration.Core.RunInMemory) { databaseRecord.Settings[runInMemoryConfigurationKey] = "false"; } var dataDirectoryConfigurationKey = RavenConfiguration.GetKey(x => x.Core.DataDirectory); databaseRecord.Settings.Remove(dataDirectoryConfigurationKey); // removing because we want to restore to given location, not to serialized in backup one if (_restoringToDefaultDataDirectory == false) { databaseRecord.Settings[dataDirectoryConfigurationKey] = _restoreConfiguration.DataDirectory; } if (_hasEncryptionKey) { // save the encryption key so we'll be able to access the database _serverStore.PutSecretKey(_restoreConfiguration.EncryptionKey, databaseName, overwrite: false); } var addToInitLog = new Action <string>(txt => // init log is not save in mem during RestoreBackup { var msg = $"[RestoreBackup] {DateTime.UtcNow} :: Database '{databaseName}' : {txt}"; if (Logger.IsInfoEnabled) { Logger.Info(msg); } }); var configuration = _serverStore .DatabasesLandlord .CreateDatabaseConfiguration(databaseName, ignoreDisabledDatabase: true, ignoreBeenDeleted: true, ignoreNotRelevant: true, databaseRecord); using (var database = new DocumentDatabase(databaseName, configuration, _serverStore, addToInitLog)) { // smuggler needs an existing document database to operate var options = InitializeOptions.SkipLoadingDatabaseRecord; if (snapshotRestore) { options |= InitializeOptions.GenerateNewDatabaseId; } database.Initialize(options); if (snapshotRestore) { result.SnapshotRestore.Processed = true; var summary = database.GetDatabaseSummary(); result.Documents.ReadCount += summary.DocumentsCount; result.Documents.Attachments.ReadCount += summary.AttachmentsCount; result.Counters.ReadCount += summary.CountersCount; result.RevisionDocuments.ReadCount += summary.RevisionsCount; result.Conflicts.ReadCount += summary.ConflictsCount; result.Indexes.ReadCount += databaseRecord.GetIndexesCount(); result.AddInfo($"Successfully restored {result.SnapshotRestore.ReadCount} " + $"files during snapshot restore, took: {sw.ElapsedMilliseconds:#,#;;0}ms"); onProgress.Invoke(result.Progress); } using (database.DocumentsStorage.ContextPool.AllocateOperationContext(out DocumentsOperationContext context)) { SmugglerRestore(_restoreConfiguration.BackupLocation, database, context, databaseRecord, onProgress, result); result.DatabaseRecord.Processed = true; result.Documents.Processed = true; result.RevisionDocuments.Processed = true; result.Conflicts.Processed = true; result.Indexes.Processed = true; result.Counters.Processed = true; onProgress.Invoke(result.Progress); databaseRecord.Topology = new DatabaseTopology(); // restoring to the current node only databaseRecord.Topology.Members.Add(_nodeTag); databaseRecord.Disabled = true; // we are currently restoring, shouldn't try to access it _serverStore.EnsureNotPassive(); DisableOngoingTasksIfNeeded(databaseRecord); var(index, _) = await _serverStore.WriteDatabaseRecordAsync(databaseName, databaseRecord, null, restoreSettings.DatabaseValues, isRestore : true); await _serverStore.Cluster.WaitForIndexNotification(index); // restore identities & cmpXchg values RestoreFromLastFile(onProgress, database, lastFile, context, result); } } // after the db for restore is done, we can safely set the db status to active databaseRecord = _serverStore.LoadDatabaseRecord(databaseName, out _); databaseRecord.Disabled = false; var(updateIndex, _) = await _serverStore.WriteDatabaseRecordAsync(databaseName, databaseRecord, null); await _serverStore.Cluster.WaitForIndexNotification(updateIndex); if (databaseRecord.Topology.RelevantFor(_serverStore.NodeTag)) { // we need to wait for the database record change to be propagated properly var db = await _serverStore.DatabasesLandlord.TryGetOrCreateResourceStore(databaseName); await db.RachisLogIndexNotifications.WaitForIndexNotification(updateIndex, _operationCancelToken.Token); } return(result); } catch (Exception e) { if (Logger.IsOperationsEnabled) { Logger.Operations("Failed to restore database", e); } var alert = AlertRaised.Create( _restoreConfiguration.DatabaseName, "Failed to restore database", $"Could not restore database named {_restoreConfiguration.DatabaseName}", AlertType.RestoreError, NotificationSeverity.Error, details: new ExceptionDetails(e)); _serverStore.NotificationCenter.Add(alert); if (_serverStore.LoadDatabaseRecord(_restoreConfiguration.DatabaseName, out var _) == null) { // delete any files that we already created during the restore IOExtensions.DeleteDirectory(_restoreConfiguration.DataDirectory); } else { var deleteResult = await _serverStore.DeleteDatabaseAsync(_restoreConfiguration.DatabaseName, true, new[] { _serverStore.NodeTag }); await _serverStore.Cluster.WaitForIndexNotification(deleteResult.Index); } result.AddError($"Error occurred during restore of database {databaseName}. Exception: {e.Message}"); onProgress.Invoke(result.Progress); throw; } finally { _operationCancelToken.Dispose(); } }
public void AfterFailedRestoreOfIndex_ShouldGenerateWarningAndResetIt() { using (var db = new DocumentDatabase(new RavenConfiguration { DataDirectory = DataDir, RunInUnreliableYetFastModeThatIsNotSuitableForProduction = false, Settings = { { "Raven/Esent/CircularLog", "false" } } })) { db.SpinBackgroundWorkers(); db.PutIndex(new RavenDocumentsByEntityName().IndexName, new RavenDocumentsByEntityName().CreateIndexDefinition()); db.Put("users/1", null, RavenJObject.Parse("{'Name':'Arek'}"), RavenJObject.Parse("{'Raven-Entity-Name':'Users'}"), null); db.Put("users/2", null, RavenJObject.Parse("{'Name':'David'}"), RavenJObject.Parse("{'Raven-Entity-Name':'Users'}"), null); WaitForIndexing(db); db.StartBackup(BackupDir, false, new DatabaseDocument()); WaitForBackup(db, true); db.Put("users/3", null, RavenJObject.Parse("{'Name':'Daniel'}"), RavenJObject.Parse("{'Raven-Entity-Name':'Users'}"), null); WaitForIndexing(db); db.StartBackup(BackupDir, true, new DatabaseDocument()); WaitForBackup(db, true); } IOExtensions.DeleteDirectory(DataDir); var incrementalDirectories = Directory.GetDirectories(BackupDir, "Inc*"); // delete 'index-files.required-for-index-restore' to make backup corrupted according to the reported error File.Delete(Path.Combine(incrementalDirectories.First(), "Indexes\\Raven%2fDocumentsByEntityName\\index-files.required-for-index-restore")); var sb = new StringBuilder(); DocumentDatabase.Restore(new RavenConfiguration(), BackupDir, DataDir, s => sb.Append(s), defrag: true); Assert.Contains( "Error: Index Raven%2fDocumentsByEntityName could not be restored. All already copied index files was deleted." + " Index will be recreated after launching Raven instance", sb.ToString()); using (var db = new DocumentDatabase(new RavenConfiguration { DataDirectory = DataDir })) { db.SpinBackgroundWorkers(); QueryResult queryResult; do { queryResult = db.Query("Raven/DocumentsByEntityName", new IndexQuery { Query = "Tag:[[Users]]", PageSize = 10 }, CancellationToken.None); } while (queryResult.IsStale); Assert.Equal(3, queryResult.Results.Count); } }
public void Dispose() { transactionalStorage.Dispose(); IOExtensions.DeleteDirectory("test"); }
public async Task can_export_all_documents() { var backupPath = Path.Combine(NewDataPath(forceCreateDir: true), "export.dump"); try { using (var store = GetDocumentStore()) { using (var commands = store.Commands()) { for (var i = 0; i < 1000; i++) { commands.Put("users/" + (i + 1), null, new { Name = "test #" + i }, new Dictionary <string, object> { { Constants.Documents.Metadata.Collection, "Users" } }); } } var task1 = Task.Run(async() => { // now perform full backup await store.Smuggler.ExportAsync(new DatabaseSmugglerExportOptions(), backupPath); }); var task2 = Task.Run(() => { // change the one document, this document should be exported (any version of it) for (var i = 0; i < 100; i++) { using (var session = store.OpenSession()) { var user = session.Load <User>("users/1000"); user.Name = "test" + i; session.SaveChanges(); } } }); await Task.WhenAll(task1, task2); } using (var store = GetDocumentStore()) { // import all the data await store.Smuggler.ImportAsync(new DatabaseSmugglerImportOptions(), backupPath); using (var session = store.OpenSession()) { var user = session.Load <User>("users/1000"); //the document should exist in the export (any version of it) Assert.NotNull(user); var list = session.Query <User>() .Customize(x => x.WaitForNonStaleResults()) .Take(1024) .ToList(); Assert.Equal(1000, list.Count); } var stats = store.Maintenance.Send(new GetStatisticsOperation()); Assert.Equal(1000, stats.CountOfDocuments); } } finally { IOExtensions.DeleteDirectory(backupPath); } }
public async Task Execute(Action <IOperationProgress> onProgress, CompactionResult result) { if (_isCompactionInProgress) { throw new InvalidOperationException($"Database '{_database}' cannot be compacted because compaction is already in progress."); } result.AddMessage($"Started database compaction for {_database}"); onProgress?.Invoke(result); _isCompactionInProgress = true; bool done = false; string compactDirectory = null; string tmpDirectory = null; try { var documentDatabase = await _serverStore.DatabasesLandlord.TryGetOrCreateResourceStore(_database); var configuration = _serverStore.DatabasesLandlord.CreateDatabaseConfiguration(_database); using (await _serverStore.DatabasesLandlord.UnloadAndLockDatabase(_database, "it is being compacted")) using (var src = DocumentsStorage.GetStorageEnvironmentOptionsFromConfiguration(configuration, new IoChangesNotifications(), new CatastrophicFailureNotification((endId, path, exception) => throw new InvalidOperationException($"Failed to compact database {_database} ({path})", exception)))) { InitializeOptions(src, configuration, documentDatabase); DirectoryExecUtils.SubscribeToOnDirectoryExec(src, configuration.Storage, documentDatabase.Name, DirectoryExecUtils.EnvironmentType.Compaction, Logger); var basePath = configuration.Core.DataDirectory.FullPath; compactDirectory = basePath + "-compacting"; tmpDirectory = basePath + "-old"; EnsureDirectoriesPermission(basePath, compactDirectory, tmpDirectory); IOExtensions.DeleteDirectory(compactDirectory); IOExtensions.DeleteDirectory(tmpDirectory); configuration.Core.DataDirectory = new PathSetting(compactDirectory); using (var dst = DocumentsStorage.GetStorageEnvironmentOptionsFromConfiguration(configuration, new IoChangesNotifications(), new CatastrophicFailureNotification((envId, path, exception) => throw new InvalidOperationException($"Failed to compact database {_database} ({path})", exception)))) { InitializeOptions(dst, configuration, documentDatabase); DirectoryExecUtils.SubscribeToOnDirectoryExec(dst, configuration.Storage, documentDatabase.Name, DirectoryExecUtils.EnvironmentType.Compaction, Logger); _token.ThrowIfCancellationRequested(); StorageCompaction.Execute(src, (StorageEnvironmentOptions.DirectoryStorageEnvironmentOptions)dst, progressReport => { result.Progress.TreeProgress = progressReport.TreeProgress; result.Progress.TreeTotal = progressReport.TreeTotal; result.Progress.TreeName = progressReport.TreeName; result.Progress.GlobalProgress = progressReport.GlobalProgress; result.Progress.GlobalTotal = progressReport.GlobalTotal; result.AddMessage(progressReport.Message); onProgress?.Invoke(result); }, _token); } result.TreeName = null; _token.ThrowIfCancellationRequested(); EnsureDirectoriesPermission(basePath, compactDirectory, tmpDirectory); IOExtensions.DeleteDirectory(tmpDirectory); SwitchDatabaseDirectories(basePath, tmpDirectory, compactDirectory); done = true; } } catch (Exception e) { throw new InvalidOperationException($"Failed to execute compaction for {_database}", e); } finally { IOExtensions.DeleteDirectory(compactDirectory); if (done) { IOExtensions.DeleteDirectory(tmpDirectory); } _isCompactionInProgress = false; } }
public RavenDB_1041() { IOExtensions.DeleteDirectory("Database #0"); IOExtensions.DeleteDirectory("Database #1"); IOExtensions.DeleteDirectory("Database #2"); }
public async Task ContentIsPreserved_MultipleDirectories() { using (var store = NewStore()) { ReseedRandom(100); // Force a random distribution. var server = GetServer(); var outputDirectory = Path.Combine(server.Configuration.DataDirectory, "Export"); try { var dumper = new SmugglerFilesApi { Options = { Incremental = false } }; var files = new Stream[10]; using (var session = store.OpenAsyncSession()) { for (int i = 0; i < files.Length; i++) { files[i] = CreateRandomFileStream(100 * i + 12); session.RegisterUpload(i + "/test.file", files[i]); } await session.SaveChangesAsync(); } ExportFilesResult result; using (new FilesStore { Url = server.Url }.Initialize()) { // now perform full backup result = await dumper.ExportData(new SmugglerExportOptions <FilesConnectionStringOptions> { ToFile = outputDirectory, From = new FilesConnectionStringOptions { Url = server.Url, DefaultFileSystem = store.DefaultFileSystem, } }); } await VerifyDump(store, result.FilePath, s => { for (int i = 0; i < files.Length; i++) { using (var session = s.OpenAsyncSession()) { var file = session.LoadFileAsync(i + "/test.file").Result; var stream = session.DownloadAsync(file).Result; files[i].Position = 0; Assert.Equal(files[i].GetMD5Hash(), stream.GetMD5Hash()); } } }); } finally { IOExtensions.DeleteDirectory(outputDirectory); } } }
private static void AddTwitterFilesToProject() { string _twitterNativeFolder = AssetsUtility.AssetPathToAbsolutePath(kRelativePathToTwitterNativeFiles); string _twitterConfileFile = Path.Combine(_twitterNativeFolder, "Config.txt"); // Re move the files if version has changed if (File.Exists(_twitterConfileFile)) { string _fileVersion = File.ReadAllText(_twitterConfileFile); if (string.Compare(_fileVersion, EditorPrefs.GetString(kTwitterConfigKey, "0")) == 0) { return; } EditorPrefs.SetString(kTwitterConfigKey, _fileVersion); } // Start moving files and framework string _projectPath = AssetsUtility.GetProjectPath(); string _twitterExternalFolder = Path.Combine(_projectPath, kExtenalFolderRelativePath + "/Twitter"); if (Directory.Exists(_twitterExternalFolder)) { Directory.Delete(_twitterExternalFolder, true); } Directory.CreateDirectory(_twitterExternalFolder); List <string> _twitterFilesList = new List <string>(); List <string> _twitterFolderList = new List <string>(); // *********************** // Source code section // *********************** string _nativeCodeSourceFolder = Path.Combine(_twitterNativeFolder, "Source"); string _nativeCodeDestFolder = Path.Combine(_twitterExternalFolder, "Source"); // Copying folder IOExtensions.CopyFilesRecursively(_nativeCodeSourceFolder, _nativeCodeDestFolder); // Adding source folder to modifier _twitterFolderList.Add("Twitter/Source:-fno-objc-arc"); // *********************** // Framework Section // *********************** string[] _zippedFrameworkFiles = Directory.GetFiles(_twitterNativeFolder, "*.gz", SearchOption.AllDirectories); string _destFrameworkFolder = Path.Combine(_twitterExternalFolder, "Framework"); if (!Directory.Exists(_destFrameworkFolder)) { Directory.CreateDirectory(_destFrameworkFolder); } // Iterate through each zip files foreach (string _curZippedFile in _zippedFrameworkFiles) { Zip.DecompressToDirectory(_curZippedFile, _destFrameworkFolder); // Adding file to modifier _twitterFilesList.Add("Twitter/Framework/" + Path.GetFileNameWithoutExtension(_curZippedFile)); } // *********************** // Xcode modifier Section // *********************** Dictionary <string, object> _xcodeModDict = new Dictionary <string, object>(); _xcodeModDict["group"] = "NativePlugins-Twitter"; _xcodeModDict["libs"] = new string[0]; _xcodeModDict["frameworks"] = new string[] { "Accounts.framework:weak", "Social.framework:weak" }; _xcodeModDict["headerpaths"] = new string[0]; _xcodeModDict["files"] = _twitterFilesList; _xcodeModDict["folders"] = _twitterFolderList; _xcodeModDict["excludes"] = new string[] { "^.*.meta$", "^.*.mdown$", "^.*.pdf$", "^.*.DS_Store" }; _xcodeModDict["compiler_flags"] = new string[0]; _xcodeModDict["linker_flags"] = new string[0]; File.WriteAllText(GetTwitterXcodeModFilePath(), _xcodeModDict.ToJSON()); }
public SmugglerApiTests() { NonAdminHttp.EnsureCanListenToWhenInNonAdminContext(Port1); NonAdminHttp.EnsureCanListenToWhenInNonAdminContext(Port2); IOExtensions.DeleteDirectory(BackupDir); }
public IncrementalBackupTest() { IOExtensions.DeleteDirectory(BackupDir); }
public async Task Smuggler_filtering_next_etag_incremental_export_to_file() { using (var server = GetNewServer()) { var file = Path.Combine(NewDataPath(), "Incremental"); IOExtensions.DeleteDirectory(file); using (var store = new DocumentStore { Url = server.SystemDatabase.Configuration.ServerUrl }.Initialize()) { store .DatabaseCommands .GlobalAdmin .CreateDatabase(new DatabaseDocument { Id = "Dba1", Settings = { { "Raven/DataDir", "Dba1" } } }); store.DatabaseCommands.EnsureDatabaseExists("Dba1"); } using (var store1 = new DocumentStore { Url = server.SystemDatabase.Configuration.ServerUrl, DefaultDatabase = "Dba1" }.Initialize()) { StoreWorkerseDba1(store1); using (var session = store1.OpenSession()) { var workers = session.Query <Worker>().ToList(); Assert.Equal(3, workers.Count); var index1 = store1.DatabaseCommands.GetIndex("WorkerByName"); var index2 = store1.DatabaseCommands.GetIndex("WorkerByAge"); var index3 = store1.DatabaseCommands.GetIndex("WorkerAccountNumber"); Assert.Equal("WorkerByName", index1.Name); Assert.Equal("WorkerByAge", index2.Name); Assert.Equal("WorkerAccountNumber", index3.Name); } } SmugglerDatabaseApi smugglerApi = new SmugglerDatabaseApi(new SmugglerDatabaseOptions { OperateOnTypes = ItemType.Documents | ItemType.Indexes, Incremental = true }); smugglerApi.Options.Filters.Add(new FilterSetting { Path = "Name", ShouldMatch = true, Values = { "worker/21", "worker/33" } }); await smugglerApi.ExportData( new SmugglerExportOptions <RavenConnectionStringOptions> { ToFile = file, From = new RavenConnectionStringOptions { Url = server.SystemDatabase.Configuration.ServerUrl, DefaultDatabase = "Dba1" } }); //check file after first export using (var store1 = new DocumentStore { Url = server.SystemDatabase.Configuration.ServerUrl, DefaultDatabase = "Dba1" }.Initialize()) { StoreWorkerseDba1(store1); } //Second time Export smugglerApi = new SmugglerDatabaseApi(new SmugglerDatabaseOptions { OperateOnTypes = ItemType.Documents | ItemType.Indexes, Incremental = true }); smugglerApi.Options.Filters.Add(new FilterSetting { Path = "Name", ShouldMatch = true, Values = { "worker/21", "worker/33" } }); await smugglerApi.ExportData( new SmugglerExportOptions <RavenConnectionStringOptions> { ToFile = file, From = new RavenConnectionStringOptions { Url = server.SystemDatabase.Configuration.ServerUrl, DefaultDatabase = "Dba1" } }); using (var store2 = new DocumentStore { Url = server.SystemDatabase.Configuration.ServerUrl, DefaultDatabase = "Dba2" }.Initialize()) { smugglerApi = new SmugglerDatabaseApi(new SmugglerDatabaseOptions { OperateOnTypes = ItemType.Documents | ItemType.Indexes, Incremental = true }); await smugglerApi.ImportData(new SmugglerImportOptions <RavenConnectionStringOptions> { FromFile = file, To = new RavenConnectionStringOptions { Url = server.SystemDatabase.Configuration.ServerUrl, DefaultDatabase = "Dba2" } }); using (var session = store2.OpenSession()) { var workers = session.Query <Worker>().ToList(); Assert.Equal(0, workers.Count); } } } }
private InternalBackupResult CreateLocalBackupOrSnapshot(PeriodicBackupStatus status, string backupFilePath, long?startDocumentEtag, long?startRaftIndex) { var internalBackupResult = new InternalBackupResult(); using (status.LocalBackup.UpdateStats(_isFullBackup)) { // will rename the file after the backup is finished var tempBackupFilePath = backupFilePath + InProgressExtension; try { BackupTypeValidation(); AddInfo($"Started {GetBackupDescription(_configuration.BackupType, _isFullBackup)}"); if (_configuration.BackupType == BackupType.Backup || _configuration.BackupType == BackupType.Snapshot && _isFullBackup == false) { // smuggler backup var options = new DatabaseSmugglerOptionsServerSide { AuthorizationStatus = AuthorizationStatus.DatabaseAdmin, IncludeArtificial = true // we want to include artificial in backup }; options.OperateOnTypes |= DatabaseItemType.Tombstones; options.OperateOnTypes |= DatabaseItemType.CompareExchangeTombstones; var currentBackupResult = CreateBackup(options, tempBackupFilePath, startDocumentEtag, startRaftIndex); if (_isFullBackup) { internalBackupResult = currentBackupResult; } else { if (_backupResult.GetLastEtag() == _previousBackupStatus.LastEtag && _backupResult.GetLastRaftIndex() == _previousBackupStatus.LastRaftIndex.LastEtag) { internalBackupResult.LastDocumentEtag = startDocumentEtag ?? 0; internalBackupResult.LastDatabaseChangeVector = _previousBackupStatus.LastDatabaseChangeVector; internalBackupResult.LastRaftIndex = startRaftIndex ?? 0; } else { internalBackupResult = currentBackupResult; } } } else { // snapshot backup ValidateFreeSpaceForSnapshot(tempBackupFilePath); (internalBackupResult.LastDocumentEtag, internalBackupResult.LastDatabaseChangeVector) = _database.ReadLastEtagAndChangeVector(); internalBackupResult.LastRaftIndex = GetDatabaseEtagForBackup(); var databaseSummary = _database.GetDatabaseSummary(); var indexesCount = _database.IndexStore.Count; var totalSw = Stopwatch.StartNew(); var sw = Stopwatch.StartNew(); var compressionLevel = _configuration.SnapshotSettings?.CompressionLevel ?? CompressionLevel.Optimal; var smugglerResult = _database.FullBackupTo(tempBackupFilePath, compressionLevel, info => { AddInfo(info.Message); _backupResult.SnapshotBackup.ReadCount += info.FilesCount; if (sw.ElapsedMilliseconds > 0 && info.FilesCount > 0) { AddInfo($"Backed up {_backupResult.SnapshotBackup.ReadCount} " + $"file{(_backupResult.SnapshotBackup.ReadCount > 1 ? "s" : string.Empty)}"); sw.Restart(); } }, TaskCancelToken.Token); EnsureSnapshotProcessed(databaseSummary, smugglerResult, indexesCount); AddInfo($"Backed up {_backupResult.SnapshotBackup.ReadCount} files, " + $"took: {totalSw.ElapsedMilliseconds:#,#;;0}ms"); } IOExtensions.RenameFile(tempBackupFilePath, backupFilePath); status.LocalBackup.Exception = null; } catch (Exception e) { status.LocalBackup.Exception = e.ToString(); // deleting the temp backup file if the backup failed DeleteFile(tempBackupFilePath); throw; } } if (_backupToLocalFolder) { var localRetentionPolicy = new LocalRetentionPolicyRunner(_retentionPolicyParameters, _configuration.LocalSettings.FolderPath); localRetentionPolicy.Execute(); } return(internalBackupResult); }
public void Dispose() { documentStore.Dispose(); server.Dispose(); IOExtensions.DeleteDirectory("HiLoData"); }
private void TimerCallback(bool fullBackup) { if (currentTask != null) { return; } if (Database.Disposed) { Dispose(); 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.WithResource(documentDatabase.Name)) { try { OperationState exportResult; bool performAnotherRun = false; do { var dataDumper = new DatabaseDataDumper(documentDatabase, new SmugglerDatabaseOptions() { Limit = backupLimit }); var localBackupConfigs = exportConfigs; var localBackupStatus = exportStatus; if (localBackupConfigs == null) { return; } if (localBackupConfigs.Disabled) { return; } if (fullBackup == false) { var currentEtags = dataDumper.Operations.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 (Directory.Exists(backupPath) == false) { Directory.CreateDirectory(backupPath); } 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 = dataDumper.Options; if (fullBackup == false) { smugglerOptions.StartDocsEtag = localBackupStatus.LastDocsEtag; smugglerOptions.StartAttachmentsEtag = localBackupStatus.LastAttachmentsEtag; smugglerOptions.StartDocsDeletionEtag = localBackupStatus.LastDocsDeletionEtag; smugglerOptions.StartAttachmentsDeletionEtag = localBackupStatus.LastAttachmentDeletionEtag; smugglerOptions.Incremental = true; smugglerOptions.ExportDeletions = true; } exportResult = await dataDumper.ExportData(new SmugglerExportOptions <RavenConnectionStringOptions> { ToFile = backupPath }).ConfigureAwait(false); 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 { await UploadToServer(exportResult.FilePath, localBackupConfigs, fullBackup).ConfigureAwait(false); } finally { // if user did not specify local folder we delete temporary file. if (String.IsNullOrEmpty(localBackupConfigs.LocalFolderName)) { IOExtensions.DeleteFile(exportResult.FilePath); } } localBackupStatus.LastAttachmentsEtag = exportResult.LastAttachmentsEtag; localBackupStatus.LastDocsEtag = exportResult.LastDocsEtag; localBackupStatus.LastDocsDeletionEtag = exportResult.LastDocDeleteEtag; localBackupStatus.LastAttachmentDeletionEtag = exportResult.LastAttachmentsDeleteEtag; if (fullBackup) { localBackupStatus.LastFullBackup = SystemTime.UtcNow; } else { 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 } } if (backupLimit != int.MaxValue) { backupLimit = int.MaxValue; performAnotherRun = true; } else { performAnotherRun = false; } } while (performAnotherRun); } catch (ObjectDisposedException) { // shutting down, probably } catch (OperationCanceledException) { // shutting down, probably } catch (Exception e) { backupLimit = 100; 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; }); } }
public void Dispose() { server.Dispose(); store.Dispose(); IOExtensions.DeleteDirectory(path); }
public async Task <IOperationResult> RunPeriodicBackup(Action <IOperationProgress> onProgress) { AddInfo($"Started task: '{_configuration.Name}'", onProgress); var totalSw = Stopwatch.StartNew(); var operationCanceled = false; var runningBackupStatus = _periodicBackup.RunningBackupStatus = new PeriodicBackupStatus { TaskId = _configuration.TaskId, BackupType = _configuration.BackupType, LastEtag = _previousBackupStatus.LastEtag, LastRaftIndex = _previousBackupStatus.LastRaftIndex, LastFullBackup = _previousBackupStatus.LastFullBackup, LastIncrementalBackup = _previousBackupStatus.LastIncrementalBackup, LastFullBackupInternal = _previousBackupStatus.LastFullBackupInternal, LastIncrementalBackupInternal = _previousBackupStatus.LastIncrementalBackupInternal, IsFull = _isFullBackup, LocalBackup = _previousBackupStatus.LocalBackup, LastOperationId = _previousBackupStatus.LastOperationId, FolderName = _previousBackupStatus.FolderName }; try { var now = DateTime.Now.ToString(DateTimeFormat, CultureInfo.InvariantCulture); if (runningBackupStatus.LocalBackup == null) { runningBackupStatus.LocalBackup = new LocalBackup(); } if (runningBackupStatus.LastRaftIndex == null) { runningBackupStatus.LastRaftIndex = new LastRaftIndex(); } if (_logger.IsInfoEnabled) { var fullBackupText = "a " + (_configuration.BackupType == BackupType.Backup ? "full backup" : "snapshot"); _logger.Info($"Creating {(_isFullBackup ? fullBackupText : "an incremental backup")}"); } var currentLastRaftIndex = GetDatabaseEtagForBackup(); if (_isFullBackup == false) { // if we come from old version the _previousBackupStatus won't have LastRaftIndex if (_previousBackupStatus.LastRaftIndex == null) { _previousBackupStatus.LastRaftIndex = new LastRaftIndex(); } // no-op if nothing has changed var currentLastEtag = _database.ReadLastEtag(); if ((currentLastEtag == _previousBackupStatus.LastEtag) && (currentLastRaftIndex == _previousBackupStatus.LastRaftIndex.LastEtag)) { var message = "Skipping incremental backup because " + $"last etag ({currentLastEtag:#,#;;0}) hasn't changed since last backup"; if (_logger.IsInfoEnabled) { _logger.Info(message); } UpdateOperationId(runningBackupStatus); runningBackupStatus.LastIncrementalBackup = _startTime; DatabaseSmuggler.EnsureProcessed(_backupResult); AddInfo(message, onProgress); return(_backupResult); } } GenerateFolderNameAndBackupDirectory(now, out var folderName, out var backupDirectory); var startDocumentEtag = _isFullBackup == false ? _previousBackupStatus.LastEtag : null; var fileName = GetFileName(_isFullBackup, backupDirectory.FullPath, now, _configuration.BackupType, out string backupFilePath); var lastEtag = CreateLocalBackupOrSnapshot(runningBackupStatus, backupFilePath, startDocumentEtag, onProgress); runningBackupStatus.LocalBackup.BackupDirectory = _backupToLocalFolder ? backupDirectory.FullPath : null; runningBackupStatus.LocalBackup.TempFolderUsed = _backupToLocalFolder == false; runningBackupStatus.IsFull = _isFullBackup; try { await UploadToServer(backupFilePath, folderName, fileName, onProgress); } finally { runningBackupStatus.UploadToS3 = _backupResult.S3Backup; runningBackupStatus.UploadToAzure = _backupResult.AzureBackup; runningBackupStatus.UploadToGlacier = _backupResult.GlacierBackup; runningBackupStatus.UploadToFtp = _backupResult.FtpBackup; // if user did not specify local folder we delete the temporary file if (_backupToLocalFolder == false) { IOExtensions.DeleteFile(backupFilePath); } } UpdateOperationId(runningBackupStatus); runningBackupStatus.LastEtag = lastEtag; runningBackupStatus.LastRaftIndex.LastEtag = currentLastRaftIndex; runningBackupStatus.FolderName = folderName; if (_isFullBackup) { runningBackupStatus.LastFullBackup = _periodicBackup.StartTime; } else { runningBackupStatus.LastIncrementalBackup = _periodicBackup.StartTime; } totalSw.Stop(); if (_logger.IsInfoEnabled) { var fullBackupText = "a " + (_configuration.BackupType == BackupType.Backup ? " full backup" : " snapshot"); _logger.Info($"Successfully created {(_isFullBackup ? fullBackupText : "an incremental backup")} " + $"in {totalSw.ElapsedMilliseconds:#,#;;0} ms"); } return(_backupResult); } catch (OperationCanceledException) { operationCanceled = TaskCancelToken.Token.IsCancellationRequested && _databaseShutdownCancellationToken.IsCancellationRequested; throw; } catch (ObjectDisposedException) { // shutting down, probably operationCanceled = true; throw; } catch (Exception e) { const string message = "Error when performing periodic backup"; runningBackupStatus.Error = new Error { Exception = e.ToString(), At = DateTime.UtcNow }; if (_logger.IsOperationsEnabled) { _logger.Operations(message, e); } _database.NotificationCenter.Add(AlertRaised.Create( _database.Name, $"Periodic Backup task: '{_periodicBackup.Configuration.Name}'", message, AlertType.PeriodicBackup, NotificationSeverity.Error, details: new ExceptionDetails(e))); throw; } finally { if (operationCanceled == false) { // whether we succeeded or not, // we need to update the last backup time to avoid // starting a new backup right after this one if (_isFullBackup) { runningBackupStatus.LastFullBackupInternal = _startTime; } else { runningBackupStatus.LastIncrementalBackupInternal = _startTime; } runningBackupStatus.NodeTag = _serverStore.NodeTag; runningBackupStatus.DurationInMs = totalSw.ElapsedMilliseconds; runningBackupStatus.Version = ++_previousBackupStatus.Version; _periodicBackup.BackupStatus = runningBackupStatus; // save the backup status await WriteStatus(runningBackupStatus, onProgress); } } }