Example #1
0
        private long RecoverFreeBlocks()
        {
            Trace.TraceWarning("The file store was not closed properly, recovering free blocks.");

            using (Stream s = _streamCache.Open(FileAccess.ReadWrite))
                using (FileBlock block = new FileBlock(_blockSize, _useAlignedIo))
                {
                    long lastBlock = LastAllocated(s);
                    long last      = 0;
                    for (long blk = lastBlock; blk > 0; blk -= _blockSize)
                    {
                        s.Position = blk & _maskOffset;
                        block.Read(s, FileBlock.HeaderSize);
                        Check.Assert <InvalidDataException>((block.BlockId & _maskOffset) == blk);
                        if ((block.Flags & BlockFlags.BlockDeleted) == BlockFlags.BlockDeleted)
                        {
                            block.NextBlockId = last;
                            last       = block.BlockId;
                            s.Position = blk & _maskOffset;
                            block.Write(s, FileBlock.HeaderSize);
                        }
                    }
                    return(last);
                }
        }
Example #2
0
        private void ReadBlock(long ordinal, FileBlock block, int length, BlockFlags type, bool exactId)
        {
            using (Stream io = OpenBlock(FileAccess.Read, ordinal))
                block.Read(io, length);

            if (exactId && block.BlockId != ordinal)
            {
                throw new InvalidDataException();
            }

            if ((block.Flags & type) == 0 && type != 0)
            {
                throw new InvalidDataException();
            }

            if (block.Length < 0 || block.Length > (_blockSize - FileBlock.HeaderSize))
            {
                throw new InvalidDataException();
            }
        }
Example #3
0
        /// <summary> Used for enumeration of the storage blocks in the file. </summary>
        /// <param name="allocatedOnly"> Allows enumeration of all stream, or of just the externally allocated streams </param>
        /// <param name="verifyReads"> Determines if the checksum should be verified while reading the block bytes </param>
        /// <param name="ignoreException"> A method that returns true to ignore the exception and continue processing </param>
        /// <returns>Enumeration of the identity and data stream of each block in the file</returns>
        public IEnumerable <KeyValuePair <long, Stream> > ForeachBlock(bool allocatedOnly, bool verifyReads, Converter <Exception, bool> ignoreException)
        {
            using (Stream s = _streamCache.Open(FileAccess.ReadWrite))
                using (FileBlock block = new FileBlock(_blockSize, _useAlignedIo))
                {
                    long lastBlock = LastAllocated(s);
                    for (long blk = lastBlock; blk > 0; blk -= _blockSize)
                    {
                        s.Position = blk & _maskOffset;
                        block.Read(s, FileBlock.HeaderSize);

                        byte[] bytes;
                        try
                        {
                            if ((block.BlockId & _maskOffset) != blk)
                            {
                                throw new InvalidDataException();
                            }
                            if (allocatedOnly && (block.Flags & BlockFlags.ExternalBlock) != BlockFlags.ExternalBlock)
                            {
                                continue;
                            }

                            using (Stream reader = new BlockStreamReader(this, block.BlockId, BlockFlags.None, verifyReads))
                                bytes = IOStream.ReadAllBytes(reader);
                        }
                        catch (Exception error)
                        {
                            if (ignoreException != null && ignoreException(error))
                            {
                                continue;
                            }
                            throw;
                        }

                        using (Stream ms = new MemoryStream(bytes, false))
                            yield return(new KeyValuePair <long, Stream>(block.BlockId, ms));
                    }
                }
        }
Example #4
0
        private long AllocBlock(FileBlock block, BlockFlags type)
        {
            using (new SafeLock(_syncFreeBlock))
            {
                long blockId = _nextFree;
                if (blockId == 0 && _reallocSize > 0)
                {
                    long fsize;
                    using (Stream s = _streamCache.Open(FileAccess.Read))
                        fsize = LastAllocated(s);
                    ResizeFile(fsize + _blockSize, fsize + _reallocSize);
                    blockId = _nextFree;
                }

                if (blockId <= 0)
                {
                    throw new IOException();
                }

                using (Stream io = OpenBlock(FileAccess.Read, blockId))
                    block.Read(io, FileBlock.HeaderSize);

                if ((block.BlockId & _maskOffset) != (blockId & _maskOffset) || (block.Flags & BlockFlags.BlockDeleted) == 0)
                {
                    throw new InvalidDataException();
                }

                _nextFree = block.NextBlockId;

                block.BlockId = blockId;
                block.IncrementId(_maskVersion);
                block.NextBlockId = 0;
                block.Flags       = type == BlockFlags.ExternalBlock ? (type | BlockFlags.Temporary) : type;
                block.Length      = 0;
                WriteBlock(block.BlockId, block, FileBlock.HeaderSize);
                return(block.BlockId);
            }
        }
Example #5
0
        /// <summary> Internal use to specify aligned IO when using NoBuffering file option </summary>
        protected FragmentedFile(IFactory <Stream> streamFactory, int blockSize, int growthRate, int cacheLimit, FileOptions options)
        {
            _useAlignedIo  = (options & NoBuffering) == NoBuffering;
            _streamCache   = new StreamCache(streamFactory, cacheLimit);
            _header        = new FileBlock(blockSize, _useAlignedIo);
            _syncFreeBlock = new object();
            try
            {
                long fallocated;
                bool canWrite;

                using (Stream s = _streamCache.Open(FileAccess.ReadWrite))
                {
                    canWrite = s.CanWrite;
                    if (!s.CanRead)
                    {
                        throw new InvalidOperationException("The stream does not support Read access.");
                    }

                    _header.Read(s, blockSize);

                    if ((_header.Flags & ~BlockFlags.HeaderFilter) != BlockFlags.HeaderFlags)
                    {
                        throw new InvalidDataException();
                    }

                    _nextFree = _header.NextBlockId;
                    SetBlockSize(_header.Length, out _blockSize, out _maskVersion, out _maskOffset);
                    if (blockSize != _blockSize)
                    {
                        throw new ArgumentOutOfRangeException("blockSize");
                    }
                    fallocated   = LastAllocated(s);
                    _reallocSize = growthRate * _blockSize;

                    if (canWrite)
                    {
                        s.Position          = 0;
                        _header.NextBlockId = long.MinValue;
                        _header.Write(s, FileBlock.HeaderSize);
                    }
                }

                if (canWrite)
                {
                    if ((_header.Flags & BlockFlags.ResizingFile) == BlockFlags.ResizingFile && _nextFree > 0)
                    {
                        ResizeFile(_nextFree, Math.Max(fallocated, _nextFree + _reallocSize));
                    }

                    if (_nextFree == long.MinValue)
                    {
                        _nextFree = RecoverFreeBlocks();
                    }
                }
            }
            catch
            {
                _streamCache.Dispose();
                throw;
            }
        }
        private void ReadBlock(long ordinal, FileBlock block, int length, BlockFlags type, bool exactId)
        {
            using (Stream io = OpenBlock(FileAccess.Read, ordinal))
                block.Read(io, length);

            if (exactId && block.BlockId != ordinal)
                throw new InvalidDataException();

            if ((block.Flags & type) == 0 && type != 0)
                throw new InvalidDataException();

            if (block.Length < 0 || block.Length > (_blockSize - FileBlock.HeaderSize))
                throw new InvalidDataException();
        }
        private long AllocBlock(FileBlock block, BlockFlags type)
        {
            using (new SafeLock(_syncFreeBlock))
            {
                long blockId = _nextFree;
                if (blockId == 0 && _reallocSize > 0)
                {
                    long fsize;
                    using (Stream s = _streamCache.Open(FileAccess.Read))
                        fsize = LastAllocated(s);
                    ResizeFile(fsize + _blockSize, fsize + _reallocSize);
                    blockId = _nextFree;
                }

                if (blockId <= 0)
                    throw new IOException();

                using (Stream io = OpenBlock(FileAccess.Read, blockId))
                    block.Read(io, FileBlock.HeaderSize);

                if ((block.BlockId & _maskOffset) != (blockId & _maskOffset) || (block.Flags & BlockFlags.BlockDeleted) == 0)
                    throw new InvalidDataException();

                _nextFree = block.NextBlockId;
            
                block.BlockId = blockId;
                block.IncrementId(_maskVersion);
                block.NextBlockId = 0;
                block.Flags = type == BlockFlags.ExternalBlock ? (type | BlockFlags.Temporary) : type;
                block.Length = 0;
                WriteBlock(block.BlockId, block, FileBlock.HeaderSize); 
                return block.BlockId;
            }
        }
        /// <summary> Used for enumeration of the storage blocks in the file. </summary>
        /// <param name="allocatedOnly"> Allows enumeration of all stream, or of just the externally allocated streams </param>
        /// <param name="verifyReads"> Determines if the checksum should be verified while reading the block bytes </param>
        /// <param name="ignoreException"> A method that returns true to ignore the exception and continue processing </param>
        /// <returns>Enumeration of the identity and data stream of each block in the file</returns>
        public IEnumerable<KeyValuePair<long, Stream>> ForeachBlock(bool allocatedOnly, bool verifyReads, Converter<Exception, bool> ignoreException)
        {
            using (Stream s = _streamCache.Open(FileAccess.ReadWrite))
            using (FileBlock block = new FileBlock(_blockSize, _useAlignedIo))
            {
                long lastBlock = LastAllocated(s);
                for (long blk = lastBlock; blk > 0; blk -= _blockSize)
                {
                    s.Position = blk & _maskOffset;
                    block.Read(s, FileBlock.HeaderSize);

                    byte[] bytes;
                    try
                    {
                        if ((block.BlockId & _maskOffset) != blk)
                            throw new InvalidDataException();
                        if (allocatedOnly && (block.Flags & BlockFlags.ExternalBlock) != BlockFlags.ExternalBlock)
                            continue;

                        using (Stream reader = new BlockStreamReader(this, block.BlockId, BlockFlags.None, verifyReads))
                            bytes = IOStream.ReadAllBytes(reader);
                    }
                    catch (Exception error)
                    {
                        if (ignoreException != null && ignoreException(error))
                            continue;
                        throw;
                    }

                    using (Stream ms = new MemoryStream(bytes, false))
                        yield return new KeyValuePair<long, Stream>(block.BlockId, ms);
                }
            }
        }
        private long RecoverFreeBlocks()
        {
            Trace.TraceWarning("The file store was not closed properly, recovering free blocks.");

            using (Stream s = _streamCache.Open(FileAccess.ReadWrite))
            using (FileBlock block = new FileBlock(_blockSize, _useAlignedIo))
            {
                long lastBlock = LastAllocated(s);
                long last = 0;
                for (long blk = lastBlock; blk > 0; blk -= _blockSize)
                {
                    s.Position = blk & _maskOffset;
                    block.Read(s, FileBlock.HeaderSize);
                    Check.Assert<InvalidDataException>((block.BlockId & _maskOffset) == blk);
                    if ((block.Flags & BlockFlags.BlockDeleted) == BlockFlags.BlockDeleted)
                    {
                        block.NextBlockId = last;
                        last = block.BlockId;
                        s.Position = blk & _maskOffset;
                        block.Write(s, FileBlock.HeaderSize);
                    }
                }
                return last;
            }
        }
        /// <summary> Internal use to specify aligned IO when using NoBuffering file option </summary>
        protected FragmentedFile(IFactory<Stream> streamFactory, int blockSize, int growthRate, int cacheLimit, FileOptions options)
        {
            _useAlignedIo = (options & NoBuffering) == NoBuffering;
            _streamCache = new StreamCache(streamFactory, cacheLimit);
            _header = new FileBlock(blockSize, _useAlignedIo);
            _syncFreeBlock = new object();
            try
            {
                long fallocated;
                bool canWrite;

                using (Stream s = _streamCache.Open(FileAccess.ReadWrite))
                {
                    canWrite = s.CanWrite;
                    if (!s.CanRead)
                        throw new InvalidOperationException("The stream does not support Read access.");

                    _header.Read(s, blockSize);

                    if ((_header.Flags & ~BlockFlags.HeaderFilter) != BlockFlags.HeaderFlags)
                        throw new InvalidDataException();

                    _nextFree = _header.NextBlockId;
                    SetBlockSize(_header.Length, out _blockSize, out _maskVersion, out _maskOffset);
                    if (blockSize != _blockSize) throw new ArgumentOutOfRangeException("blockSize");
                    fallocated = LastAllocated(s);
                    _reallocSize = growthRate * _blockSize;

                    if (canWrite)
                    {
                        s.Position = 0;
                        _header.NextBlockId = long.MinValue;
                        _header.Write(s, FileBlock.HeaderSize);
                    }
                }

                if (canWrite)
                {
                    if ((_header.Flags & BlockFlags.ResizingFile) == BlockFlags.ResizingFile && _nextFree > 0)
                        ResizeFile(_nextFree, Math.Max(fallocated, _nextFree + _reallocSize));

                    if (_nextFree == long.MinValue)
                        _nextFree = RecoverFreeBlocks();
                }
            }
            catch
            {
                _streamCache.Dispose();
                throw;
            }
        }