/// <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)); } }
/// <summary> /// Find first leaf data [sub]folder and data file in it containing items dated at, earlier or later than the /// <paramref name="seekTime"/> /// </summary> /// <param name="seekTime"> /// Specifies the start of date-time range (inclusive) to find data in /// </param> /// <param name="backwards"> /// To which side from <paramref name="seekTime"/> to look for data /// </param> /// <returns> /// First (according to <paramref name="seekTime"/>) data file containing the required data; /// <see langword="null"/> if none found /// </returns> public IRepositoryFile Seek(DateTime seekTime, bool backwards) { _log.DebugFormat("Seeking data folder for reader, descr: {0}" , this.IsVirtualRoot ? "Virtual Root" : this._folderDescriptor.ToString()); IRepositoryFileName dataFile = null; IRepositoryFile retval = null; if (IsLeafFolder) { LoadFiles(false); dataFile = _dataFileBrowser.GetFile(seekTime, backwards); if (null != dataFile) { _log.DebugFormat("Seek found file: {0}", dataFile.FileName); retval = GetContainedRepositoryFile(dataFile); } } else { LoadSubFolders(false); IDirectedEnumerable <IDataFolder> sequence = GetSubfoldersSequence(seekTime, backwards); for ( IEnumerator <IDataFolder> scanner = sequence.GetEnumerator(); scanner.MoveNext() && null == retval; ) { retval = scanner.Current.Seek(seekTime, backwards); } } return(retval); }
private IDataFileAccessor GetAccessor(IRepositoryFileName targetFile) { var retval = _targetFolder.Repository.ObjectFactory.GetDataFileAccessor(_currentFolder, targetFile); retval.Coder = Coder; retval.EqualTimestampItemsComparer = EqualTimestampedItemsComparer; return(retval); }
/// <summary> /// Create new instance. /// </summary> /// <param name="containingFolder"> /// Leaf data folder object reference, mandatory. /// </param> /// <param name="fileName"> /// Object representing data file name, optional. /// </param> public RepositoryFile(IDataFolder containingFolder, IRepositoryFileName fileName) { Check.DoRequireArgumentNotNull(containingFolder, "containingFolder"); RepositoryFolder.CheckNotDetached(containingFolder.RepoFolder); ContainingFolder = containingFolder; Name = fileName; }
/// <summary> /// Get child data file next to the specified data file. /// </summary> /// <param name="file"> /// The data file which neighbour to find /// </param> /// <param name="backwards"> /// The direction in which to go from <paramref name="file"/>: /// <see langword="true"/>: to the past /// <see langword="false"/>: to the future /// </param> /// <returns> /// Existing data file which is contained in this data folder or <see langword="null"/> if the sought data file /// does not exist. /// </returns> /// <exception cref="InvalidOperationException"> /// This is not a leaf folder /// </exception> public IRepositoryFileName GetNextDataFile(IRepositoryFileName file, bool backwards) { Check.RequireLambda(IsLeafFolder, () => new InvalidOperationException("Operation not supported on non-leaf folders")); DateTime seekTime = backwards ? file.FirstItemTimestamp.AddTicks(-1) : file.End; return(_dataFileBrowser.GetFile(seekTime, backwards)); }
/// <summary> /// Create data file accessor instance. /// </summary> /// <param name="folder"> /// Data folder containig the file. /// </param> /// <param name="file"> /// Data file to be accessed; may not exist on disk. /// </param> /// <returns> /// New <see cref="IDataFileAccessor"/> instance. /// </returns> public IDataFileAccessor GetDataFileAccessor(IDataFolder folder, IRepositoryFileName file) { Check.DoRequireArgumentNotNull(folder, "folder"); Check.DoRequireArgumentNotNull(file, "file"); RepositoryFolder.CheckNotDetached(folder.RepoFolder); return(new RepositoryFileAccessor(folder, file)); }
/// <summary> /// Discarding changes if dirty. Call <see cref="Flush"/> to save changes. /// </summary> public void Close() { FirstItemTimestamp = DateTime.MaxValue; LastItemTimestamp = DateTime.MinValue; _existinglFilePath = null; _dataItems = null; _dataFolder = null; _repoFile = null; }
/// <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; }
/// <summary> /// Get data files around the specified item timestamp /// </summary> /// <param name="itemTimestamp"> /// The data item timestamp /// </param> /// <param name="predecessor"> /// The file if any which ends before the specified timestamp /// </param> /// <param name="owner"> /// The file covering the specified item timestamp /// </param> /// <param name="successor"> /// The file which starts after the specified timestamp /// </param> public void GetDataFiles(DateTime itemTimestamp , out IRepositoryFileName predecessor , out IRepositoryFileName owner , out IRepositoryFileName successor) { Check.Require(_container.Start <= itemTimestamp && _container.End > itemTimestamp); _files.GetItems(itemTimestamp, out predecessor, out owner, out successor); }
/// <summary> /// Create accessor for a file and retrieve compressor from repository's /// object factory by the file extension /// </summary> /// <param name="folder"> /// Containing repo folder /// </param> /// <param name="repoFile"> /// Target data file, optional. /// </param> /// <param name="dataFolder"> /// Leaf data folder containing <paramref name="repoFile"/> /// </param> /// <param name="equalTimestampedItemsComparer"> /// Comparer for data items with equal timestamps, optional. /// </param> internal RepositoryFileAccessor( IFolder folder , IRepositoryFileName repoFile , IDataFolder dataFolder , IComparer <IDataItem> equalTimestampedItemsComparer) : this(dataFolder, repoFile , folder.Repository.ObjectFactory.GetCompressor(repoFile.CompressorCode) , equalTimestampedItemsComparer) { }
private IRepositoryFile GetContainedRepositoryFile(IRepositoryFileName fileName) { IRepositoryFile retval = null; if (null != fileName) { retval = new RepositoryFile(containingFolder: this, fileName: fileName); } return(retval); }
/// <summary> /// Handle creation, renaming, or deletion of any file belonging to this container /// </summary> /// <param name="firstItemTimestamp"> /// First item timestamp before the change; use <see cref="DateTime.MinValue"/> to handle creation /// </param> /// <param name="newFileName"> /// File name after the change; use <see langword="null"/> to handle deletion /// </param> /// <remarks> /// /// </remarks> private void HandleFileChanged(DateTime firstItemTimestamp, IRepositoryFileName newFileName) { if (firstItemTimestamp != DateTime.MinValue) { bool removed = DeleteFile(firstItemTimestamp); } if (newFileName != null) { AddFile(newFileName); } }
/// <summary> /// Not thread-safe /// </summary> private void AddFile(IRepositoryFileName file) { RequireFileValid(file); try { // overlapping and duplicates handled inside Add _files.Add(file); } catch (OverlappingRangesException e) { throw new OverlappingFileInContainer(e, _container.RelativePath); } }
public void Refresh() { string dirPath = this.FullPath; IEnumerable <string> files = _folder.Repository.ObjectFactory.FileSystemProvider.DirectoryProvider.EnumerateFiles(dirPath, "*"); _files = new IndexedRangeTreeDictionary <DateTime, IRepositoryFileName>(f => f.FirstItemTimestamp, f => f.End); foreach (string filePath in files) { IRepositoryFileName repoFile = _folder.Repository.ObjectFactory.GetFileDescriptor(System.IO.Path.GetFileName(filePath)); if (null != repoFile) { AddFile(repoFile); } } }
/// <summary> /// /// </summary> /// <param name="dataFolder"> /// Leaf data folder in which the data files will be accessed. /// </param> /// <param name="repoFile"> /// Target repo file, optional. New instance will be created using object factory if null is supplied. /// </param> /// <param name="coder"> /// Compressor instance /// </param> /// <param name="equalTimestampedItemsComparer"> /// Comparer to use when sorting data items for items with equal timestamps. /// When timestamps are not equal the comparer has no effect. /// </param> internal RepositoryFileAccessor( IDataFolder dataFolder , IRepositoryFileName repoFile , ICoder coder , IComparer <IDataItem> equalTimestampedItemsComparer) { Check.DoRequireArgumentNotNull(dataFolder, "dataFolder"); Check.DoRequireArgumentNotNull(repoFile, "repoFile"); Check.DoRequireArgumentNotNull(coder, "coder"); RepositoryFolder.CheckNotDetached(dataFolder.RepoFolder); _folder = dataFolder.RepoFolder; _repoFile = repoFile; _dataFolder = dataFolder; if (_repoFile == null) { _repoFile = _folder.Repository.ObjectFactory.CreateNewFile(_folder); } this.Coder = coder; if (repoFile.Encrypted) { this.Encryptor = _folder.Repository.ObjectFactory.GetEncryptor(repoFile.EncryptorCode); } if (_folder.Repository.ObjectFactory.FileSystemProvider.FileProvider.Exists(this.FilePath)) { _existinglFilePath = this.FilePath; } else { _dataItems = new List <IDataItem>(); } _isSorted = true; this.EqualTimestampItemsComparer = equalTimestampedItemsComparer; FirstItemTimestamp = DateTime.MaxValue; LastItemTimestamp = DateTime.MinValue; }
/// <summary> /// Get next data file in the same repo folder. /// </summary> /// <param name="backwards"> /// The direction in which to look for data file relative to this file: to the past or to the future /// </param> /// <returns> /// Next data file or <see langword="null"/> if none exists. /// </returns> public IRepositoryFile GetNext(bool backwards) { IRepositoryFile retval = null; IRepositoryFileName fileInSameFolder = ContainingFolder.GetNextDataFile(this.Name, backwards); if (null != fileInSameFolder) { retval = new RepositoryFile(containingFolder: ContainingFolder, fileName: fileInSameFolder); } else { // scanning sibling leaf folders until first data file is found for ( IDataFolder nextFolder = ContainingFolder.GetNextSiblingInTree(backwards); nextFolder != null && retval == null; nextFolder = nextFolder.GetNextSiblingInTree(backwards)) { retval = nextFolder.FindFirstDataFile(backwards); } } return(retval); }
private static int CompareFiles(IRepositoryFileName file1, IRepositoryFileName file2) { return(DateTime.Compare(file1.FirstItemTimestamp, file2.FirstItemTimestamp)); }
private void RequireFileValid(IRepositoryFileName file) { Util.Check.RequireArgumentNotNull(file, "file"); Util.Check.RequireLambda(file.FirstItemTimestamp <= file.LastItemTimestamp, () => StorageResources.InvalidFileNamingFirstLast); }
/// <summary> /// Notify container that a file was changed /// </summary> /// <param name="firstItemTimestamp"> /// The timestamp of the file as it has been known to the container /// (the value before the change happened) /// </param> /// <param name="newFileName"> /// New file name /// </param> /// <exception cref="FileContainerNotificationException"> /// The file cannot be found in the container; possible concurrency issue /// </exception> /// <exception cref="OverlappingFileInContainer"> /// The <paramref name="newRepoFile"/> overlaps with an existing file; possible concurrency issue or internal error. /// </exception> public void FileChanged(DateTime firstItemTimestamp, IRepositoryFileName newFileName) { FileDeleted(firstItemTimestamp); FileAdded(newFileName); }
/// <summary> /// Perform necessary operations after a new file has been added to the container. /// </summary> /// <param name="newRepoFile"> /// New file added to the container /// </param> /// <exception cref="OverlappingFileInContainer"> /// The <paramref name="newRepoFile"/> overlaps with an existing file; possible concurrency issue or internal error. /// </exception> public void FileAdded(IRepositoryFileName newRepoFile) { AddFile(newRepoFile); }
public SeekFileResult(DateTime seekTime, IDataFolder foundFolder, IRepositoryFileName foundFile) { this.SeekDateTime = seekTime; this.RepositoryFile = new RepositoryFile(containingFolder: foundFolder, fileName: foundFile); }
public void DeleteFile(IRepositoryFileName file) { throw new NotImplementedException(); }
/// <summary> /// Create new instance. /// </summary> /// <param name="folder"> /// Data folder where file will be stored. /// </param> /// <param name="file"> /// File name instance, optional. /// </param> /// <remarks> /// If <paramref name="file"/> is not supplied new instance will be created using the object factory (<see cref="IRepository.ObjectFactory"/>). /// Coder and encryptor will be set from the object factory as well. They may be overridden afterwards. /// </remarks> public RepositoryFileAccessor(IDataFolder folder, IRepositoryFileName file) : this(folder : folder.RepoFolder, repoFile : file, dataFolder : folder, equalTimestampedItemsComparer : null) { }
/// <summary> /// Get full path of the contained data file /// </summary> /// <param name="file"> /// </param> /// <returns> /// </returns> /// <remarks> /// This must be a leaf folder /// </remarks> private string GetDataFilePath(IRepositoryFileName file) { Check.Require(IsLeafFolder); return(Path.Combine(FullPath, file.FileName)); }