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); } }
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(); } }
/// <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 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> 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; } }