/// <summary> /// Writes all of the dirty blocks passed onto the disk subsystem. Also computes the checksum for the data. /// </summary> /// <param name="currentEndOfCommitPosition">the last valid byte of the file system where this data will be appended to.</param> /// <param name="stream">the source of the data to dump to the disk</param> /// <param name="length">The number by bytes to write to the file system.</param> /// <param name="waitForWriteToDisk">True to wait for a complete commit to disk before returning from this function.</param> public void Write(long currentEndOfCommitPosition, MemoryPoolStreamCore stream, long length, bool waitForWriteToDisk) { byte[] buffer = m_bufferQueue.Dequeue(); long endPosition = currentEndOfCommitPosition + length; long currentPosition = currentEndOfCommitPosition; while (currentPosition < endPosition) { IntPtr ptr; int streamLength; stream.ReadBlock(currentPosition, out ptr, out streamLength); int subLength = (int)Math.Min(streamLength, endPosition - currentPosition); Footer.ComputeChecksumAndClearFooter(ptr, m_fileStructureBlockSize, subLength); Marshal.Copy(ptr, buffer, 0, subLength); WriteRaw(currentPosition, buffer, subLength); currentPosition += subLength; } m_bufferQueue.Enqueue(buffer); if (waitForWriteToDisk) { FlushFileBuffers(); } else { using (m_isUsingStream.EnterReadLock()) { m_stream.Flush(false); } } }
/// <summary> /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. /// </summary> /// <filterpriority>2</filterpriority> public void Dispose() { if (!m_disposed) { try { m_disposed = true; //Unregistering from this event gaurentees that a collection will no longer //be called since this class utilizes custom code to garentee this. m_pool.RequestCollection -= m_pool_RequestCollection; lock (m_syncRoot) { if (m_pageReplacementAlgorithm != null) m_pageReplacementAlgorithm.Dispose(); if (m_queue != null) m_queue.Dispose(); if (m_writeBuffer != null) m_writeBuffer.Dispose(); } } finally { m_queue = null; m_disposed = true; m_pageReplacementAlgorithm = null; m_writeBuffer = null; m_queue = null; GC.SuppressFinalize(this); } } }
/// <summary> /// Releases the buffered data contained in the buffer pool. /// This is acomplished by disposing of the writer and recreating it. /// </summary> private void ReleaseWriteBufferSpace() { m_writeBuffer.Dispose(); m_writeBuffer = new MemoryPoolStreamCore(m_pool); m_writeBuffer.ConfigureAlignment(m_lengthOfCommittedData, m_pool.PageSize); }
/// <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); }