InnoDB Index Page Parsing
Background
In a production environment, after a large amount of data is deleted from an InnoDB table, free pages are left between originally contiguous data pages. As a result, the table file is no longer compact. However, how are these fragmented pages generated? Can they be reused by newly inserted data? Can they be reused by other tables?
This section will delve into the InnoDB physical file management mechanism to answer these questions from a theoretical perspective.
Pages
The InnoDB physical file system mainly consists of system tablespace files (ibdata*), user tablespace files (*.ibd), independent undo tablespace files (undo_* by default), temporary tablespace files (temp_*.ibt), redo log files (#ib_redo*), and doublewrite files (#ib_16384_*.dblwr by default).
Except redo log files, all other files are composed of standard InnoDB pages. A page is the basic unit for managing storage space in InnoDB. Generally, the size of a page is 16 KB. You can set the innodb_page_size parameter to adjust the page size to any value between 4 KB and 64 KB during database initialization. Data in a table is stored in pages as records. If the data to be queried is not in the buffer pool, InnoDB loads the entire page containing that data into the buffer pool. Similarly, when dirty pages in the buffer pool are flushed to disk, the flushing is performed on a per-page basis.
In the InnoDB storage engine, there are multiple types of pages, each serving a different function. These include:
- Tablespace header page (FIL_PAGE_TYPE_FSP_HDR): records metadata of the tablespace.
- User data storage page (FIL_PAGE_INDEX): stores data and primary key indexes of user tables.
- Rollback segment page (FIL_PAGE_UNDO_LOG): stores undo logs to support transaction rollback.
- Segment index node page (FIL_PAGE_INODE): manages segment information in data files.
- Extent descriptor page (FIL_PAGE_TYPE_XDES): maintains metadata of extents.
- Insert buffer bitmap page (FIL_PAGE_IBUF_BITMAP): tracks whether each page has insert buffer entries to be processed.
Although the preceding page types are different, they share the same page structure, including the common page header (Fil Header) and common page trailer (Fil Trailer). The detailed information recorded in them is as follows:
| Structure | Name | Description | Bytes |
|---|---|---|---|
| Common page header | FIL_PAGE_SPACE_OR_CHKSUM | Checksum. | 4 |
| FIL_PAGE_OFFSET | Page number. | 4 | |
| FIL_PAGE_PREV | Previous page number. | 4 | |
| FIL_PAGE_NEXT | Next page number. | 4 | |
| FIL_PAGE_LSN | LSN of the last modification. | 8 | |
| FIL_PAGE_TYPE | Page type. | 2 | |
| FIL_PAGE_FILE_FLUSH_LSN | This field is defined only on page 0 of the system tablespace, indicating the LSN to which the file has been flushed at a minimum. | 8 | |
| FIL_PAGE_SPACE_ID | Tablespace ID. | 4 | |
| Page content | ... | ... | ... |
| Common page trailer | FIL_PAGE_END_LSN_OLD_CHKSUM | Page trailer checksum (4). | 4 |
| Low 4 bytes of the LSN. | 4 |
We will focus on the FIL_PAGE_INDEX type, which is directly related to user data and is commonly referred to as the index page type.
Index Page Characteristics
An index page has the following structural characteristics:
- Rapid data location: The page directory stores the offset of the maximum record in each group. The target can be quickly located using a two-step method involving binary search and linked list traversal.
- Data integrity and recovery: When a page is read from disk, its content is checked via a checksum to ensure that data can be restored in sequence after a crash, preventing data loss and damage.
- Space management optimization: The free space linked list effectively reorganizes fragmented space, maximizing space utilization within a page.
- Sequential access optimization: Logically adjacent records are stored on the same page, which is more suitable for sequential scan operations, significantly improving read efficiency.
These structural characteristics collaboratively optimize the InnoDB query performance while ensuring data reliability.
Index Page Format
As shown in the figure below, an index page consists of seven sections: File Header, Page Header, Infimum + Supremum, User Records, Free Space, Page Directory, and File Trailer.
| Name | Description |
|---|---|
| File Header | General information about the page, such as the current page number. |
| Page Header | Information specific to the data page, such as the number of records on the page. |
| Infimum + Supremum | Two virtual row records, representing the minimum and maximum records on the page. |
| User Records | Actual table data stored. |
| Free Space | Unused space on the page. |
| Page Directory | Address offset of the maximum record in each group on the page relative to the start of the page. |
| File Trailer | Used to verify whether the page is complete. |
- File Header
The file header describes some general information applicable to various types of pages, as shown in the table below.
Table 3 File header Name
Description
Occupied Space
FIL_PAGE_SPACE_OR_CHKSUM
Checksum of the page.
4 bytes
FIL_PAGE_OFFSET
Page number.
4 bytes
FIL_PAGE_PREV
Page number of the previous page.
4 bytes
FIL_PAGE_NEXT
Page number of the next page.
4 bytes
FIL_PAGE_LSN
LSN corresponding to the latest modification of the page.
8 bytes
FIL_PAGE_TYPE
Page type.
2 bytes
FIL_PAGE_FILE_FLUSH_LSN
This field is defined only on page 0 of the system tablespace, indicating the LSN to which the file has been flushed at a minimum.
8 bytes
FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID
ID of the tablespace to which the page belongs.
4 bytes
The following describes several important components:
- FIL_PAGE_OFFSET: page number of the current page, indicating the logical offset of the page in the data file.
- FIL_PAGE_PREV and FIL_PAGE_NEXT: store the page numbers of the previous and next pages, respectively. They connect physically discontinuous pages into logically adjacent pages at the same level of the B+ tree. On page 0 of the tablespace, these two fields are reloaded as FIL_PAGE_SRV_VERSION and FIL_PAGE_SPACE_VERSION.
On one hand, large tables struggle to acquire contiguous space at a time and can only be allocated in chunks. On the other hand, frequent page splits and reclaims cause logically adjacent pages to drift far apart on the disk. These two pointers are used to maintain a linked list structure that keeps indexes ordered at the logical level, allowing queries to quickly jump between physically non-contiguous pages.
- FIL_PAGE_LSN: LSN corresponding to the latest modification of the current data page. The idempotence of redo logs depends on this field. During crash recovery, if the LSN of a redo log is less than or equal to this value, the redo log is not applied.
- Page Header
Table 4 Page header Name
Occupied Space
Description
PAGE_N_DIR_SLOTS
2 bytes
Number of slots in the page directory. A new empty data page contains two slots, which point to the maximum and minimum records, respectively. The first slot always points to the minimum record, and the last slot always points to the maximum record.
PAGE_HEAP_TOP
2 bytes
Address of the lowest unused space. Any space with an address greater than this and less than the page directory is free space and can be used later.
PAGE_N_HEAP
2 bytes
Bit 15 is the compact format flag, and the remaining 15 bits (bits 14–0) indicate the number of records in the heap (including the minimum and maximum records and records marked as deleted).
PAGE_FREE
2 bytes
Address of the first record that has been physically deleted via purge. (Deleted records also form a single-linked list via next_record, and the records in this list can be reused.)
PAGE_GARBAGE
2 bytes
Number of bytes occupied by deleted records.
PAGE_LAST_INSERT
2 bytes
Position of the last inserted record.
PAGE_DIRECTION
2 bytes
Direction in which records are inserted.
PAGE_N_DIRECTION
2 bytes
Number of records inserted consecutively in the current direction, which is reset to zero when the direction changes.
PAGE_N_RECS
2 bytes
Number of records on the page, excluding the maximum and minimum records. Unlike PAGE_N_HEAP, this value decreases if a record is marked as delete_marked.
PAGE_MAX_TRX_ID
8 bytes
Maximum transaction ID of transactions that modified the current page. This value is defined only in secondary indexes.
PAGE_LEVEL
2 bytes
Level of the current page in the B+ tree. The value 0 indicates a leaf node.
PAGE_INDEX_ID
8 bytes
Index ID, indicating the index to which the current page belongs.
PAGE_BTR_SEG_LEAF
10 bytes
Header information of the B+ tree leaf segment, which is defined only on the root page of the B+ tree.
PAGE_BTR_SEG_TOP
10 bytes
Header information of the B+ tree non-leaf segment, which is defined only on the root page of the B+ tree.
-
These are two pseudo-records. In the DYNAMIC row format, each record consists of a 5-byte record header and an 8-byte fixed meaning. Since these two records are not user data, they are stored separately in the Infimum + Supremum section.
In TaurusDB, the infimum record is the logically smallest record on the data page, and all user records are greater than it. The supremum record is the largest record on the data page, and all user records are smaller than it. These two records are generated when the data page is created and cannot be deleted.
Figure 2 Infimum and supremum records
- User Records
All user records are stored here in row format. When a page is generated for the first time, this section is empty. Each time a record is inserted, the corresponding space is allocated from the free space to the user records. By default, there is no gap between records. However, if the space from deleted records is reused, space fragmentation may occur.
Records are sorted on the page in the order they are inserted. Each record contains a pointer (next_record) to the next record, forming a singly linked list. You can traverse the page starting from the infimum record through to the supremum record. In a clustered index, records are stored in primary key order. In a secondary index, records are sorted by index key and primary key.
User records include all active records and all deleted records (marked as delete_marked). Records that have been physically deleted via purge are moved to the PAGE_FREE list and are no longer accessible.
Figure 3 User records
- Free Space
The space between PAGE_HEAP_TOP and the last page directory is free space, which is reset to 0. When you need to insert a record, the system first attempts to find available space among the previously deleted records. If no suitable space is found, the system allocates space from here. After space is allocated to a record, the values of PAGE_N_RECS and PAGE_N_HEAP need to be incremented.
- Page Directory
To accelerate the query efficiency within a page and avoid traversing the single-linked list for each query, TaurusDB divides all valid records (including infimum and supremum records, but excluding deleted records) on the page into several groups for management. Records that are marked as deleted but have not been physically deleted via purge are still retained in the page directory and continue to be linked to the next_record logical linked list for subsequent unified cleanup.
- The last record in each group (that is, the largest record in the group) is used as the owner_rec, and its n_owned field stores the number of records in the group.
- The address offsets of the owner_rec are collected in index order to form the page directory, which is stored at the end of the page and grows from higher addresses toward lower addresses.
- File Trailer
This section is located at the very end of the data page and occupies only 8 bytes. The first four bytes represent the checksum of the page, and the last four bytes store the four least significant bytes of FIL_PAGE_LSN.
What is your overall rating for this page?
Thank you very much for your feedback. We will continue working to improve the documentation.See the reply and handling status in My Cloud VOC.
For any further questions, feel free to contact us through the chatbot.
Chatbot