/// <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;
 }
Beispiel #2
0
        /// <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);
        }
Beispiel #3
0
        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);
        }
Beispiel #4
0
        /// <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);
        }
        /// <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));
        }
Beispiel #6
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>
        ///		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);
        }