/// <summary>
        /// Iterate all blocks in this page to find the block with given id.
        /// If the block has different size from the given len, throw an
        /// exception.
        /// Note that it doesn't need lock to work properly.
        /// </summary>
        /// <param name="id"></param>
        /// <param name="len"></param>
        /// <returns>Offset if success. 0 if failed.</returns>
        public int TryFindAllocated(int id, int len)
        {
            int offset = _currentPagePtr->AllocationTableOffset;

            while (offset != 0)
            {
                IntPtr           tableIntPtr = new IntPtr(_currentPagePtr) + offset;
                AllocationTable *tablePtr    = (AllocationTable *)tableIntPtr;
                for (int i = 0; i < TableSize; ++i)
                {
                    var currentId = tablePtr->Entries[i * 2];
                    if (currentId == 0)
                    {
                        return(0);
                    }
                    else if (currentId == id)
                    {
                        //TODO probably we should check the size? (need one more int),
                        //and also alignment.
                        return(tablePtr->Entries[i * 2 + 1]);
                    }
                }
                offset = tablePtr->NextAllocationTable;
            }
            return(0);
        }
        /// <summary>
        /// Try to allocate in the current page. Note that this doesn't lock
        /// the memory, and doesn't check allocated blocks.
        /// Caller must lock the base page before calling this function.
        /// </summary>
        /// <param name="id">Id of the block used to check existence.</param>
        /// <param name="len">Length of the block.</param>
        /// <returns>Offset if success. 0 if failed.</returns>
        public int TryAllocate(int id, int len, int alignment)
        {
            int dataOffset = ApplyAlignment(_currentPagePtr->AllocationSize, alignment);

            if (dataOffset + len > _pageSize)
            {
                //Not enough space for data.
                return(0);
            }
            int tableOffset     = _currentPagePtr->AllocationTableOffset;
            int lastTableOffset = 0;

            //Try to find an empty slot in existing tables.
            while (tableOffset != 0)
            {
                AllocationTable *tablePtr = GetAllocationTablePtr(tableOffset);
                for (int i = 0; i < TableSize; ++i)
                {
                    var currentId = tablePtr->Entries[i * 2];
                    if (currentId == 0)
                    {
                        tablePtr->Entries[i * 2]        = id;
                        tablePtr->Entries[i * 2 + 1]    = dataOffset;
                        _currentPagePtr->AllocationSize = dataOffset + len;
                        return(dataOffset);
                    }
                }
                lastTableOffset = tableOffset;
                tableOffset     = tablePtr->NextAllocationTable;
            }
            //Not enough table. Create a new one.
            tableOffset = ApplyAlignment(dataOffset + len, 4);
            if (tableOffset + TableStructSize > _pageSize)
            {
                //Not enough space for a new table.
                return(0);
            }
            {
                //Set up AllocationTable linked list.
                AllocationTable *tablePtr = GetAllocationTablePtr(lastTableOffset);
                tablePtr->NextAllocationTable = tableOffset;
            }
            {
                //Create new entry.
                AllocationTable *tablePtr = GetAllocationTablePtr(tableOffset);
                tablePtr->Entries[0] = id;
                tablePtr->Entries[1] = dataOffset;
            }
            _currentPagePtr->AllocationSize = tableOffset + TableStructSize;
            return(dataOffset);
        }