Anatomy of SQLSERVER Article 2 reverse the data page header)

Source: Internet
Author: User
Anatomy of the second article of SQL Server to reverse the data page header (translated) improve. dkreverse-engineering-SQL-server-page-headers when developing OrcaMDF, the first challenge was to parse the data page header. We know that the data page consists of two parts, 96-byte page header and 8096-byte data

Anatomy of SQL Server Second on the data page header reverse http://improve.dk/reverse-engineering-sql-server-page-headers/ in the Development of OrcaMDF when the first challenge is to parse the data page header, we know that the data page is divided into two parts, 96-byte page header and 8096-byte data

AnatomySQLSERVER SecondArticle Data PageHeader Proceed ReverseTranslation)

Http://improve.dk/reverse-engineering-sql-server-page-headers/

The first challenge during OrcaMDF development is parsing.DataPageHeader, we knowDataPageDivided into two parts, 96 bytesPageHeader and 8096-byteDataLine

Paul Randal wrote an article describing the page header structure. However, even though the article is very detailed, I still cannot find any format for page header storage.

For each fieldDataTypes and their order

We can use the dbcc page command to fill in some randomDataGo inDataPage, And thenPageDump out

PageNo. Is ):

DBCC TRACEON (3604)DBCC PAGE (TextTest, 1, 101, 2)

The result is divided into two parts. First, we get the formatted dbcc page.PageContent.SecondSome are 96 bytesPageHeader

Now, we need to find outPageHeadersDataValue correspondingDataWhat is the type?

For simplicity, we need to pay attention to some unique values so that we do not get some ambiguous values.

Starting from the m_freeCnt field, we can see that the m_freeCnt value is 4066, whileDataThe row size is 8060, so it is obvious that the m_freeCntDataThe type cannot be tinyint.

M_freeCnt is unlikely to use the int type. It is assumed that m_freeCnt may use the smallint type, which causesDataThe row can accommodate 0-8060 bytes.Data

Smallint: an integer from-2 ^ 15 (-32,768) to 2 ^ 15-1 (32,767)DataThe storage size is 2 bytes. I think the value of m_freeCnt cannot be too large.

Now, the decimal number of 4066 is changed to the hexadecimal value 0x0FE2. The byte is switched to 0xE20F. Now we know that we have matched the m_freeCntDataType

In addition, we already knowDataType and location

/*    Bytes    Content    -----    -------    00-27    ?    28-29    FreeCnt (smallint)    30-95    ?*/

Continue our search. We can see that m_freeData = 3895 is converted into a hexadecimal value of 0x0F37 bytes after the 0x370F

We found that the m_freeCnt field is stored behind m_freeCnt.

With this technique, we can match the unique and unambiguous content stored in the page header.DataValue

However, for the m_level field, the values of the m_xactReserved field, m_reservedCnt field, and m_ghostRecCnt field are the same.

How do we know which value of 0 belongs to the m_level field? And how can we find outDataWhat about the type? This may be of the tinyint to bigint type.

Let's go to Visual Studio and shutdown SQLSERVER

Drag the mdf file into VS and VS will open the hex editor.PageOffset CalculationPageLocation

101*8192 = 827,392

Looking at the byte content marked by the red box, he has identified ourPageHeader content, and confirm that we have jumped to the correct position

Now, we will fill in some numeric values in the mdf file and save the file. Please do not create them randomly in production.DataDatabaseProceedTest

Before

After

Now we start SQLSERVER and run the dbcc page command again.

DBCC TRACEON (3604)DBCC PAGE (TextTest, 1, 101, 2)

You can note thatPageThe header becomes like this

Several numeric values have changed. The previous numeric value of the m_xactReserved field is 0, and now it is 30806. convert this number to hexadecimal format andProceedByte exchange returns 0x5678

Take a lookPageHeader. Now we have identified the value andDataType (smallint)

Let's update our page header table.

/*    Bytes    Content    -----    -------    00-27    ?    28-29    FreeCnt (smallint)    30-49    ?    50-51    XactReserved (smallint)    30-95    ?*/

Continue following this method and set the page headerProceedModify the modified PAGE header and dbcc page output in disorderProceedAssociation, it is possible to find outDataType

If you see the following message, you will know thatPageMessy Headers

You should be proud that no one can fix your randomly modified errors.

I have prepared a page header structure table.

/*    Bytes    Content    -----    -------    00    HeaderVersion (tinyint)    01    Type (tinyint)    02    TypeFlagBits (tinyint)    03    Level (tinyint)    04-05    FlagBits (smallint)    06-07    IndexID (smallint)    08-11    PreviousPageID (int)    12-13    PreviousFileID (smallint)    14-15    Pminlen (smallint)    16-19    NextPageID (int)    20-21    NextPageFileID (smallint)    22-23    SlotCnt (smallint)    24-27    ObjectID (int)    28-29    FreeCnt (smallint)    30-31    FreeData (smallint)    32-35    PageID (int)    36-37    FileID (smallint)    38-39    ReservedCnt (smallint)    40-43    Lsn1 (int)    44-47    Lsn2 (int)    48-49    Lsn3 (smallint)    50-51    XactReserved (smallint)    52-55    XdesIDPart2 (int)    56-57    XdesIDPart1 (smallint)    58-59    GhostRecCnt (smallint)    60-95    ?*/

I'm not sure about the correspondence between other bytes in the PAGE header and the fields output by DBCC PAGE.PageThese bytes seem to be stored as 0

I think these should be reserved bytes for some future use. Now, we have obtained the page header format. It is easy to read each field.

HeaderVersion = header[0];Type = (PageType)header[1];TypeFlagBits = header[2];Level = header[3];FlagBits = BitConverter.ToInt16(header, 4);IndexID = BitConverter.ToInt16(header, 6);PreviousPage = new PagePointer(BitConverter.ToInt16(header, 12), BitConverter.ToInt32(header, 8));Pminlen = BitConverter.ToInt16(header, 14);NextPage = new PagePointer(BitConverter.ToInt16(header, 20), BitConverter.ToInt32(header, 16));SlotCnt = BitConverter.ToInt16(header, 22);ObjectID = BitConverter.ToInt32(header, 24);FreeCnt = BitConverter.ToInt16(header, 28);FreeData = BitConverter.ToInt16(header, 30);Pointer = new PagePointer(BitConverter.ToInt16(header, 36), BitConverter.ToInt32(header, 32));ReservedCnt = BitConverter.ToInt16(header, 38);Lsn = "(" + BitConverter.ToInt32(header, 40) + ":" + BitConverter.ToInt32(header, 44) + ":" + BitConverter.ToInt16(header, 48) + ")";XactReserved = BitConverter.ToInt16(header, 50);XdesID = "(" + BitConverter.ToInt16(header, 56) + ":" + BitConverter.ToInt32(header, 52) + ")";GhostRecCnt = BitConverter.ToInt16(header, 58);

Let's take a look at the pageheader class I wrote.

using System;using System.Text;namespace OrcaMDF.Core.Engine.Pages{public class PageHeader{public short FreeCnt { get; private set; }public short FreeData { get; private set; }public short FlagBits { get; private set; }public string Lsn { get; private set; }public int ObjectID { get; private set; }public PageType Type { get; private set; }public short Pminlen { get; private set; }public short IndexID { get; private set; }public byte TypeFlagBits { get; private set; }public short SlotCnt { get; private set; }public string XdesID { get; private set; }public short XactReserved { get; private set; }public short ReservedCnt { get; private set; }public byte Level { get; private set; }public byte HeaderVersion { get; private set; }public short GhostRecCnt { get; private set; }public PagePointer NextPage { get; private set; }public PagePointer PreviousPage { get; private set; }public PagePointer Pointer { get; private set; }public PageHeader(byte[] header){if (header.Length != 96)throw new ArgumentException("Header length must be 96.");/*                Bytes    Content                -----    -------                00        HeaderVersion (tinyint)                01        Type (tinyint)                02        TypeFlagBits (tinyint)                03        Level (tinyint)                04-05    FlagBits (smallint)                06-07    IndexID (smallint)                08-11    PreviousPageID (int)                12-13    PreviousFileID (smallint)                14-15    Pminlen (smallint)                16-19    NextPageID (int)                20-21    NextPageFileID (smallint)                22-23    SlotCnt (smallint)                24-27    ObjectID (int)                28-29    FreeCnt (smallint)                30-31    FreeData (smallint)                32-35    PageID (int)                36-37    FileID (smallint)                38-39    ReservedCnt (smallint)                40-43    Lsn1 (int)                44-47    Lsn2 (int)                48-49    Lsn3 (smallint)                50-51    XactReserved (smallint)                52-55    XdesIDPart2 (int)                56-57    XdesIDPart1 (smallint)                58-59    GhostRecCnt (smallint)                60-63    Checksum/Tornbits (int)                64-95    ?            */HeaderVersion = header[0];Type = (PageType)header[1];TypeFlagBits = header[2];Level = header[3];FlagBits = BitConverter.ToInt16(header, 4);IndexID = BitConverter.ToInt16(header, 6);PreviousPage = new PagePointer(BitConverter.ToInt16(header, 12), BitConverter.ToInt32(header, 8));Pminlen = BitConverter.ToInt16(header, 14);NextPage = new PagePointer(BitConverter.ToInt16(header, 20), BitConverter.ToInt32(header, 16));SlotCnt = BitConverter.ToInt16(header, 22);ObjectID = BitConverter.ToInt32(header, 24);FreeCnt = BitConverter.ToInt16(header, 28);FreeData = BitConverter.ToInt16(header, 30);Pointer = new PagePointer(BitConverter.ToInt16(header, 36), BitConverter.ToInt32(header, 32));ReservedCnt = BitConverter.ToInt16(header, 38);Lsn = "(" + BitConverter.ToInt32(header, 40) + ":" + BitConverter.ToInt32(header, 44) + ":" + BitConverter.ToInt16(header, 48) + ")";XactReserved = BitConverter.ToInt16(header, 50);XdesID = "(" + BitConverter.ToInt16(header, 56) + ":" + BitConverter.ToInt32(header, 52) + ")";GhostRecCnt = BitConverter.ToInt16(header, 58);}public override string ToString(){var sb = new StringBuilder();sb.AppendLine("m_freeCnt:\t" + FreeCnt);sb.AppendLine("m_freeData:\t" + FreeData);sb.AppendLine("m_flagBits:\t0x" + FlagBits.ToString("x"));sb.AppendLine("m_lsn:\t\t" + Lsn);sb.AppendLine("m_objId:\t" + ObjectID);sb.AppendLine("m_pageId:\t(" + Pointer.FileID + ":" + Pointer.PageID + ")");sb.AppendLine("m_type:\t\t" + Type);sb.AppendLine("m_typeFlagBits:\t" + "0x" + TypeFlagBits.ToString("x"));sb.AppendLine("pminlen:\t" + Pminlen);sb.AppendLine("m_indexId:\t" + IndexID);sb.AppendLine("m_slotCnt:\t" + SlotCnt);sb.AppendLine("m_nextPage:\t" + NextPage);sb.AppendLine("m_prevPage:\t" + PreviousPage);sb.AppendLine("m_xactReserved:\t" + XactReserved);sb.AppendLine("m_xdesId:\t" + XdesID);sb.AppendLine("m_reservedCnt:\t" + ReservedCnt);sb.AppendLine("m_ghostRecCnt:\t" + GhostRecCnt);return sb.ToString();}}}

SecondSummary

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.