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> /// Creates a new file (or truncates an existing one) that stores multiple smaller files /// </summary> private static void WriteEmtpy(IFactory <Stream> streamFactory, int blockSize) { long mask; SetBlockSize(blockSize, out blockSize, out mask, out mask); using (FileBlock block = new FileBlock(Check.InRange(blockSize, 512, /*65,536*/ 0x10000), false)) { block.Length = blockSize; block.Flags = BlockFlags.HeaderFlags; using (Stream f = streamFactory.Create()) { f.Position = 0; block.Write(f, blockSize); f.SetLength(f.Position); } } }
private void WriteBlock(long ordinal, FileBlock block, int length) { if (block.BlockId != ordinal) { throw new InvalidDataException(); } if (block.Length < 0 || block.Length > (_blockSize - FileBlock.HeaderSize)) { throw new InvalidDataException(); } try { } finally { using (Stream io = OpenBlock(FileAccess.Write, ordinal)) block.Write(io, length); } }
private void ResizeFile(long startBlock, long endBlock) { if ((startBlock & _maskVersion) != 0 || (endBlock & _maskVersion) != 0) { throw new InvalidDataException(); } using (FileBlock block = new FileBlock(_blockSize, _useAlignedIo)) using (Stream io = _streamCache.Open(FileAccess.Write)) { _header.Flags |= BlockFlags.ResizingFile; _header.NextBlockId = startBlock; io.Position = 0; _header.Write(io, FileBlock.HeaderSize); try { block.Clear(); block.Flags = BlockFlags.BlockDeleted; _nextFree = 0; for (long ix = endBlock; ix >= startBlock; ix -= _blockSize) { block.BlockId = ix; block.NextBlockId = _nextFree; _nextFree = block.BlockId; io.Position = ix & _maskOffset; block.Write(io, FileBlock.HeaderSize); } } finally { _header.Flags &= ~BlockFlags.ResizingFile; _header.NextBlockId = long.MinValue; io.Position = 0; _header.Write(io, FileBlock.HeaderSize); } } }
private void WriteBlock(long ordinal, FileBlock block, int length) { if (block.BlockId != ordinal) throw new InvalidDataException(); if (block.Length < 0 || block.Length > (_blockSize - FileBlock.HeaderSize)) throw new InvalidDataException(); try { } finally { using (Stream io = OpenBlock(FileAccess.Write, ordinal)) block.Write(io, length); } }
/// <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 ResizeFile(long startBlock, long endBlock) { if ((startBlock & _maskVersion) != 0 || (endBlock & _maskVersion) != 0) throw new InvalidDataException(); using (FileBlock block = new FileBlock(_blockSize, _useAlignedIo)) using (Stream io = _streamCache.Open(FileAccess.Write)) { _header.Flags |= BlockFlags.ResizingFile; _header.NextBlockId = startBlock; io.Position = 0; _header.Write(io, FileBlock.HeaderSize); try { block.Clear(); block.Flags = BlockFlags.BlockDeleted; _nextFree = 0; for (long ix = endBlock; ix >= startBlock; ix -= _blockSize) { block.BlockId = ix; block.NextBlockId = _nextFree; _nextFree = block.BlockId; io.Position = ix & _maskOffset; block.Write(io, FileBlock.HeaderSize); } } finally { _header.Flags &= ~BlockFlags.ResizingFile; _header.NextBlockId = long.MinValue; io.Position = 0; _header.Write(io, FileBlock.HeaderSize); } } }
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> /// Creates a new file (or truncates an existing one) that stores multiple smaller files /// </summary> private static void WriteEmtpy(IFactory<Stream> streamFactory, int blockSize) { long mask; SetBlockSize(blockSize, out blockSize, out mask, out mask); using (FileBlock block = new FileBlock(Check.InRange(blockSize, 512, /*65,536*/0x10000), false)) { block.Length = blockSize; block.Flags = BlockFlags.HeaderFlags; using (Stream f = streamFactory.Create()) { f.Position = 0; block.Write(f, blockSize); f.SetLength(f.Position); } } }
/// <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; } }
/// <summary> /// 写入区块 /// </summary> /// <param name="value">区块对象</param> public void Write(FileBlock value) { if (EnabledIoBuffer) { if (IoBuffer.Count >= IoBufferSize) WriteAllBlock(); lock (IoBuffer) IoBuffer.Add(value.Index, value); } else value.Write(); }