/// <summary> /// Get data file iterator. /// </summary> /// <param name="folder"> /// Folder whose data files to iterate over. /// </param> /// <param name="backwards"> /// Initial iteration direction. /// </param> /// <returns> /// <see cref="IDataFileIterator"/> /// </returns> /// <remarks> /// Note that you must call one of the Seek methods to start iteration after the iterator instance is created. /// </remarks> public IDataFileIterator GetDataFileIterator(IRepositoryFolder folder, bool backwards) { CheckHelper.CheckRepositoryNotDisposed(Repository); Check.DoRequireArgumentNotNull(folder, "folder"); RepositoryFolder.CheckNotDetached(folder); return(new DataFileIterator(folder, backwards)); }
/// <summary> /// Check read and/or write access status to the <paramref name="folder"/>. /// </summary> /// <param name="folder"> /// Folder to check current access to. /// </param> /// <param name="subtree"> /// Whether to check access to all folders in the subtree or only to the <paramref name="folder"/> itself /// </param> /// <param name="read"> /// Whether to check read access, i.e. whether target folder[s] is/are being read from /// </param> /// <param name="write"> /// Whether to check write access, i.e. whether target folder[s] is/are being written to /// </param> /// <remarks> /// Access to readers and writers registry is synchronised; all concurrent calls accessing registry of readers and writers /// will wait until this method finishes. /// </remarks> private bool IsDataBeingAccessed(IRepositoryFolder folder, bool subtree, bool write, bool read) { Exceptions.DifferentRepositoriesExceptionHelper.Check(this, folder.Repository); Util.Check.Require(write || read); IFolder f = RepositoryFolder.CastFolder(folder, "folder"); bool retval = false; _dataAccessorRegistryLock.EnterReadLock(); try { if (read) { retval = IsDataBeingAccessed(_readers, f, subtree); } if (!retval && write) { retval = IsDataBeingAccessed(_writers, f, subtree); } } finally { _dataAccessorRegistryLock.ExitReadLock(); } return(retval); }
public void TestWritingNotInOrder() { const string subFolderName = "TestWritingNotInOrder"; const int desiredFileSize = 100; Mock.MultiLevelDataRouter router = new Mock.MultiLevelDataRouter(2, 2); IRepositoryFolder targetFolder = Repository.RootFolder.GetDescendant(FixtureRootRepoFolder.LogicalPath, false).CreateSubfolder(subFolderName); targetFolder.Properties.DesiredItemsPerFile = desiredFileSize; const int itemCount = 100000; const int intervalMinutes = 1; IDataItem[] data = GetTestData(itemCount, DateTime.Now, intervalMinutes); for (int j = 0; j < 2; ++j) { using (IRepositoryWriter writer = GetWriter(targetFolder, router)) { for (int n = j; n < itemCount; n = n + 2) { writer.Write(dataItem: data[n]); } } } // the following commented out call is necessary if writing was done instandalone instance because target folder does not know that subfolders have been created // during writing; but now I am not using standalone writer //targetFolder.Refresh(true, true); CheckAllDataInFolder(targetFolder, data); }
public static FolderContainsSubfoldersException GetCannotDelete(IRepositoryFolder folder) { return(new FolderContainsSubfoldersException( folder , string.Format(Storage.StorageResources.CannotDeleteFolderWithSubfolders, folder.LogicalPath) )); }
/// <summary> /// <see cref="IRepositoryReader.RemoveFolder"/> /// </summary> /// <exception cref="ObjectDisposedException"> /// The reader has been disposed. /// </exception> public void RemoveFolder(IRepositoryFolder folder) { CheckNotDisposed(); Util.Check.DoRequireArgumentNotNull(folder, "folder"); Exceptions.DifferentRepositoriesExceptionHelper.Check(folder.Repository, Repository); RepositoryFolderReader reader = GetExistingReader(folder.FolderKey); Util.Check.DoRequire(reader != null, "The folder is not being read by the reader"); _position.Remove(reader.Position); reader.Unload(); bool topReaderRemoved = this.HasData && TopReader == reader; bool success = !(!_exhaustedReaders.Remove(reader) && !_offlineQueue.Remove(reader) && !_onlineQueue.Remove(reader)); Util.Check.Ensure(success, "Internal error: reader not found."); success = _readers.Remove(folder.FolderKey); Util.Check.Ensure(success); if (topReaderRemoved) { SyncOfflineQueueForReading(); } Invariant(); }
public void CreateSubfolderTest() { string subFolderName = "CreateSubfolderTest"; int initialSubfoldersCount = FixtureRootRepoFolder.SubFolders.Count; IRepositoryFolder subfolder1 = FixtureRootRepoFolder.CreateSubfolder(subFolderName); IRepositoryFolder rootFoder = Repository.RootFolder; string fullPath = subfolder1.FullPath; Assert.IsTrue(((IFolder)subfolder1).Exists); Assert.IsTrue(Directory.Exists(fullPath)); Assert.AreEqual(initialSubfoldersCount + 1, FixtureRootRepoFolder.SubFolders.Count()); string customPropertyName = "CustomProperty1"; string customPropertyValue = "CustomPropertyValue1"; subfolder1.Properties.SetCustomProperty(customPropertyName, "CustomPropertyValue1"); subfolder1.Properties.Load(); Assert.AreEqual(customPropertyValue, subfolder1.Properties.GetCustomProperty(customPropertyName) , "Custom property value not persisted"); IRepositoryWriter writer = subfolder1.GetWriter(); writer.AllowSubfoldersCreation = true; Populate(writer, 100); writer.Close(); subfolder1.Delete(true, true); Assert.IsFalse(Directory.Exists(fullPath), "Directory not removed from disk"); Assert.AreEqual(initialSubfoldersCount, FixtureRootRepoFolder.SubFolders.Count); }
/// <summary> /// Add a folder to the list of folders being read and prepare it for reading from the specified position /// </summary> /// <param name="folder"> /// Repository folder /// </param> /// <param name="seekTime"> /// Seek timestamp for the folder /// </param> /// <returns> /// <see langword="false"/> - the folder is already being read /// <see langword="true"/> otherwise /// </returns> /// <remarks> /// Any subsequent Seek overrides the position used here /// </remarks> /// <exception cref="ObjectDisposedException"> /// The reader has been disposed. /// </exception> public bool AddFolder(IRepositoryFolder folder, DateTime seekTime) { CheckNotDisposed(); Exceptions.DifferentRepositoriesExceptionHelper.Check(folder.Repository, Repository); // all additions should go through AddFolderImpl return(AddFolderImpl(folder, new FolderReadingPosition(folder, seekTime))); }
/// <summary> /// Add folder to read and optionally prepare it for reading /// </summary> /// <param name="folder"> /// Folder to add /// </param> /// <param name="position"> /// <see langword="null"/> means do not prepare it for reading /// </param> /// <returns> /// <see langword="false"/> - the folder is already being read /// <see langword="true"/> otherwise /// </returns> /// <remarks> /// If reader has data (<see cref="HasData"/>) <paramref name="position"/> must have value /// </remarks> private bool AddFolderImpl(IRepositoryFolder folder, IFolderReadingPosition position) { Check.RequireArgumentNotNull(folder, "folder"); IFolder folderTyped = RepositoryFolder.CastFolder(folder); Check.Require(object.ReferenceEquals(folder.Repository, Repository)); Check.Require(!HasData || position != null, "If we have data we cannot leave a reader unpositioned"); if (IsAccessing(folder, false)) { return(false); } Check.Require(!_position.FolderPositions.ContainsKey(folder.FolderKey) , "Folder position found in repository reader position for a folder not being read"); RepositoryFolderReader reader = new RepositoryFolderReader(folderTyped, this); reader.Direction = this.Direction; _readers.Add(folder.FolderKey, reader); if (position != null) { SeekFolderReader(reader, position); } return(true); }
/// <summary> /// Create new instance. /// </summary> /// <param name="targetFolder"> /// Target repository folder. /// </param> /// <param name="backwards"> /// Whether to iterate backwards. /// </param> /// <exception cref="ObjectDisposedException"> /// The target repository instance is disposed. /// </exception> /// <exception cref="InvalidOperationException"> /// The <paramref name="targetFolder"/> is detached. /// </exception> public DataFileIterator(IRepositoryFolder targetFolder, bool backwards) { RepositoryFolder.CheckNotDetached(targetFolder); _targetFolder = RepositoryFolder.CastFolder(targetFolder); _backwards = backwards; Current = NextForward = NextBackwards = Next = Previous = null; }
private static List <T> GetDataAccessors <T>( LinkedList <Util.WeakReferenceT <T> > list , IRepositoryFolder folder , bool subtree , bool firstOnly) where T : class, IRepositoryDataAccessor { List <T> retval = new List <T>(); for (LinkedListNode <Util.WeakReferenceT <T> > node = list.First; node != null;) { LinkedListNode <Util.WeakReferenceT <T> > nextNode = node.Next; IRepositoryDataAccessor accessor = node.Value.Target; if (accessor == null) { _logger.Info("Purging dead accessor"); list.Remove(node); } else { if (accessor.IsAccessing(RepositoryFolder.CastFolder(folder, "folder"), subtree)) { _logger.InfoFormat("GetDataAccessors found alive writer for {0}", folder.LogicalPath); retval.Add((T)accessor); if (firstOnly) { break; } } } node = nextNode; } return(retval); }
/// <summary> /// Method called from <see cref="Write(IDataItem)"/> /// </summary> /// <param name="folder"> /// Repository folder into which new data item has been added /// </param> /// <param name="file"> /// The data file the data item is going to go to. /// </param> /// <param name="dataItem"> /// The new data item /// </param> protected virtual void OnDataItemAdded(IRepositoryFolder folder, IRepositoryFileName file, IDataItem dataItem) { if (!_itemAddedEvent.HasNoSubscribers) { _itemAddedEvent.Raise(this, new bfs.Repository.Events.DataItemAddedEventArgs(folder, file, dataItem)); } }
public void AddToReaderTest() { string name = "AddToReaderTest"; string subName = "SubName"; IRepositoryFolder target = FixtureRootRepoFolder.CreateSubfolder(name); IRepositoryFolder subFolder = target.CreateSubfolder(subName); //----------------------------------- Mock.RepositoryReaderMock mockedReader = new Mock.RepositoryReaderMock(); target.AddToReader(mockedReader, false); Assert.AreEqual(1, mockedReader.AddFolderCalled); Assert.AreSame(mockedReader.LastFolderArgument, target); mockedReader.Reset(); target.AddToReader(mockedReader, true); Assert.AreEqual(2, mockedReader.AddFolderCalled); Assert.IsTrue(mockedReader.FolderArguments.Contains(target)); Assert.IsTrue(mockedReader.FolderArguments.Contains(subFolder)); //------------------------------------ //now real reader IRepositoryReader reader = Repository.RootFolder.GetReader(DateTime.Now.AddDays(-1), false); Assert.AreEqual(1, reader.Folders.Count, "Reader just created from a folder"); target.AddToReader(reader, false); Assert.AreEqual(2, reader.Folders.Count, "Another reader added"); }
/// <summary> /// Create and initialize new instance. /// </summary> /// <param name="folder"> /// Repository folder to which a new data item has been added. /// </param> /// <param name="file"> /// Repository file to which a new data item has been added. /// </param> /// <param name="dataItem"> /// Newly added data item. /// </param> public DataItemAddedEventArgs( IRepositoryFolder folder , IRepositoryFileName file , IDataItem dataItem) { this.Folder = folder; this.File = file; this.DataItem = dataItem; }
public void ReadEmptyFolderTest() { string targetFolderName = "ReadEmptyFolderTest"; IRepositoryFolder targetFolder = FixtureRootRepoFolder.CreateSubfolder(targetFolderName); using (IRepositoryReader target = targetFolder.GetReader(DateTime.MinValue, true)) { Assert.IsFalse(target.HasData); } }
private ICoder GetEncryptor(IRepositoryFolder targetFolder) { ICoder retval = null; if (targetFolder.Properties.EnableEncryption.HasValue && targetFolder.Properties.EnableEncryption.Value) { retval = Repository.ObjectFactory.GetEncryptor(targetFolder.Properties.Encryptor); } return(retval); }
/// <summary> /// Create exception instance for when timestamp of the last data item read from a data file does not match the border timestamp /// recorded in the file name instance. /// </summary> /// <param name="folder"> /// The target folder containig the data file. /// </param> /// <param name="fileName"> /// The file name as presented by the file name instance contained in the repository object model /// </param> /// <param name="expectedTime"> /// The border timestamp as recorded in the file name instance. /// </param> /// <param name="actualTime"> /// The actual timestamp of the last data item in the file. /// </param> /// <returns> /// New <see cref="ConcurrencyException"/> instance. /// </returns> public static ConcurrencyException GetLastReadItemTimestampMismatch(IRepositoryFolder folder, string fileName, DateTime expectedTime, DateTime actualTime) { string message = string.Format( Storage.StorageResources.ReaderLastItemTimeInFileMismatch , folder.LogicalPath , fileName , expectedTime , actualTime); return(new ConcurrencyException(folder, Storage.StorageResources.PotentialConcurrencyIssueMessage, message, null)); }
/// <summary> /// Add folder and restore its reading position. Folder is identified by its <see cref="IRepositoryFolder.FolderKey"/> /// , which is specified by <see cref="IFolderReadingPosition.FolderKey"/> /// </summary> /// <param name="folderPosition"> /// Folder reading position /// </param> /// <returns> /// <see langword="true"/> - success /// <see langword="false"/> - folder is already being read /// </returns> /// <exception cref="ObjectDisposedException"> /// The reader has been disposed. /// </exception> public bool AddFolder(IFolderReadingPosition folderPosition) { CheckNotDisposed(); Check.DoRequireArgumentNotNull(folderPosition, "folderPosition"); IRepositoryFolder folder = Repository.RootFolder.GetDescendant(folderPosition.FolderKey, false); Check.DoAssertLambda(folder != null , () => new ArgumentException(string.Format(StorageResources.FolderNotFound, folderPosition.FolderKey))); return(AddFolderImpl(folder, folderPosition)); }
/// <summary> /// /// </summary> /// <param name="targetFolder"></param> /// <remarks> /// Constructor is internal because all readers and writers are created in the <see cref="IRepositoryManager.Objectactory /> /// to be able to handle concurrency and provide own/different implementation. /// </remarks> internal FolderDataAccessor(IRepositoryFolder targetFolder) { Check.DoRequireArgumentNotNull(targetFolder, "targetFolder"); Check.DoAssertLambda(!targetFolder.IsDetached, () => new ArgumentException(StorageResources.FolderIsNotPartOfARepository)); _targetFolder = RepositoryFolder.CastFolder(targetFolder); _iterator = Repository.ObjectFactory.GetDataFileIterator(targetFolder, false); Check.Ensure(Repository.IsDataBeingAccessed(Folder, false)); }
/// <summary> /// Get writer preconfigured to track unsaved changes and allow subfolders creation and targeting /// child folder named <paramref name="targetFolderName"/> of <see cref="FixtureRootRepoFolder"/> /// </summary> public IRepositoryWriter GetStandaloneWriter(string targetFolderName, int desiredFileSize, IDataRouter router) { IRepositoryManager manager = GetStandaloneRepository(); manager.Settings.StorageTransactionSettings = StorageTransactionSettings.RequireTransactions | StorageTransactionSettings.DisallowJoiningAmbientManaged; IRepositoryFolder targetFolder = manager.RootFolder.GetDescendant(FixtureRootRepoFolder.LogicalPath, false).GetSubFolder(targetFolderName); targetFolder.Properties.DesiredItemsPerFile = desiredFileSize; return(GetWriter(targetFolder: targetFolder, router: router)); }
/// <summary> /// Write data item to repository /// </summary> /// <param name="dataItem"> /// Data item to write. Must be serializable. /// </param> /// <remarks> /// The <paramref name="dataItem"/> needs to be serializable employing either automatic or custom serialization. Automatic serialization /// requires only <see cref="SerializableAttribute"/>, but it may be difficult to implement versioning. With custom serialization /// the class has to implement the <see cref="ISerializable"/> interface and a special constructor. Note that no immediate check is performed /// in this method and if the <paramref name="dataItem"/> is not serializable the subsequent flushing of the data to disk may fail. /// Not thread safe, must not be used in more than 1 thread at once. /// </remarks> public void Write(IDataItem dataItem) { CheckNotDisposed(); Check.DoRequireArgumentNotNull(dataItem, "dataItem"); Check.DoRequire(dataItem.RelativePath != null, "RelativePath must not be null"); Check.Invariant(_activeDataRouter != null); // if new transaction scope is created for ambient managed here and the transaction gets disposed using (var scope = _transactionManager.GetLazyTransactionScope()) { DirectSingleFolderWriter targetWriter; // relative path as directed by active router string originalRelativePath = _activeDataRouter.GetRelativePath(dataItem); // have a look at exact match in the cache targetWriter = GetExistingWriterByRelativePath(originalRelativePath); if (null == targetWriter) { // no exact match, let's normalise path string normalizedRelativePath = RepositoryFolder.GetFolderPathKey(originalRelativePath); if (!string.Equals(normalizedRelativePath, originalRelativePath, StringComparison.Ordinal)) { targetWriter = GetExistingWriterByRelativePath(normalizedRelativePath); } // if normilised is the same as original or not same but still there's no writer in cache if (null == targetWriter) { // writing to the folder for the first time // using original relative path to preserve casing when creating IRepositoryFolder targetFolder = GetSubfolder(originalRelativePath, this.AllowSubfoldersCreation); if (null == targetFolder) { throw FolderNotFoundExceptionHelper.GetForWriter(this.Folder, originalRelativePath); } targetWriter = CreateWriter(targetFolder, normalizedRelativePath); } } Check.Ensure(targetWriter.TrackUnsavedItems == this.TrackUnsavedItems); targetWriter.Write(dataItem); OnDataItemAdded(targetWriter.Folder, targetWriter.CurrentFile, dataItem); scope.Complete(); } }
/// <summary> /// Get reader for this repository /// </summary> /// <param name="targetFolder"> /// Target folder to read. Specify <see langword="null"/> to add target folders later. /// </param> /// <returns> /// New instance of repository reader. /// </returns> public virtual IRepositoryReader GetReader(IRepositoryFolder targetFolder) { CheckHelper.CheckRepositoryNotDisposed(Repository); IRepositoryReader retval = new RepositoryReader(Repository); Repository.RegisterReader(retval); if (null != targetFolder) { retval.AddFolder(targetFolder); } return(retval); }
/// <summary> /// Add a folder to the list of folders being read and prepare it for reading if the reader has data /// </summary> /// <param name="folder"> /// Repository folder /// </param> /// <returns> /// <see langword="false"/> - the folder is already being read /// <see langword="true"/> otherwise /// </returns> /// <remarks> /// Starting new folder from last read item time, not next item time to be consistent /// if no items has been read yet, using last seek time; this works transparently with restoring position; /// say a reader was sought but there was no data or reading was interrupted; the reader should provide a position /// upon restoration of which later all items added since the position was saved and which would have been read /// had the seek been called after they were added, would be read by the reader. /// </remarks> /// <exception cref="ObjectDisposedException"> /// The reader has been disposed. /// </exception> public bool AddFolder(IRepositoryFolder folder) { CheckNotDisposed(); Exceptions.DifferentRepositoriesExceptionHelper.Check(folder.Repository, Repository); // position if reading is under way; otherwise Seek will have to be called before reading // all additions should go through AddFolderImpl FolderReadingPosition position = null; if (IsPositioned) { position = new FolderReadingPosition(folder, _position.Time); } return(AddFolderImpl(folder, position)); }
public void GetUnsavedItemsWithFlushTest() { const int subfolderCount = 3; string subFolderName = "GetUnsavedItemsTest"; IRepositoryFolder targetFolder = FixtureRootRepoFolder.CreateSubfolder(subFolderName); IRepositoryWriter writer = targetFolder.GetWriter(); IDataRouter dataRouter = new Mock.NumberedDataRouter(subfolderCount); writer.DataRouter = dataRouter; writer.AllowSubfoldersCreation = true; string fullPath = targetFolder.FullPath; Mock.TestDataItem item; int lastFlushCount = 0; for (int n = 0; n < 10000; ++n) { item = Mock.TestDataItem.GetTestItem(n); writer.Write(item); if ((n + 1) % 10 == 0) { IDictionary <string, IList <IDataItem> > unsavedItems = writer.GetUnsavedItems(); Assert.IsNotNull(unsavedItems); Assert.AreEqual(Math.Min(n + 1, subfolderCount), unsavedItems.Count, "Unsaved items dictionary entry count is not equal to the direct writers count"); Assert.AreEqual(n + 1 - lastFlushCount, unsavedItems.Values.Sum((l) => l.Count), "Total number of unsaved items incorrect"); } else if ((n + 1) % 134 == 0) { writer.Flush(); lastFlushCount = n + 1; IDictionary <string, IList <IDataItem> > unsavedItems = writer.GetUnsavedItems(); Assert.IsNotNull(unsavedItems); Assert.AreEqual(Math.Min(n + 1, subfolderCount), unsavedItems.Count, "Unsaved items dictionary entry count is not equal to the direct writers count"); Assert.AreEqual(0, unsavedItems.Values.Sum((l) => l.Count), "Total number of unsaved items after flush must be 0"); } } writer.Close(); }
/// <summary> /// Get existing readers from either the specified folder or any of its descendants, depending on the parameter /// </summary> /// <param name="folder"> /// <see cref="IRepositoryFolder"/> instance representing the folder or the whole subtree /// (the folder and all its descendants), depending on <paramref name="subtree"/> /// </param> /// <param name="subtree"> /// the scope of the search - <code>bool</code> indicating whether to find writer to any of the descendants of /// <paramref name="folder"/> (<see langword="true"/>) or just <paramref name="folder"/> itself. /// </param> /// <returns> /// The list of existing readers, never <see langword="null"/> /// </returns> /// <exception cref="ArgumentException"> /// The <paramref name="folder"/> does not belong to this repository /// </exception> /// <remarks> /// Access to readers and writers registry is synchronised; all concurrent calls accessing registry of readers and writers /// will wait until this method finishes. /// </remarks> public IList <IRepositoryDataAccessor> GetReaders(IRepositoryFolder folder, bool subtree) { CheckNotDisposed(); Check.DoRequireArgumentNotNull(folder, "folder"); Exceptions.DifferentRepositoriesExceptionHelper.Check(this, folder.Repository); _dataAccessorRegistryLock.EnterReadLock(); try { return(GetDataAccessors(_readers, folder, subtree, false)); } finally { _dataAccessorRegistryLock.ExitReadLock(); } }
//------------------------------------------------------------------ /// <summary> /// Get writer preconfigured to track unsaved changes and allow subfolders creation /// </summary> /// <param name="targetFolder"></param> /// <param name="desiredFileSize"></param> /// <param name="router"></param> /// <returns></returns> public IRepositoryWriter GetWriter(IRepositoryFolder targetFolder, IDataRouter router) { IRepositoryWriter writer = targetFolder.GetWriter(); writer.TrackUnsavedItems = true; if (router != null) { writer.DataRouter = router; } writer.AllowSubfoldersCreation = true; return(writer); }
private void CheckAllDataInFolder(IRepositoryFolder folder, IDataItem[] expectedData) { List <IDataItem> dataRead = new List <IDataItem>(expectedData.Length); using (IRepositoryReader reader = folder.GetReader(DateTime.MinValue, true)) { while (reader.HasData) { dataRead.Add(reader.Read().DataItem); } } Assert.AreEqual(expectedData.Length, dataRead.Count, "The total number of items read after writing does not match the amount written"); for (int n = 0; n < expectedData.Length; ++n) { Assert.AreEqual(expectedData[n], dataRead[n]); } }
public void QuickIntegrationTest() { IRepositoryFolder targetFolder = FixtureRootRepoFolder; IDataFileIterator iterator = Repository.ObjectFactory.GetDataFileIterator(targetFolder, false); // this must guarantee that previous, current and next are all not null DateTime seekTime = _firstDataItemTime.AddDays(_daysPerFile * 3); iterator.Seek(seekTime); Assert.IsNotNull(iterator.Current); Assert.IsNotNull(iterator.NextBackwards); Assert.IsNotNull(iterator.NextForward); Assert.IsTrue(iterator.Current.Name.End > seekTime); Assert.IsTrue(iterator.NextBackwards.Name.End <= seekTime); Assert.IsTrue(iterator.NextForward.Name.FirstItemTimestamp > seekTime); }
public static FolderNotFoundException GetForWriter( IRepositoryFolder writersTarget, string originalRelativePath) { string message = string.Format(Storage.StorageResources.DescendantFolderNotFound, originalRelativePath, writersTarget.LogicalPath); string technicalInfo = string.Format( @"Target folder was not found by its relative path {0} in forlder {1} repository {2}" , originalRelativePath , writersTarget.LogicalPath , writersTarget.Repository.RepositoryRoot); return(new FolderNotFoundException( message: message , technicalInfo: technicalInfo , rootRepositoryPath: writersTarget.Repository.RepositoryRoot , pathToTargetFolder: originalRelativePath , innerException: null)); }
/// <summary> /// Get writer for this repository /// </summary> /// <param name="targetFolder"> /// Target root folder to write. Data items may go to descendants folders, /// <see cref="bfs.Repository.Interfaces.IDataItem.RelativePath"/> /// </param> /// <returns> /// New instance of <see cref="IRepositoryWriter"/>. /// </returns> /// <remarks> /// Only 1 writer can be created for a particular folder. /// </remarks> public virtual IRepositoryWriter GetWriter(IRepositoryFolder targetFolder) { CheckHelper.CheckRepositoryNotDisposed(Repository); Check.RequireArgumentNotNull(targetFolder, "targetFolder"); RepositoryWriter retval; lock (targetFolder) { RepositoryFolder.CheckNotDetached(targetFolder); Check.DoAssertLambda(!Repository.IsDataBeingWrittenTo(targetFolder, false), () => new InvalidOperationException(string.Format(StorageResources.WriterAlreadyExistsForFolder, targetFolder.LogicalPath))); retval = new RepositoryWriter(RepositoryFolder.CastFolder(targetFolder)); Repository.RegisterWriter(retval); } Check.Ensure(Repository.IsDataBeingWrittenTo(targetFolder, false)); return(retval); }
public void WriteTest() { string subFolderName = "WriteTest"; int initialSubfoldersCount = Repository.RootFolder.SubFolders.Count; IRepositoryFolder targetFolder = FixtureRootRepoFolder.CreateSubfolder(subFolderName); IRepositoryWriter writer = targetFolder.GetWriter(); writer.AllowSubfoldersCreation = true; string fullPath = targetFolder.FullPath; Mock.TestDataItem item; for (int n = 0; n < 100; ++n) { item = Mock.TestDataItem.GetTestItem(n); writer.Write(item); } // testing automatic subfolder creation item = Mock.TestDataItem.GetTestItem(1000); item.RelativePath = "AutoSubfolder1/Auto2"; writer.Write(item); Assert.AreEqual(1, targetFolder.SubFolders.Count, "Automatic subfolder creation during write failed"); Assert.IsNotNull(targetFolder.GetSubFolder("AutoSubfolder1")); Assert.AreEqual(1, targetFolder.GetSubFolder("AutoSubfolder1").SubFolders.Count); Assert.IsNotNull(targetFolder.GetSubFolder("AutoSubfolder1").GetSubFolder("Auto2")); writer.Flush(); writer.Close(); targetFolder.Delete(true, true); Assert.IsFalse(Directory.Exists(fullPath), "Directory not removed from disk"); Assert.AreEqual(initialSubfoldersCount, Repository.RootFolder.SubFolders.Count); }