A page replacement algorithm that utilizes a quasi LRU algorithm. This class is thread safe.
This class is used by BufferedFile to decide which pages should be replaced.
Inheritance: IDisposable
Exemplo n.º 1
0
        /// <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);
        }
Exemplo n.º 2
0
            /// <summary>
            /// Creates an unallocated block.
            /// </summary>
            protected PageLock(PageReplacementAlgorithm parent)
            {
                m_hashCode         = DateTime.UtcNow.Ticks.GetHashCode();
                m_parent           = parent;
                m_currentPageIndex = -1;

                lock (m_parent.m_syncRoot)
                {
                    if (m_parent.m_disposed)
                    {
                        throw new ObjectDisposedException(GetType().FullName);
                    }
                    m_parent.m_arrayIndexLocks.Add(this);
                }
            }
Exemplo n.º 3
0
        /// <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>
 /// Creates a new <see cref="IoSession"/>
 /// </summary>
 /// <param name="stream">the base class</param>
 /// <param name="pageReplacement">The page Replacement Algorithm</param>
 internal IoSession(BufferedFile stream, PageReplacementAlgorithm pageReplacement)
     : base(pageReplacement)
 {
     m_stream = stream;
 }
Exemplo n.º 5
0
 /// <summary>
 /// Creates a new <see cref="IoSession"/>
 /// </summary>
 /// <param name="stream">the base class</param>
 /// <param name="pageReplacement">The page Replacement Algorithm</param>
 internal IoSession(BufferedFile stream, PageReplacementAlgorithm pageReplacement)
     : base(pageReplacement)
 {
     m_stream = stream;
 }
        /// <summary>
        /// Processes the GetBlock from the committed area.
        /// </summary>
        /// <param name="pageLock"></param>
        /// <param name="position"></param>
        /// <param name="pointer">an output parameter that contains the pointer for the provided position</param>
        /// <remarks>The valid length is at least the size of the buffer pools page size.</remarks>
        private void GetBlockFromCommittedSpace(PageReplacementAlgorithm.PageLock pageLock, long position, out IntPtr pointer)
        {
            //If the page is in the buffer, we can return and don't have to read it.
            if (pageLock.TryGetSubPage(position, out pointer))
                return;

            //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_queue.Read(position, poolAddress);

            //Since a race condition exists, I need to check the buffer to make sure that 
            //the most recently read page already exists in the PageReplacementAlgorithm.
            bool wasPageAdded;
            pointer = pageLock.GetOrAddPage(position, poolAddress, poolPageIndex, out wasPageAdded);
            //If I lost on the race condition, I need to re-release this page.
            if (!wasPageAdded)
                m_pool.ReleasePage(poolPageIndex);
        }
        /// <summary>
        /// Populates the pointer data inside <see cref="args"/> for the desired block as specified in <see cref="args"/>.
        /// This function will block if needing to retrieve data from the disk.
        /// </summary>
        /// <param name="pageLock">The reusable lock information about what this block is currently using.</param>
        /// <param name="args">Contains what block needs to be read and when this function returns, 
        /// it will contain the proper pointer information for this block.</param>
        private void GetBlock(PageReplacementAlgorithm.PageLock pageLock, BlockArguments args)
        {
            pageLock.Clear();
            //Determines where the block is located.
            if (args.Position >= m_lengthOfCommittedData)
            {
                //If the block is in the uncommitted space, it is stored in the 
                //MemoryPoolStreamCore.
                args.SupportsWriting = true;
                m_writeBuffer.GetBlock(args);
            }
            else if (args.Position < m_lengthOfHeader)
            {
                //If the block is in the header, error because this area of the file is not designed to be accessed.
                throw new ArgumentOutOfRangeException("args", "Cannot use this function to modify the file header.");
            }
            else
            {
                //If it is between the file header and uncommitted space, 
                //it is in the committed space, which this space by design is never to be modified. 
                if (args.IsWriting)
                    throw new ArgumentException("Cannot write to committed data space", "args");
                args.SupportsWriting = false;
                args.Length = m_diskBlockSize;
                //rounds to the beginning of the block to be looked up.
                args.FirstPosition = args.Position & ~(long)m_pool.PageMask;

                GetBlockFromCommittedSpace(pageLock, args.FirstPosition, out args.FirstPointer);

                //Make sure the block does not go beyond the end of the uncommitted space.
                if (args.FirstPosition + args.Length > m_lengthOfCommittedData)
                    args.Length = (int)(m_lengthOfCommittedData - args.FirstPosition);
            }
        }
        /// <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>
        /// 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);
        }