예제 #1
0
        public async Task Should_remove_deleting_file_and_its_pages_after_storage_cleanup()
        {
            const int numberOfPages = 10;

            var client = NewAsyncClient();
            var rfs    = GetFileSystem();

            var bytes = new byte[numberOfPages * StorageConstants.MaxPageSize];

            new Random().NextBytes(bytes);

            await client.UploadAsync("toDelete.bin", new MemoryStream(bytes));


            rfs.Files.IndicateFileToDelete(FileHeader.Canonize("toDelete.bin"), null);

            await rfs.Files.CleanupDeletedFilesAsync();

            Assert.Throws(typeof(FileNotFoundException),
                          () => rfs.Storage.Batch(accessor => accessor.GetFile(RavenFileNameHelper.DeletingFileName("toDelete.bin"), 0, 10)));

            for (var i = 1; i <= numberOfPages; i++)
            {
                var pageId = 0;
                var i1     = i;
                rfs.Storage.Batch(accessor => pageId = accessor.ReadPage(i1, null));
                Assert.Equal(-1, pageId); // if page does not exist we return -1
            }
        }
예제 #2
0
        public void Should_not_delete_downloading_file_if_synchronization_retry_is_being_performed()
        {
            const string fileName            = "file.bin";
            var          downloadingFileName = RavenFileNameHelper.DownloadingFileName(fileName);

            var client = NewAsyncClient();
            var rfs    = GetFileSystem();

            client.UploadAsync(fileName, new RandomStream(1)).Wait();

            client.UploadAsync(downloadingFileName, new RandomStream(1)).Wait();

            rfs.Files.IndicateFileToDelete(downloadingFileName, null);

            rfs.Storage.Batch(accessor =>
                              accessor.SetConfigurationValue(RavenFileNameHelper.SyncLockNameForFile(fileName), LockFileTests.SynchronizationConfig(DateTime.UtcNow)));

            rfs.Files.CleanupDeletedFilesAsync().Wait();

            DeleteFileOperation deleteFile = null;

            rfs.Storage.Batch(accessor =>
                              deleteFile = accessor.GetConfigurationValue <DeleteFileOperation>(RavenFileNameHelper.DeleteOperationConfigNameForFile(RavenFileNameHelper.DeletingFileName(downloadingFileName))));

            Assert.Equal(RavenFileNameHelper.DeletingFileName(downloadingFileName), deleteFile.CurrentFileName);
            Assert.Equal(downloadingFileName, deleteFile.OriginalFileName);
        }
예제 #3
0
        public async Task Upload_before_performing_cleanup_do_a_rename_by_adding_version_number()
        {
            var client = NewAsyncClient();
            var rfs    = GetFileSystem();

            await client.UploadAsync("file.bin", new RandomStream(1));

            // this upload should indicate old file to delete
            await client.UploadAsync("file.bin", new RandomStream(1));

            // upload again - note that actual file delete was not performed yet
            await client.UploadAsync("file.bin", new RandomStream(1));

            List <string> configNames = null;

            rfs.Storage.Batch(
                accessor =>
                configNames =
                    accessor.GetConfigNames(0, 10).ToArray().Where(x => x.StartsWith(RavenFileNameHelper.DeleteOperationConfigPrefix)).OrderBy(x => x.Length).ToList());

            Assert.Equal(2, configNames.Count);
            Assert.Equal(RavenFileNameHelper.DeleteOperationConfigPrefix + RavenFileNameHelper.DeletingFileName("file.bin"), configNames[0]);
            Assert.True(configNames[1].StartsWith(RavenFileNameHelper.DeleteOperationConfigPrefix + "/file.bin") &&
                        configNames[1].EndsWith(RavenFileNameHelper.DeletingFileSuffix)); // number in the middle is used to avoid duplicates
        }
예제 #4
0
        public void Should_not_perform_file_delete_if_it_is_being_synced()
        {
            var filename = FileHeader.Canonize("file.bin");

            var client = NewAsyncClient();
            var rfs    = GetFileSystem();

            client.UploadAsync("file.bin", new MemoryStream(new byte[] { 1, 2, 3, 4, 5 })).Wait();

            rfs.Files.IndicateFileToDelete(filename, null);

            rfs.Storage.Batch(accessor =>
                              accessor.SetConfigurationValue(RavenFileNameHelper.SyncLockNameForFile(filename),
                                                             LockFileTests.SynchronizationConfig(DateTime.UtcNow)));

            rfs.Files.CleanupDeletedFilesAsync().Wait();

            DeleteFileOperation deleteFile = null;

            rfs.Storage.Batch(accessor =>
                              deleteFile = accessor.GetConfigurationValue <DeleteFileOperation>(RavenFileNameHelper.DeleteOperationConfigNameForFile(RavenFileNameHelper.DeletingFileName(filename))));

            Assert.Equal(RavenFileNameHelper.DeletingFileName(filename), deleteFile.CurrentFileName);
            Assert.Equal(filename, deleteFile.OriginalFileName);
        }
예제 #5
0
        public async Task Upload_before_performing_cleanup_do_a_rename_by_adding_version_number()
        {
            var client = NewAsyncClient();
            var rfs    = GetFileSystem();

            await client.UploadAsync("file.bin", new RandomStream(1));

            // this upload should indicate old file to delete
            await client.UploadAsync("file.bin", new RandomStream(1));

            // upload again - note that actual file delete was not performed yet
            await client.UploadAsync("file.bin", new RandomStream(1));

            List <string> configNames = null;

            rfs.Storage.Batch(
                accessor =>
                configNames =
                    accessor.GetConfigNames(0, 10).ToArray().Where(x => x.StartsWith(RavenFileNameHelper.DeleteOperationConfigPrefix)).ToList());

            Assert.Equal(2, configNames.Count());

            foreach (var configName in configNames)
            {
                Assert.True(RavenFileNameHelper.DeleteOperationConfigPrefix + RavenFileNameHelper.DeletingFileName("file.bin") == configName ||
                            RavenFileNameHelper.DeleteOperationConfigPrefix + RavenFileNameHelper.DeletingFileName("file.bin1") == configName); // 1 indicate delete version
            }
        }
예제 #6
0
        public async Task Can_force_storage_cleanup_from_client()
        {
            var client = NewAsyncClient();
            await client.UploadAsync("toDelete.bin", new MemoryStream(new byte[] { 1, 2, 3, 4, 5 }));

            await client.DeleteAsync("toDelete.bin");

            await client.Storage.CleanUpAsync();

            var configNames = await client.Configuration.GetKeyNamesAsync();

            Assert.DoesNotContain(
                RavenFileNameHelper.DeleteOperationConfigNameForFile(RavenFileNameHelper.DeletingFileName("toDelete.bin")),
                configNames);
        }
예제 #7
0
        public void Should_create_apropriate_config_after_indicating_file_to_delete()
        {
            var client = NewAsyncClient();
            var rfs    = GetRavenFileSystem();

            client.UploadAsync("toDelete.bin", new MemoryStream(new byte[] { 1, 2, 3, 4, 5 })).Wait();

            rfs.StorageOperationsTask.IndicateFileToDelete("toDelete.bin");

            DeleteFileOperation deleteFile = null;

            rfs.Storage.Batch(accessor =>
                              deleteFile = accessor.GetConfigurationValue <DeleteFileOperation>(RavenFileNameHelper.DeleteOperationConfigNameForFile(RavenFileNameHelper.DeletingFileName("toDelete.bin"))));

            Assert.Equal(RavenFileNameHelper.DeletingFileName("toDelete.bin"), deleteFile.CurrentFileName);
            Assert.Equal("toDelete.bin", deleteFile.OriginalFileName);
        }
예제 #8
0
        public async Task Should_remove_file_deletion_config_after_storage_cleanup()
        {
            var client = NewAsyncClient();
            var rfs    = GetFileSystem();

            await client.UploadAsync("toDelete.bin", new MemoryStream(new byte[] { 1, 2, 3, 4, 5 }));

            rfs.Files.IndicateFileToDelete("toDelete.bin", null);

            await rfs.Files.CleanupDeletedFilesAsync();

            IEnumerable <string> configNames = null;

            rfs.Storage.Batch(accessor => configNames = accessor.GetConfigNames(0, 10).ToArray());

            Assert.DoesNotContain(RavenFileNameHelper.DeleteOperationConfigNameForFile(RavenFileNameHelper.DeletingFileName("toDelete.bin")), configNames);
        }
예제 #9
0
        public void IndicateFileToDelete(string fileName)
        {
            var deletingFileName = RavenFileNameHelper.DeletingFileName(fileName);
            var fileExists       = true;

            storage.Batch(accessor =>
            {
                var existingFileHeader = accessor.ReadFile(fileName);

                if (existingFileHeader == null)
                {
                    // do nothing if file does not exist
                    fileExists = false;
                    return;
                }

                if (existingFileHeader.Metadata[SynchronizationConstants.RavenDeleteMarker] != null)
                {
                    // if it is a tombstone drop it
                    accessor.Delete(fileName);
                    fileExists = false;
                    return;
                }

                var metadata = new RavenJObject(existingFileHeader.Metadata).WithDeleteMarker();

                var renameSucceeded = false;

                int deleteVersion = 0;

                do
                {
                    try
                    {
                        accessor.RenameFile(fileName, deletingFileName);
                        renameSucceeded = true;
                    }
                    catch (FileExistsException)                     // it means that .deleting file was already existed
                    {
                        var deletingFileHeader = accessor.ReadFile(deletingFileName);

                        if (deletingFileHeader != null && deletingFileHeader.Equals(existingFileHeader))
                        {
                            fileExists = false;                             // the same file already marked as deleted no need to do it again
                            return;
                        }

                        // we need to use different name to do a file rename
                        deleteVersion++;
                        deletingFileName = RavenFileNameHelper.DeletingFileName(fileName, deleteVersion);
                    }
                } while (!renameSucceeded && deleteVersion < 128);

                if (renameSucceeded)
                {
                    accessor.UpdateFileMetadata(deletingFileName, metadata);
                    accessor.DecrementFileCount(deletingFileName);

                    Log.Debug(string.Format("File '{0}' was renamed to '{1}' and marked as deleted", fileName, deletingFileName));

                    var configName = RavenFileNameHelper.DeleteOperationConfigNameForFile(deletingFileName);
                    var operation  = new DeleteFileOperation {
                        OriginalFileName = fileName, CurrentFileName = deletingFileName
                    };
                    accessor.SetConfig(configName, JsonExtensions.ToJObject(operation));

                    notificationPublisher.Publish(new ConfigurationChangeNotification {
                        Name = configName, Action = ConfigurationChangeAction.Set
                    });
                }
                else
                {
                    Log.Warn("Could not rename a file '{0}' when a delete operation was performed", fileName);
                }
            });

            if (fileExists)
            {
                search.Delete(fileName);
                search.Delete(deletingFileName);
            }
        }
예제 #10
0
        public void IndicateFileToDelete(string fileName, Etag etag)
        {
            var deletingFileName = RavenFileNameHelper.DeletingFileName(fileName);
            var fileExists       = true;

            Storage.Batch(accessor =>
            {
                AssertDeleteOperationNotVetoed(fileName);

                var existingFile = accessor.ReadFile(fileName);

                if (existingFile == null)
                {
                    // do nothing if file does not exist
                    fileExists = false;
                    return;
                }

                if (existingFile.Metadata[SynchronizationConstants.RavenDeleteMarker] != null)
                {
                    // if it is a tombstone drop it
                    accessor.Delete(fileName);
                    fileExists = false;
                    return;
                }

                if (etag != null && existingFile.Etag != etag)
                {
                    throw new ConcurrencyException("Operation attempted on file '" + fileName + "' using a non current etag")
                    {
                        ActualETag   = existingFile.Etag,
                        ExpectedETag = etag
                    }
                }
                ;

                var metadata = new RavenJObject(existingFile.Metadata).WithDeleteMarker();

                var renameSucceeded = false;

                int deleteVersion = 0;

                do
                {
                    try
                    {
                        accessor.RenameFile(fileName, deletingFileName);
                        renameSucceeded = true;
                    }
                    catch (FileExistsException)                     // it means that .deleting file was already existed
                    {
                        var deletingFileHeader = accessor.ReadFile(deletingFileName);

                        if (deletingFileHeader != null && deletingFileHeader.Equals(existingFile))
                        {
                            fileExists = false;                             // the same file already marked as deleted no need to do it again
                            return;
                        }

                        // we need to use different name to do a file rename
                        deleteVersion++;
                        deletingFileName = RavenFileNameHelper.DeletingFileName(fileName, deleteVersion);
                    }
                } while (!renameSucceeded && deleteVersion < 128);

                if (renameSucceeded)
                {
                    accessor.UpdateFileMetadata(deletingFileName, metadata, null);
                    accessor.DecrementFileCount(deletingFileName);

                    Log.Debug("File '{0}' was renamed to '{1}' and marked as deleted", fileName, deletingFileName);

                    var configName = RavenFileNameHelper.DeleteOperationConfigNameForFile(deletingFileName);
                    var operation  = new DeleteFileOperation {
                        OriginalFileName = fileName, CurrentFileName = deletingFileName
                    };
                    accessor.SetConfig(configName, JsonExtensions.ToJObject(operation));

                    FileSystem.DeleteTriggers.Apply(trigger => trigger.AfterDelete(fileName));

                    Publisher.Publish(new ConfigurationChangeNotification {
                        Name = configName, Action = ConfigurationChangeAction.Set
                    });
                    Publisher.Publish(new FileChangeNotification {
                        File = fileName, Action = FileChangeAction.Delete
                    });

                    Log.Debug("File '{0}' was deleted", fileName);
                }
                else
                {
                    Log.Warn("Could not rename a file '{0}' when a delete operation was performed", fileName);
                }
            });

            if (fileExists)
            {
                Search.Delete(fileName);
                Search.Delete(deletingFileName);
            }
        }