/// <summary> /// Creates a readonly copy of a transaction. /// </summary> /// <param name="dataReader"></param> internal ReadSnapshot(DiskIo dataReader) { if (dataReader == null) throw new ArgumentNullException("dataReader"); m_fileHeaderBlock = dataReader.LastCommittedHeader; m_dataReader = dataReader; }
private static void TestOpenExistingFile(DiskIo stream, FileHeaderBlock fat) { Guid id = Guid.NewGuid(); TransactionalEdit trans = new TransactionalEdit(stream); //create 3 files SubFileStream fs1 = trans.OpenFile(0); SubFileStream fs2 = trans.OpenFile(1); SubFileStream fs3 = trans.OpenFile(2); //read from them and verify content. SubFileStreamTest.TestSingleByteRead(fs1); SubFileStreamTest.TestCustomSizeRead(fs2, 5); SubFileStreamTest.TestCustomSizeRead(fs3, BlockDataLength + 20); //rewrite bad data. SubFileStreamTest.TestSingleByteWrite(fs2); SubFileStreamTest.TestCustomSizeWrite(fs3, 5); SubFileStreamTest.TestCustomSizeWrite(fs1, BlockDataLength + 20); fs1.Dispose(); fs2.Dispose(); fs3.Dispose(); trans.CommitAndDispose(); }
private void SetHeaderTab(FileHeaderBlock fileHeaderBlock) { StringBuilder sb = new StringBuilder(); sb.Append("File Type: ").Append(fileHeaderBlock.FileTypeToASCII()).AppendLine(); sb.Append("File Version: ").Append(fileHeaderBlock.FileVersion.ToString()).AppendLine(); if (fileHeaderBlock.CreationMethod == 0) { sb.Append("Creation Method: ").Append("Simulation").AppendLine(); } else { sb.Append("Creation Method: ").Append("Measurement").AppendLine(); } sb.Append("Total Luminous Flux: ").Append(fileHeaderBlock.TotalLuminousFlux.ToString()).AppendLine(); sb.Append("Total Radiant Flux: ").Append(fileHeaderBlock.TotalRadiantFlux.ToString()).AppendLine(); sb.Append("Number of Rays: ").Append(fileHeaderBlock.NumberOfRays.ToString()).AppendLine(); sb.Append("File Creation Data: ").Append(fileHeaderBlock.FileCreationDatetoASCII().ToString()).AppendLine(); sb.Append("Ray Start Position: ").Append(RayStartOptions[fileHeaderBlock.RayStartPosition].ToString()).AppendLine(); sb.Append("Spectral Data Identifier: ").Append(SpectralDataOptions[fileHeaderBlock.SpectralDataIdentifier].ToString()).AppendLine(); sb.Append("Single Wavelength: ").Append(fileHeaderBlock.SingleWavelength.ToString()).AppendLine(); sb.Append("Minimum Wavelength: ").Append(fileHeaderBlock.MinimumWavelength.ToString()).AppendLine(); sb.Append("Maximum Wavelength: ").Append(fileHeaderBlock.MaximumWavelength.ToString()).AppendLine(); sb.Append("Number of Spectral Tables: ").Append(fileHeaderBlock.NumberOfSpectralTables.ToString()).AppendLine(); sb.Append("Number of Additiona Ray Data Items: ").Append(fileHeaderBlock.NumberOfAdditionalRayDataItemsPerRay.ToString()).AppendLine(); sb.Append("Size of Additional Text Block: ").Append(fileHeaderBlock.SizeOfAdditionalTextBlock.ToString()).AppendLine(); sb.Append("Reserved for Additional Use: ").AppendLine(); string headerString = sb.ToString(); richTextBoxHeader.Text = headerString; }
/// <summary> /// Executes a commit of data. This will flush the data to the disk use the provided header data to properly /// execute this function. /// </summary> /// <param name="headerBlock"></param> public void CommitChanges(FileHeaderBlock headerBlock) { if (IsDisposed) { throw new ObjectDisposedException("MemoryStream"); } }
public void Test() { Assert.AreEqual(Globals.MemoryPool.AllocatedBytes, 0L); string fileName = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString() + ".tmp"); try { using (DiskIo stream = DiskIo.CreateFile(fileName, Globals.MemoryPool, BlockSize)) { FileHeaderBlock fat = stream.LastCommittedHeader; //obtain a readonly copy of the file allocation table. fat = stream.LastCommittedHeader; TestCreateNewFile(stream, fat); fat = stream.LastCommittedHeader; TestOpenExistingFile(stream, fat); fat = stream.LastCommittedHeader; TestRollback(stream, fat); fat = stream.LastCommittedHeader; TestVerifyRollback(stream, fat); Assert.IsTrue(true); } } finally { File.Delete(fileName); } Assert.AreEqual(Globals.MemoryPool.AllocatedBytes, 0L); }
private static void TestCreateNewFile(DiskIo stream, FileHeaderBlock fat) { SubFileName id1 = SubFileName.CreateRandom(); SubFileName id2 = SubFileName.CreateRandom(); SubFileName id3 = SubFileName.CreateRandom(); TransactionalEdit trans = new TransactionalEdit(stream); //create 3 files SubFileStream fs1 = trans.CreateFile(id1); SubFileStream fs2 = trans.CreateFile(id2); SubFileStream fs3 = trans.CreateFile(id3); if (fs1.SubFile.FileName != id1) { throw new Exception(); } //write to the three files SubFileStreamTest.TestSingleByteWrite(fs1); SubFileStreamTest.TestCustomSizeWrite(fs2, 5); SubFileStreamTest.TestCustomSizeWrite(fs3, BlockDataLength + 20); //read from them and verify content. SubFileStreamTest.TestCustomSizeRead(fs3, BlockDataLength + 20); SubFileStreamTest.TestCustomSizeRead(fs2, 5); SubFileStreamTest.TestSingleByteRead(fs1); fs1.Dispose(); fs2.Dispose(); fs3.Dispose(); trans.CommitAndDispose(); }
/// <summary> /// Creates a file backed memory stream. /// </summary> /// <param name="stream">The <see cref="CustomFileStream"/> to buffer</param> /// <param name="pool">The <see cref="MemoryPool"/> to allocate memory from</param> /// <param name="header">The <see cref="FileHeaderBlock"/> to be managed when modifications occur</param> /// <param name="isNewFile">Tells if this is a newly created file. This will make sure that the /// first 10 pages have the header data copied to it.</param> public BufferedFile(CustomFileStream stream, MemoryPool pool, FileHeaderBlock header, bool isNewFile) { m_fileStructureBlockSize = header.BlockSize; m_diskBlockSize = pool.PageSize; m_lengthOfHeader = header.BlockSize * header.HeaderBlockCount; m_writeBuffer = new MemoryPoolStreamCore(pool); m_pool = pool; m_queue = stream; m_syncRoot = new object(); m_pageReplacementAlgorithm = new PageReplacementAlgorithm(pool); pool.RequestCollection += m_pool_RequestCollection; if (isNewFile) { try { m_queue.Open(); byte[] headerBytes = header.GetBytes(); for (int x = 0; x < header.HeaderBlockCount; x++) { m_queue.WriteRaw(0, headerBytes, headerBytes.Length); } } finally { m_queue.Close(); } } m_lengthOfCommittedData = (header.LastAllocatedBlock + 1) * header.BlockSize; m_writeBuffer.ConfigureAlignment(m_lengthOfCommittedData, pool.PageSize); }
private static void CheckEqual(FileHeaderBlock RO, FileHeaderBlock RW) { if (!AreEqual(RW, RO)) { throw new Exception(); } }
/// <summary> /// Occurs when committing the following data to the disk. /// This will copy any pending data to the disk in a manner that /// will protect against corruption. /// </summary> /// <param name="header"></param> public void CommitChanges(FileHeaderBlock header) { header.IsReadOnly = true; m_disk.CommitChanges(header); Thread.MemoryBarrier(); m_header = header; }
/// <summary> /// Creates an SubFileStream /// </summary> /// <param name="dataReader">The location to read from.</param> /// <param name="subFile">The file to read.</param> /// <param name="fileHeaderBlock">The FileAllocationTable</param> /// <param name="isReadOnly">Determines if the stream allows editing.</param> internal SubFileStream(DiskIo dataReader, SubFileHeader subFile, FileHeaderBlock fileHeaderBlock, bool isReadOnly) { if (dataReader == null) throw new ArgumentNullException("dataReader"); if (subFile == null) throw new ArgumentNullException("subFile"); if (fileHeaderBlock == null) throw new ArgumentNullException("subFile"); if (!isReadOnly) { if (dataReader.IsReadOnly) throw new ArgumentException("This parameter cannot be read only when opening for writing", "dataReader"); if (fileHeaderBlock.IsReadOnly) throw new ArgumentException("This parameter cannot be read only when opening for writing", "fileHeaderBlock"); if (subFile.IsReadOnly) throw new ArgumentException("This parameter cannot be read only when opening for writing", "subFile"); } if (isReadOnly) { if (!fileHeaderBlock.IsReadOnly) throw new ArgumentException("This parameter must be read only when opening for reading", "fileHeaderBlock"); if (!subFile.IsReadOnly) throw new ArgumentException("This parameter must be read only when opening for reading", "subFile"); } m_blockSize = dataReader.BlockSize; m_dataReader = dataReader; m_subFile = subFile; m_fileHeaderBlock = fileHeaderBlock; m_isReadOnly = isReadOnly; }
/// <summary> /// Creates a <see cref="DiskMedium"/> that is entirely based in memory. /// </summary> /// <param name="pool">the <see cref="MemoryPool"/> to allocate data from</param> /// <param name="fileStructureBlockSize">the block size of the file structure. Usually 4kb.</param> /// <param name="flags">Flags to write to the file</param> /// <returns></returns> public static DiskMedium CreateMemoryFile(MemoryPool pool, int fileStructureBlockSize, params Guid[] flags) { FileHeaderBlock header = FileHeaderBlock.CreateNew(fileStructureBlockSize, flags); MemoryPoolFile disk = new MemoryPoolFile(pool); return(new DiskMedium(disk, header)); }
private static void TestCreateNewFile(DiskIo stream, FileHeaderBlock fat) { SubFileName id1 = SubFileName.CreateRandom(); SubFileName id2 = SubFileName.CreateRandom(); SubFileName id3 = SubFileName.CreateRandom(); TransactionalEdit trans = new TransactionalEdit(stream); //create 3 files SubFileStream fs1 = trans.CreateFile(id1); SubFileStream fs2 = trans.CreateFile(id2); SubFileStream fs3 = trans.CreateFile(id3); if (fs1.SubFile.FileName != id1) throw new Exception(); //write to the three files SubFileStreamTest.TestSingleByteWrite(fs1); SubFileStreamTest.TestCustomSizeWrite(fs2, 5); SubFileStreamTest.TestCustomSizeWrite(fs3, BlockDataLength + 20); //read from them and verify content. SubFileStreamTest.TestCustomSizeRead(fs3, BlockDataLength + 20); SubFileStreamTest.TestCustomSizeRead(fs2, 5); SubFileStreamTest.TestSingleByteRead(fs1); fs1.Dispose(); fs2.Dispose(); fs3.Dispose(); trans.CommitAndDispose(); }
/// <summary> /// Creates a new DiskIoSession that can be used to read from the disk subsystem. /// </summary> /// <param name="diskIo">owner of the disk</param> /// <param name="ioSession">the base ioSession to use for this io session</param> /// <param name="file">The file that will be read from this diskIoSession</param> public DiskIoSession(DiskIo diskIo, BinaryStreamIoSessionBase ioSession, FileHeaderBlock header, SubFileHeader file) { if (diskIo == null) { throw new ArgumentNullException("diskIo"); } if (diskIo.IsDisposed) { throw new ObjectDisposedException(diskIo.GetType().FullName); } if (ioSession == null) { throw new ArgumentNullException("ioSession"); } if (file == null) { throw new ArgumentNullException("file"); } m_args = new BlockArguments(); m_lastReadonlyBlock = diskIo.LastReadonlyBlock; m_diskMediumIoSession = ioSession; m_snapshotSequenceNumber = header.SnapshotSequenceNumber; m_fileIdNumber = file.FileIdNumber; m_isReadOnly = file.IsReadOnly || diskIo.IsReadOnly; m_blockSize = diskIo.BlockSize; m_diskIo = diskIo; IsValid = false; IsDisposed = false; }
private static void TestVerifyRollback(DiskIo stream, FileHeaderBlock fat) { Guid id = Guid.NewGuid(); TransactionalEdit trans = new TransactionalEdit(stream); if (trans.Files.Count != 3) { throw new Exception(); } //open files SubFileStream fs1 = trans.OpenFile(0); SubFileStream fs2 = trans.OpenFile(1); SubFileStream fs3 = trans.OpenFile(2); //read from them and verify content. SubFileStreamTest.TestSingleByteRead(fs2); SubFileStreamTest.TestCustomSizeRead(fs3, 5); SubFileStreamTest.TestCustomSizeRead(fs1, BlockDataLength + 20); fs1.Dispose(); fs2.Dispose(); fs3.Dispose(); trans.Dispose(); }
/// <summary> /// Creates a <see cref="DiskIoSession"/> that can be used to perform basic read/write functions. /// </summary> /// <returns></returns> public DiskIoSession CreateDiskIoSession(FileHeaderBlock header, SubFileHeader file) { if (m_disposed) { throw new ObjectDisposedException(GetType().FullName); } return(new DiskIoSession(this, m_stream.CreateIoSession(), header, file)); }
/// <summary> /// Creates a <see cref="DiskMedium"/> from a <see cref="stream"/>. /// This will initialize the <see cref="stream"/> as an empty file structure. /// </summary> /// <param name="stream">An open <see cref="FileStream"/> to use. The <see cref="DiskMedium"/> /// will assume ownership of this <see cref="FileStream"/>.</param> /// <param name="pool">the <see cref="MemoryPool"/> to allocate data from</param> /// <param name="fileStructureBlockSize">the block size of the file structure. Usually 4kb.</param> /// <param name="flags">Flags to write to the file</param> /// <returns></returns> /// <remarks> /// This will not check if the file is truely a new file. If calling this with an existing /// archive file, it will overwrite the table of contents, corrupting the file. /// </remarks> public static DiskMedium CreateFile(CustomFileStream stream, MemoryPool pool, int fileStructureBlockSize, params Guid[] flags) { FileHeaderBlock header = FileHeaderBlock.CreateNew(fileStructureBlockSize, flags); BufferedFile disk = new BufferedFile(stream, pool, header, isNewFile: true); return(new DiskMedium(disk, header)); }
/// <summary> /// Creates a simplified file writer. /// </summary> /// <param name="pendingFileName"></param> /// <param name="completeFileName"></param> /// <param name="blockSize"></param> /// <param name="flags"></param> public SimplifiedFileWriter(string pendingFileName, string completeFileName, int blockSize, params Guid[] flags) { m_pendingFileName = pendingFileName; m_completeFileName = completeFileName; m_fileHeaderBlock = FileHeaderBlock.CreateNewSimplified(blockSize, flags).CloneEditable(); m_fileHeaderBlock.ArchiveType = SortedTreeFile.FileType; m_stream = new FileStream(pendingFileName, FileMode.CreateNew, FileAccess.ReadWrite, FileShare.None); }
/// <summary> /// Creates a <see cref="DiskMedium"/> from a <see cref="stream"/>. /// This will read the existing header from the <see cref="stream"/>. /// </summary> /// <param name="stream">An open <see cref="FileStream"/> to use. The <see cref="DiskMedium"/> /// will assume ownership of this <see cref="FileStream"/>.</param> /// <param name="pool">The <see cref="MemoryPool"/> to allocate data from.</param> /// <param name="fileStructureBlockSize">the block size of the file structure. Usually 4kb.</param> /// <returns></returns> public static DiskMedium OpenFile(CustomFileStream stream, MemoryPool pool, int fileStructureBlockSize) { byte[] buffer = new byte[fileStructureBlockSize]; stream.ReadRaw(0, buffer, fileStructureBlockSize); FileHeaderBlock header = FileHeaderBlock.Open(buffer); BufferedFile disk = new BufferedFile(stream, pool, header, isNewFile: false); return(new DiskMedium(disk, header)); }
/// <summary> /// Opens a file /// </summary> /// <param name="fileName">the name of the file.</param> /// <param name="ioBlockSize">the number of bytes to do all of the io</param> /// <param name="fileStructureBlockSize">The number of bytes in the file structure</param> /// <param name="isReadOnly">if the file should be opened in read only</param> /// <param name="isSharingEnabled">if the file should be opened with read sharing permissions.</param> /// <returns></returns> public static CustomFileStream OpenFile(string fileName, int ioBlockSize, out int fileStructureBlockSize, bool isReadOnly, bool isSharingEnabled) { using (FileStream fileStream = new FileStream(fileName, FileMode.Open, isReadOnly ? FileAccess.Read : FileAccess.ReadWrite, isSharingEnabled ? FileShare.Read : FileShare.None, 2048, true)) { fileStructureBlockSize = FileHeaderBlock.SearchForBlockSize(fileStream); } return(new CustomFileStream(ioBlockSize, fileStructureBlockSize, fileName, isReadOnly, isSharingEnabled)); }
/// <summary> /// Occurs when committing the following data to the disk. /// This will copy any pending data to the disk in a manner that /// will protect against corruption. /// </summary> /// <param name="header"></param> public void CommitChanges(FileHeaderBlock header) { if (m_disposed) { throw new ObjectDisposedException(GetType().FullName); } if (m_isReadOnly) { throw new ReadOnlyException(); } m_stream.CommitChanges(header); }
/// <summary> /// Creates a <see cref="ShadowCopyAllocator"/> that is used make shadow copies of blocks. /// </summary> /// <param name="ioSessions"></param> public ShadowCopyAllocator(SubFileDiskIoSessionPool ioSessions) : base(ioSessions) { if (ioSessions == null) throw new ArgumentNullException("ioSessions"); if (ioSessions.IsReadOnly) throw new ArgumentException("DataReader is read only", "ioSessions"); m_lastReadOnlyBlock = ioSessions.LastReadonlyBlock; m_fileHeaderBlock = ioSessions.Header; m_subFileHeader = ioSessions.File; m_ioSessions = ioSessions; }
public void CheckFileTypeToASCII() { //Arrange FileHeaderBlock headerBlock = new FileHeaderBlock(); headerBlock.FileType = Helpers.GetFixedSizeByteArrayFromBinaryString("TM25", 4); var expected = "TM25"; //Act string result = headerBlock.FileTypeToASCII(); //Assert Assert.AreEqual(expected, result); }
public void CheckFileCreationDateToASCII() { //Arrange FileHeaderBlock headerBlock = new FileHeaderBlock(); headerBlock.FileCreationDateAndTime = Helpers.GetFixedSizeByteArrayFromBinaryString("2013-09-04T08:30:29+01:00", 28); var expected = "2013-09-04T08:30:29+01:00 "; //Act string result = headerBlock.FileCreationDatetoASCII(); //Assert Assert.AreEqual(expected, result); }
private static void TestBinaryStream(DiskIo stream) { FileHeaderBlock header = stream.LastCommittedHeader; header = header.CloneEditable(); SubFileHeader node = header.CreateNewFile(SubFileName.CreateRandom()); header.CreateNewFile(SubFileName.CreateRandom()); header.CreateNewFile(SubFileName.CreateRandom()); SubFileStream ds = new SubFileStream(stream, node, header, false); BinaryStreamTest.Test(ds); }
/// <summary> /// Opens a file /// </summary> /// <param name="fileName">the name of the file.</param> /// <param name="ioBlockSize">the number of bytes to do all of the io</param> /// <param name="fileStructureBlockSize">The number of bytes in the file structure</param> /// <param name="isReadOnly">if the file should be opened in read only</param> /// <param name="isSharingEnabled">if the file should be opened with read sharing permissions.</param> /// <returns></returns> public static CustomFileStream OpenFile(string fileName, int ioBlockSize, out int fileStructureBlockSize, bool isReadOnly, bool isSharingEnabled) { //Exclusive opening to prevent duplicate opening. FileStream fileStream = new FileStream(fileName, FileMode.Open, isReadOnly ? FileAccess.Read : FileAccess.ReadWrite, isSharingEnabled ? FileShare.Read : FileShare.None, 2048, true); try { fileStructureBlockSize = FileHeaderBlock.SearchForBlockSize(fileStream); } catch (Exception) { fileStream.Dispose(); throw; } return(new CustomFileStream(fileStream, ioBlockSize, fileStructureBlockSize, fileName, isReadOnly, isSharingEnabled)); }
public void Test() { MemoryPoolTest.TestMemoryLeak(); Assert.AreEqual(Globals.MemoryPool.AllocatedBytes, 0L); FileHeaderBlock header = FileHeaderBlock.CreateNew(4096); header = header.CloneEditable(); header.CreateNewFile(SubFileName.CreateRandom()); header.CreateNewFile(SubFileName.CreateRandom()); header.CreateNewFile(SubFileName.CreateRandom()); header.IsReadOnly = true; FileHeaderBlock header2 = FileHeaderBlock.Open(header.GetBytes()); CheckEqual(header2, header); Assert.AreEqual(Globals.MemoryPool.AllocatedBytes, 0L); //verify they are the same; MemoryPoolTest.TestMemoryLeak(); }
public void Test() { Assert.AreEqual(Globals.MemoryPool.AllocatedBytes, 0L); DiskIo stream = DiskIo.CreateMemoryFile(Globals.MemoryPool, BlockSize); FileHeaderBlock fat = stream.LastCommittedHeader; //obtain a readonly copy of the file allocation table. fat = stream.LastCommittedHeader; TestCreateNewFile(stream, fat); fat = stream.LastCommittedHeader; TestOpenExistingFile(stream, fat); fat = stream.LastCommittedHeader; TestRollback(stream, fat); fat = stream.LastCommittedHeader; TestVerifyRollback(stream, fat); Assert.IsTrue(true); stream.Dispose(); Assert.AreEqual(Globals.MemoryPool.AllocatedBytes, 0L); }
/// <summary> /// /// </summary> /// <param name="other"></param> /// <returns></returns> /// <remarks>A debug function</remarks> internal static bool AreEqual(FileHeaderBlock other, FileHeaderBlock self) { if (other == null) return false; if (self == null) return false; if (self.CanWrite != other.CanWrite) return false; if (self.CanRead != other.CanRead) return false; if (self.ArchiveId != other.ArchiveId) return false; if (self.ArchiveType != other.ArchiveType) return false; if (self.SnapshotSequenceNumber != other.SnapshotSequenceNumber) return false; if (self.LastAllocatedBlock != other.LastAllocatedBlock) return false; if (self.FileCount != other.FileCount) return false; //compare files. if (self.Files == null) { if (other.Files != null) return false; } else { if (other.Files == null) return false; if (self.Files.Count != other.Files.Count) return false; for (int x = 0; x < self.Files.Count; x++) { SubFileHeader subFile = self.Files[x]; SubFileHeader subFileOther = other.Files[x]; if (subFile == null) { if (subFileOther != null) return false; } else { if (subFileOther == null) return false; if (!SubFileMetaDataTest.AreEqual(subFile, subFileOther)) return false; } } } return (self.GetBytes().SequenceEqual(other.GetBytes())); }
public SimplifiedSubFileStreamIoSession(FileStream stream, SubFileHeader subFile, FileHeaderBlock header) { if (stream == null) throw new ArgumentNullException("stream"); if (subFile == null) throw new ArgumentNullException("subFile"); if (header == null) throw new ArgumentNullException("header"); if (subFile.DirectBlock == 0) throw new Exception("Must assign subFile.DirectBlock"); m_stream = stream; m_header = header; m_blockSize = header.BlockSize; m_subFile = subFile; m_memory = new Memory(m_blockSize); m_buffer = new byte[m_blockSize]; m_currentPhysicalBlock = -1; m_blockDataLength = m_blockSize - FileStructureConstants.BlockFooterLength; }
/// <summary> /// Creates an SimplifiedSubFileStream /// </summary> /// <param name="stream">The location to read from.</param> /// <param name="subFile">The file to read.</param> /// <param name="fileHeaderBlock">The FileAllocationTable</param> internal SimplifiedSubFileStream(FileStream stream, SubFileHeader subFile, FileHeaderBlock fileHeaderBlock) { if (stream == null) throw new ArgumentNullException("stream"); if (subFile == null) throw new ArgumentNullException("subFile"); if (fileHeaderBlock == null) throw new ArgumentNullException("fileHeaderBlock"); if (subFile.DirectBlock == 0) throw new Exception("Must assign subFile.DirectBlock"); if (fileHeaderBlock.IsReadOnly) throw new ArgumentException("This parameter cannot be read only when opening for writing", "fileHeaderBlock"); if (subFile.IsReadOnly) throw new ArgumentException("This parameter cannot be read only when opening for writing", "subFile"); m_blockSize = fileHeaderBlock.BlockSize; m_stream = stream; m_subFile = subFile; m_fileHeaderBlock = fileHeaderBlock; }
private static void TestReadAndWrites(DiskIo stream) { FileHeaderBlock header = stream.LastCommittedHeader; header = header.CloneEditable(); SubFileHeader node = header.CreateNewFile(SubFileName.CreateRandom()); header.CreateNewFile(SubFileName.CreateRandom()); header.CreateNewFile(SubFileName.CreateRandom()); SubFileStream ds = new SubFileStream(stream, node, header, false); TestSingleByteWrite(ds); TestSingleByteRead(ds); TestCustomSizeWrite(ds, 5); TestCustomSizeRead(ds, 5); TestCustomSizeWrite(ds, BlockDataLength + 20); TestCustomSizeRead(ds, BlockDataLength + 20); stream.CommitChanges(header); }
/// <summary> /// Creates a new DiskIoSession that can be used to read from the disk subsystem. /// </summary> /// <param name="diskIo">owner of the disk</param> /// <param name="ioSession">the base ioSession to use for this io session</param> /// <param name="file">The file that will be read from this diskIoSession</param> public DiskIoSession(DiskIo diskIo, BinaryStreamIoSessionBase ioSession, FileHeaderBlock header, SubFileHeader file) { if (diskIo == null) throw new ArgumentNullException("diskIo"); if (diskIo.IsDisposed) throw new ObjectDisposedException(diskIo.GetType().FullName); if (ioSession == null) throw new ArgumentNullException("ioSession"); if (file == null) throw new ArgumentNullException("file"); m_args = new BlockArguments(); m_lastReadonlyBlock = diskIo.LastReadonlyBlock; m_diskMediumIoSession = ioSession; m_snapshotSequenceNumber = header.SnapshotSequenceNumber; m_fileIdNumber = file.FileIdNumber; m_isReadOnly = file.IsReadOnly | diskIo.IsReadOnly; m_blockSize = diskIo.BlockSize; m_diskIo = diskIo; IsValid = false; IsDisposed = false; }
private static void TestRollback(DiskIo stream, FileHeaderBlock fat) { SubFileName id1 = SubFileName.CreateRandom(); SubFileName id2 = SubFileName.CreateRandom(); SubFileName id3 = SubFileName.CreateRandom(); TransactionalEdit trans = new TransactionalEdit(stream); //create 3 files additional files SubFileStream fs21 = trans.CreateFile(id1); SubFileStream fs22 = trans.CreateFile(id2); SubFileStream fs23 = trans.CreateFile(id3); //open files SubFileStream fs1 = trans.OpenFile(0); SubFileStream fs2 = trans.OpenFile(1); SubFileStream fs3 = trans.OpenFile(2); //read from them and verify content. SubFileStreamTest.TestSingleByteRead(fs2); SubFileStreamTest.TestCustomSizeRead(fs3, 5); SubFileStreamTest.TestCustomSizeRead(fs1, BlockDataLength + 20); //rewrite bad data. SubFileStreamTest.TestSingleByteWrite(fs3); SubFileStreamTest.TestCustomSizeWrite(fs1, 5); SubFileStreamTest.TestCustomSizeWrite(fs2, BlockDataLength + 20); fs1.Dispose(); fs2.Dispose(); fs3.Dispose(); fs21.Dispose(); fs22.Dispose(); fs23.Dispose(); trans.RollbackAndDispose(); }
/// <summary> /// Occurs when committing the following data to the disk. /// This will copy any pending data to the disk in a manner that /// will protect against corruption. /// </summary> /// <param name="header"></param> public void CommitChanges(FileHeaderBlock header) { if (m_disposed) throw new ObjectDisposedException(GetType().FullName); if (m_isReadOnly) throw new ReadOnlyException(); m_stream.CommitChanges(header); }
/// <summary> /// Class is created through static methods of this class. /// </summary> /// <param name="disk">the underlying disk medium</param> /// <param name="header">the header data to use.</param> private DiskMedium(IDiskMediumCoreFunctions disk, FileHeaderBlock header) { m_header = header; m_disk = disk; m_blockSize = header.BlockSize; }
/// <summary> /// Executes a commit of data. This will flush the data to the disk use the provided header data to properly /// execute this function. /// </summary> /// <param name="header"></param> public void CommitChanges(FileHeaderBlock header) { using (var pageLock = new IoSession(this, m_pageReplacementAlgorithm)) { //Determine how much committed data to write long lengthOfAllData = (header.LastAllocatedBlock + 1) * (long)m_fileStructureBlockSize; long copyLength = lengthOfAllData - m_lengthOfCommittedData; //Write the uncommitted data. m_queue.Write(m_lengthOfCommittedData, m_writeBuffer, copyLength, waitForWriteToDisk: true); byte[] bytes = header.GetBytes(); if (header.HeaderBlockCount == 10) { //Update the new header to position 0, position 1, and one of position 2-9 m_queue.WriteRaw(0, bytes, m_fileStructureBlockSize); m_queue.WriteRaw(m_fileStructureBlockSize, bytes, m_fileStructureBlockSize); m_queue.WriteRaw(m_fileStructureBlockSize * ((header.SnapshotSequenceNumber & 7) + 2), bytes, m_fileStructureBlockSize); } else { for (int x = 0; x < header.HeaderBlockCount; x++) { m_queue.WriteRaw(x * m_fileStructureBlockSize, bytes, m_fileStructureBlockSize); } } m_queue.FlushFileBuffers(); long startPos; //Copy recently committed data to the buffer pool if ((m_lengthOfCommittedData & (m_diskBlockSize - 1)) != 0) //Only if there is a split page. { startPos = m_lengthOfCommittedData & (~(long)(m_diskBlockSize - 1)); //Finish filling up the split page in the buffer. IntPtr ptrDest; if (pageLock.TryGetSubPage(startPos, out ptrDest)) { int length; IntPtr ptrSrc; m_writeBuffer.ReadBlock(m_lengthOfCommittedData, out ptrSrc, out length); Footer.WriteChecksumResultsToFooter(ptrSrc, m_fileStructureBlockSize, length); ptrDest += (m_diskBlockSize - length); Memory.Copy(ptrSrc, ptrDest, length); } startPos += m_diskBlockSize; } else { startPos = m_lengthOfCommittedData; } while (startPos < lengthOfAllData) { //If the address doesn't exist in the current list. Read it from the disk. int poolPageIndex; IntPtr poolAddress; m_pool.AllocatePage(out poolPageIndex, out poolAddress); m_writeBuffer.CopyTo(startPos, poolAddress, m_diskBlockSize); Footer.WriteChecksumResultsToFooter(poolAddress, m_fileStructureBlockSize, m_diskBlockSize); if (!m_pageReplacementAlgorithm.TryAddPage(startPos, poolAddress, poolPageIndex)) { m_pool.ReleasePage(poolPageIndex); } startPos += m_diskBlockSize; } m_lengthOfCommittedData = lengthOfAllData; } ReleaseWriteBufferSpace(); }
/// <summary> /// Executes a commit of data. This will flush the data to the disk use the provided header data to properly /// execute this function. /// </summary> /// <param name="header"></param> public void CommitChanges(FileHeaderBlock header) { using (var pageLock = new IoSession(this, m_pageReplacementAlgorithm)) { //Determine how much committed data to write long lengthOfAllData = (header.LastAllocatedBlock + 1) * (long)m_fileStructureBlockSize; long copyLength = lengthOfAllData - m_lengthOfCommittedData; //Write the uncommitted data. m_queue.Write(m_lengthOfCommittedData, m_writeBuffer, copyLength, waitForWriteToDisk: true); byte[] bytes = header.GetBytes(); if (header.HeaderBlockCount == 10) { //Update the new header to position 0, position 1, and one of position 2-9 m_queue.WriteRaw(0, bytes, m_fileStructureBlockSize); m_queue.WriteRaw(m_fileStructureBlockSize, bytes, m_fileStructureBlockSize); m_queue.WriteRaw(m_fileStructureBlockSize * ((header.SnapshotSequenceNumber & 7) + 2), bytes, m_fileStructureBlockSize); } else { for (int x = 0; x < header.HeaderBlockCount; x++) { m_queue.WriteRaw(x * m_fileStructureBlockSize, bytes, m_fileStructureBlockSize); } } m_queue.FlushFileBuffers(); long startPos; //Copy recently committed data to the buffer pool if ((m_lengthOfCommittedData & (m_diskBlockSize - 1)) != 0) //Only if there is a split page. { startPos = m_lengthOfCommittedData & (~(long)(m_diskBlockSize - 1)); //Finish filling up the split page in the buffer. IntPtr ptrDest; if (pageLock.TryGetSubPage(startPos, out ptrDest)) { int length; IntPtr ptrSrc; m_writeBuffer.ReadBlock(m_lengthOfCommittedData, out ptrSrc, out length); Footer.WriteChecksumResultsToFooter(ptrSrc, m_fileStructureBlockSize, length); ptrDest += (m_diskBlockSize - length); Memory.Copy(ptrSrc, ptrDest, length); } startPos += m_diskBlockSize; } else { startPos = m_lengthOfCommittedData; } while (startPos < lengthOfAllData) { //If the address doesn't exist in the current list. Read it from the disk. int poolPageIndex; IntPtr poolAddress; m_pool.AllocatePage(out poolPageIndex, out poolAddress); m_writeBuffer.CopyTo(startPos, poolAddress, m_diskBlockSize); Footer.WriteChecksumResultsToFooter(poolAddress, m_fileStructureBlockSize, m_diskBlockSize); if (!m_pageReplacementAlgorithm.TryAddPage(startPos, poolAddress, poolPageIndex)) m_pool.ReleasePage(poolPageIndex); startPos += m_diskBlockSize; } m_lengthOfCommittedData = lengthOfAllData; } ReleaseWriteBufferSpace(); }
/// <summary> /// Creates a file backed memory stream. /// </summary> /// <param name="stream">The <see cref="CustomFileStream"/> to buffer</param> /// <param name="pool">The <see cref="MemoryPool"/> to allocate memory from</param> /// <param name="header">The <see cref="FileHeaderBlock"/> to be managed when modifications occur</param> /// <param name="isNewFile">Tells if this is a newly created file. This will make sure that the /// first 10 pages have the header data copied to it.</param> public BufferedFile(CustomFileStream stream, MemoryPool pool, FileHeaderBlock header, bool isNewFile) { m_fileStructureBlockSize = header.BlockSize; m_diskBlockSize = pool.PageSize; m_lengthOfHeader = header.BlockSize * header.HeaderBlockCount; m_writeBuffer = new MemoryPoolStreamCore(pool); m_pool = pool; m_queue = stream; m_syncRoot = new object(); m_pageReplacementAlgorithm = new PageReplacementAlgorithm(pool); pool.RequestCollection += m_pool_RequestCollection; if (isNewFile) { byte[] headerBytes = header.GetBytes(); for (int x = 0; x < header.HeaderBlockCount; x++) { m_queue.WriteRaw(0, headerBytes, headerBytes.Length); } } m_lengthOfCommittedData = (header.LastAllocatedBlock + 1) * (long)header.BlockSize; m_writeBuffer.ConfigureAlignment(m_lengthOfCommittedData, pool.PageSize); }
private unsafe string TestFile(string fileName) { ShortTime lastReport = ShortTime.Now; int errorBlocks = 0; uint firstBlockWithError = uint.MaxValue; try { using (var stream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) { int blockSize = FileHeaderBlock.SearchForBlockSize(stream); stream.Position = 0; byte[] data = new byte[blockSize]; stream.ReadAll(data, 0, blockSize); var header = FileHeaderBlock.Open(data); fixed(byte *lp = data) { stream.Position = header.HeaderBlockCount * blockSize; uint startingBlock = header.HeaderBlockCount; if (m_shouldQuickScan) { uint blocksToScan = (uint)Math.Ceiling(m_mbToScan * 1024 * 1024 / blockSize); if (blocksToScan < header.LastAllocatedBlock) { startingBlock = Math.Max(header.HeaderBlockCount, header.LastAllocatedBlock - blocksToScan); } } for (uint x = startingBlock; x <= header.LastAllocatedBlock; x++) { long checksum1; int checksum2; stream.ReadAll(data, 0, blockSize); Footer.ComputeChecksum((IntPtr)lp, out checksum1, out checksum2, blockSize - 16); long checksumInData1 = *(long *)(lp + blockSize - 16); int checksumInData2 = *(int *)(lp + blockSize - 8); if (!(checksum1 == checksumInData1 && checksum2 == checksumInData2)) { firstBlockWithError = Math.Min(firstBlockWithError, x); errorBlocks++; } if (m_quit) { if (errorBlocks == 0) { return("Quit Early - No Errors Found"); } return($"Quit Early - Blocks With Errors {errorBlocks} Starting At {firstBlockWithError}"); } if (lastReport.ElapsedSeconds() > .25) { lastReport = ShortTime.Now; lblProgress.Text = $"Completed {m_filesScanned} of {m_filesToScan} files. Current File: {(stream.Position / (double)stream.Length).ToString("0.0%")}"; Application.DoEvents(); } } } } if (errorBlocks == 0) { return("No Errors Found"); } return($"Blocks With Errors {errorBlocks} Starting At {firstBlockWithError}"); } catch (Exception e) { MessageBox.Show(e.ToString()); return("Error"); } }
private static void CheckEqual(FileHeaderBlock RO, FileHeaderBlock RW) { if (!AreEqual(RW, RO)) throw new Exception(); }
/// <summary> /// /// </summary> /// <param name="other"></param> /// <returns></returns> /// <remarks>A debug function</remarks> internal static bool AreEqual(FileHeaderBlock other, FileHeaderBlock self) { if (other is null) { return(false); } if (self is null) { return(false); } if (self.CanWrite != other.CanWrite) { return(false); } if (self.CanRead != other.CanRead) { return(false); } if (self.ArchiveId != other.ArchiveId) { return(false); } if (self.ArchiveType != other.ArchiveType) { return(false); } if (self.SnapshotSequenceNumber != other.SnapshotSequenceNumber) { return(false); } if (self.LastAllocatedBlock != other.LastAllocatedBlock) { return(false); } if (self.FileCount != other.FileCount) { return(false); } //compare files. if (self.Files is null) { if (other.Files != null) { return(false); } } else { if (other.Files is null) { return(false); } if (self.Files.Count != other.Files.Count) { return(false); } for (int x = 0; x < self.Files.Count; x++) { SubFileHeader subFile = self.Files[x]; SubFileHeader subFileOther = other.Files[x]; if (subFile is null) { if (subFileOther != null) { return(false); } } else { if (subFileOther is null) { return(false); } if (!SubFileMetaDataTest.AreEqual(subFile, subFileOther)) { return(false); } } } } return(self.GetBytes().SequenceEqual(other.GetBytes())); }
/// <summary> /// Creates a <see cref="DiskIoSession"/> that can be used to perform basic read/write functions. /// </summary> /// <returns></returns> public DiskIoSession CreateDiskIoSession(FileHeaderBlock header, SubFileHeader file) { if (m_disposed) throw new ObjectDisposedException(GetType().FullName); return new DiskIoSession(this, m_stream.CreateIoSession(), header, file); }
private static void TestVerifyRollback(DiskIo stream, FileHeaderBlock fat) { Guid id = Guid.NewGuid(); TransactionalEdit trans = new TransactionalEdit(stream); if (trans.Files.Count != 3) throw new Exception(); //open files SubFileStream fs1 = trans.OpenFile(0); SubFileStream fs2 = trans.OpenFile(1); SubFileStream fs3 = trans.OpenFile(2); //read from them and verify content. SubFileStreamTest.TestSingleByteRead(fs2); SubFileStreamTest.TestCustomSizeRead(fs3, 5); SubFileStreamTest.TestCustomSizeRead(fs1, BlockDataLength + 20); fs1.Dispose(); fs2.Dispose(); fs3.Dispose(); trans.Dispose(); }
/// <summary> /// Creates this file with the following data. /// </summary> /// <param name="diskIo"></param> /// <param name="header"></param> /// <param name="file"></param> /// <param name="isReadOnly"></param> public SubFileDiskIoSessionPool(DiskIo diskIo, FileHeaderBlock header, SubFileHeader file, bool isReadOnly) { LastReadonlyBlock = diskIo.LastCommittedHeader.LastAllocatedBlock; File = file; Header = header; IsReadOnly = isReadOnly; SourceData = diskIo.CreateDiskIoSession(header, file); SourceIndex = diskIo.CreateDiskIoSession(header, file); if (!isReadOnly) { DestinationData = diskIo.CreateDiskIoSession(header, file); DestinationIndex = diskIo.CreateDiskIoSession(header, file); } }
/// <summary> /// Executes a commit of data. This will flush the data to the disk use the provided header data to properly /// execute this function. /// </summary> /// <param name="headerBlock"></param> public void CommitChanges(FileHeaderBlock headerBlock) { if (IsDisposed) throw new ObjectDisposedException("MemoryStream"); }