Example #1
0
        /// <summary>
        ///		Set custom property value.
        /// </summary>
        /// <param name="name">
        ///		Property name.
        /// </param>
        /// <param name="value">
        ///		Property value. Specify null to remove property.
        /// </param>
        /// <remarks>
        ///		Every repository folder can have an arbitrary set of named string properties. This should not be overused as the storage is not optimised for performance and
        ///		large volumes of data.
        ///		If property with the specified name is already set it will be overwritten. To remove a propert set its value to null.
        ///		The value is immediately saved to disk.
        /// </remarks>
        /// <seealso cref="GetCustomProperty(string)"/>
        public void SetCustomProperty(string name, string value)
        {
            RepositoryFolder.CheckNotDetached(_folder);

            Check.RequireArgumentNotNull(name, "name");

            NameValuePair pair = FindCustomProperty(name);

            if (pair != null)
            {
                if (value == null)
                {
                    _folderConfig.Config.CustomParameters.Remove(pair);
                }
                else
                {
                    pair.Value = value;
                }
            }
            else
            {
                _folderConfig.Config.CustomParameters.Add(new NameValuePair()
                {
                    Name = name, Value = value
                });
            }

            Save();
        }
        /// <summary>
        ///		Initialise iteration position.
        /// </summary>
        /// <param name="seekTime">
        ///		Data timestamp; files containig data items with the timestamp will be iterated.
        /// </param>
        /// <param name="backwards">
        ///		Direction in which to search for data files if the <paramref name="seekTime"/> is not covered by any
        ///		existing data file
        /// </param>
        /// <returns>
        ///		First found data file; null if none found.
        /// </returns>
        /// <remarks>
        ///		The data in a data file does not have to be entirely in the specified datetime range for the file to be iterated. If any data in the file
        ///		falls in the sought range it will be returned by the iterator.
        /// </remarks>
        /// <exception cref="ObjectDisposedException">
        ///		The target repository instance is disposed.
        /// </exception>
        /// <exception cref="InvalidOperationException">
        ///		The <paramref name="targetFolder"/> is detached.
        /// </exception>
        public IRepositoryFile Seek(DateTime seekTime, bool backwards)
        {
            RepositoryFolder.CheckNotDetached(Folder);

            DateTime        seekTimeCorrected;
            IRepositoryFile currentFile = _targetFolder.RootDataFolder.Seek(seekTime, backwards);

            if (currentFile != null)
            {
                seekTimeCorrected = currentFile.Name.FirstItemTimestamp;
            }
            else
            {
                seekTimeCorrected = seekTime;
            }

            SeekExact(seekTimeCorrected);

            Check.Ensure(Current == null || Current.Name == currentFile.Name, "Seek results differ");
            Check.Ensure(Current == null ||
                         GetComparer(backwards).Compare(
                             backwards ? Current.Name.FirstItemTimestamp : Current.Name.LastItemTimestamp
                             , seekTime
                             ) >= 0
                         );
            Check.Ensure(NextBackwards == null || NextBackwards.Name.End <= seekTime);
            Check.Ensure(NextForward == null || NextForward.Name.FirstItemTimestamp > seekTime);
            return(Current);
        }
Example #3
0
 /// <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>
 ///		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;
 }
        /// <summary>
        ///		Only set current if owns the <paramref name="seekTime"/>. Set next and previous as per <paramref name="seekTime"/>
        /// </summary>
        /// <param name="seekTime">
        ///		Data timestamp
        /// </param>
        /// <returns>
        ///		Existing <see cref="IRepositoryFile"/> if it covers the <paramref name="seekTime"/>.
        ///		<see langword="null"/> otherwise
        /// </returns>
        /// <exception cref="ObjectDisposedException">
        ///		The target repository instance is disposed.
        /// </exception>
        /// <exception cref="InvalidOperationException">
        ///		The <paramref name="targetFolder"/> is detached.
        /// </exception>
        public IRepositoryFile SeekExact(DateTime seekTime)
        {
            RepositoryFolder.CheckNotDetached(Folder);

            IRepositoryFile owner;
            IRepositoryFile predecessor;
            IRepositoryFile successor;

            _targetFolder.RootDataFolder.CutDataFiles(seekTime, out predecessor, out owner, out successor);

            Current       = owner;
            NextBackwards = predecessor;
            NextForward   = successor;

            if (Backwards)
            {
                Next     = NextBackwards;
                Previous = NextForward;
            }
            else
            {
                Next     = NextForward;
                Previous = NextBackwards;
            }

            return(Current);
        }
Example #6
0
        /// <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));
        }
Example #7
0
        /// <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;
        }
Example #8
0
        /// <summary>
        ///		Create regular folder object instance
        /// </summary>
        /// <param name="parent">
        ///		Parent folder
        /// </param>
        /// <param name="name">
        ///		Folder name
        /// </param>
        /// <returns>
        ///		New instance of regular repository folder
        /// </returns>
        public virtual IFolder GetFolder(IFolder parent, string name)
        {
            CheckHelper.CheckRepositoryNotDisposed(Repository);
            Check.DoRequireArgumentNotNull(parent, "parent");
            RepositoryFolder.CheckNotDetached(parent);
            Exceptions.DifferentRepositoriesExceptionHelper.Check(Repository, parent.Repository);

            return(new RepositoryFolder(parent, name));
        }
Example #9
0
        /// <summary>
        ///		Force save to disk.
        /// </summary>
        public void Save()
        {
            RepositoryFolder.CheckNotDetached(_folder);

            using (var scope = StorageTransactionScope.Create(_folder.Repository))
            {
                _folderConfig.Save(this.ConfigFilePath, this.FileProvider);
                scope.Complete();
            }
        }
Example #10
0
        /// <summary>
        ///		Delete properties from disk.
        /// </summary>
        public void Delete()
        {
            RepositoryFolder.CheckNotDetached(_folder);

            using (var scope = StorageTransactionScope.Create(_folder.Repository))
            {
                if (ConfigFileExists)
                {
                    this.FileProvider.Delete(this.ConfigFilePath);
                }
                scope.Complete();
            }
        }
Example #11
0
        /// <summary>
        ///		Get custom property value.
        /// </summary>
        /// <param name="name">
        ///		Property name.
        /// </param>
        /// <returns>
        ///		Custom property value or null if not set.
        /// </returns>
        /// <remarks>
        ///		Every repository folder can have an arbitrary set of named string properties. This should not be overused as the storage is not optimised for performance and
        ///		large volumes of data.
        /// </remarks>
        /// <seealso cref="SetCustomProperty(string, string)"/>
        public string GetCustomProperty(string name)
        {
            RepositoryFolder.CheckNotDetached(_folder);

            string        retval = null;
            NameValuePair pair   = FindCustomProperty(name);

            if (pair != null)
            {
                retval = pair.Value;
            }
            return(retval);
        }
Example #12
0
        /// <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);
        }
        /// <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>
        ///		Move current file to the next file.
        /// </summary>
        /// <param name="backwards">
        ///		The direction in which to move
        /// </param>
        /// <returns>
        ///		New current file (either <see cref="NextForward"/> or <see cref="NextBackwards"/> prior to the call to this method)
        /// </returns>
        /// <remarks>
        ///		Does nothing if <see cref="Current"/> and <see cref="Next"/> are already <see langword="null"/>.
        ///		Otherwise the iterator will not be able to go back.
        /// </remarks>
        /// <exception cref="ObjectDisposedException">
        ///		The target repository instance is disposed.
        /// </exception>
        /// <exception cref="InvalidOperationException">
        ///		The <paramref name="targetFolder"/> is detached.
        /// </exception>
        public IRepositoryFile MoveNext(bool backwards)
        {
            RepositoryFolder.CheckNotDetached(Folder);

            if (Current != null || Next != null)
            {
                Previous = Current;
                if (backwards)
                {
                    NextForward = Current;
                    Current     = NextBackwards;
                    Next        = NextBackwards = GetNextNullSafe(Current, backwards);
                }
                else
                {
                    NextBackwards = Current;
                    Current       = NextForward;
                    Next          = NextForward = GetNextNullSafe(Current, backwards);
                }
            }
            return(Current);
        }
        /// <summary>
        ///		Create single folder writer and add it to the collection of writers.
        /// </summary>
        /// <param name="targetFolder">
        ///		Target folder for writer
        /// </param>
        /// <returns>
        ///		New initialised instance. If the method succeeds (does not throw exception)
        /// </returns>
        /// <remarks>
        ///		Locking sequence: target folder lock start, then repo manager's registry lock/release, then direct writers collection lock/release,
        ///		then target folder released.
        /// </remarks>
        private DirectSingleFolderWriter CreateWriter(IRepositoryFolder targetFolder, string normalisedRelativePath)
        {
            Check.RequireArgumentNotNull(targetFolder, "targetFolder");
            RepositoryFolder.CheckNotDetached(targetFolder);

            IFolder folder = RepositoryFolder.CastFolder(targetFolder);

            Exceptions.DifferentRepositoriesExceptionHelper.Check(Folder.Repository, targetFolder.Repository);

            DirectSingleFolderWriter writer = null;

            ICoder compressor = GetCompressor(targetFolder: targetFolder);
            ICoder encryptor  = GetEncryptor(targetFolder: targetFolder);

            lock (targetFolder)
            {
                Check.DoAssertLambda(
                    object.ReferenceEquals(targetFolder, _repoFolder) ||                                                        // this writer has already seized this folder as target
                    !Folder.Repository.IsDataBeingWrittenTo(targetFolder, false),
                    () => new InvalidOperationException(string.Format(StorageResources.WriterAlreadyExistsForFolder, targetFolder.LogicalPath)));

                writer = new DirectSingleFolderWriter(folder, compressor, encryptor);
                writer.EqualTimestampedItemsComparer = this.EqualTimestampedItemsComparer;

                lock (_directWritersByRelativePath)
                {
                    _directWritersByRelativePath.Add(normalisedRelativePath, writer);
                    _directWritersByFolderKey.Add(targetFolder.FolderKey, writer);
                }
            }

            writer.TrackUnsavedItems = TrackUnsavedItems;

            Check.Ensure(Repository.IsDataBeingWrittenTo(targetFolder, false));
            return(writer);
        }
Example #16
0
        /// <summary>
        ///		Load properties from disk.
        /// </summary>
        public void Load()
        {
            RepositoryFolder.CheckNotDetached(_folder);

            _folderConfig = RepoFolderXmlConfig.Load(this.ConfigFilePath, this.FileProvider);
        }