Firebird Documentation Index → Inside a Firebird Database → Database Header Page - Type 0x01 |
The first page of the first file of a Firebird database is a very important page. It holds data that describes the database, where its other files are to be found, shadow file names, database page size, ODS version and so on. On startup, the Firebird engine reads the first part (1,024 bytes) of the first page in the first file of the database and runs a number of checks to ensure that the file is actually a database and so on. If the database is multi-file, then each file will have a header page of its own.
The C code representation of the database header page is:
struct header_page { pag hdr_header; USHORT hdr_page_size; USHORT hdr_ods_version; SLONG hdr_PAGES; ULONG hdr_next_page; SLONG hdr_oldest_transaction; SLONG hdr_oldest_active; SLONG hdr_next_transaction; USHORT hdr_sequence; USHORT hdr_flags; SLONG hdr_creation_date[2]; SLONG hdr_attachment_id; SLONG hdr_shadow_count; SSHORT hdr_implementation; USHORT hdr_ods_minor; USHORT hdr_ods_minor_original; USHORT hdr_end; ULONG hdr_page_buffers; SLONG hdr_bumped_transaction; SLONG hdr_oldest_snapshot; SLONG hdr_backup_pages; SLONG hdr_misc[3]; UCHAR hdr_data[1]; };
Hdr_header: The database header page has a standard page header, as do all pages.
Hdr_page_size: Two bytes, unsigned. Bytes 0x10 - 0x11 on the page. This is the page size, in bytes, for each and every page in the database.
Hds_ods_version: Two bytes, unsigned. Bytes 0x12 and 0x13 on the page. The ODS major version for the database. The format of this word is the ODS major version ANDed with the Firebird flag of 0x8000. In the example below, the value is 0x800b for ODS version 11. The minor ODS version is held elsewhere in the header page - see hdr_ods_minor below.
Hdr_pages: Four bytes, signed. Bytes 0x14 - 0x17 on the page. This is the page number of the first pointer page for the table named RDB$PAGES. When this location is known, the database engine uses it to determine the locations of all other matadata pages in the database. This field is only valid in the header page of the first file in a multi-file database. The remaining files in the database have this field set to zero.
Hdr_next_page: Four bytes, unsigned. Bytes 0x18 - 0x1b on the page. The page number of the header page in the next file of the database - if this is a multi-file database. Zero otherwise.
Hdr_oldest_transaction: Four bytes, signed. Bytes 0x1c - 0x1f on the page. The transaction id of the oldest active (ie, uncommitted - but may be in limbo or rolled back) transaction against this database. This field is only valid in the header page of the first file in a multi-file database. The remaining files in the database have this field set to zero.
Hdr_oldest_active: Four bytes, signed. Bytes 0x20 - 0x23 on the page. The transaction id of the oldest active transaction against this database, when any active transaction started. This field is only valid in the header page of the first file in a multi-file database. The remaining files in the database have this field set to zero.
Hdr_next_transaction: Four bytes, signed. Bytes 0x24 - 0x27 on the page. The transaction id that will be assigned to the next transaction against this database. This field is only valid in the header page of the first file in a multi-file database. The remaining files in the database have this field set to zero.
Hdr_sequence: Two bytes, unsigned. Bytes 0x28 and 0x29 on the page. The sequence number of this file within the database.
Hdr_flags: Two bytes, unsigned. Bytes 0x2a and 0x2b on the page. The database flags. The bits in the flag bytes are used as follows:
Flag Name | Flag value | Description |
---|---|---|
hdr_active_shadow | 0x01 (bit 0) | This file is an active shadow file. |
hdr_force_write | 0x02 (bit 1) | The database is in forced writes mode. |
Unused | 0x04 (bit 2) | Was previously for short term journalling, no longer used. |
Unused | 0x08 (bit 3) | Was previously for long term journalling, no longer used. |
hdr_no_checksums | 0x10 (bit 4) | Don't calculate checksums. |
hdr_no_reserve | 0x20 (bit 5) | Don'r reserve space for record versions in pages. |
Unused | 0x40 (bit 6) | Was used to indicate that the shared cache file was disabled. |
hdr_shutdown_mask (bit one of two) | 0x1080 (bits 7 and 12) | Used with bit 12 (see below) to indicate the database shutdown mode. |
hdr_sql_dialect_3 | 0x100 (bit 8) | If set, the database is using SQL dialect 3. |
hdr_read_only | 0x200 (bit 9) | Database is in read only mode. |
hdr_backup_mask | 0xC00 (bits 10 and 11) | Indicates the current backup mode. |
hdr_shutdown_mask (bit two of two) | 0x1080 (bits 7 and 12) | Used with bit 7 (see above) to indicate the database shutdown mode. |
The final two database flags use a pair of bits to indicate various states of backup and shutdown.
Hdr_backup_mask: These two bits determine the current database backup mode, as follows:
Flag Value | Description |
---|---|
0x00 (Both bits zero) | Database is not in backup mode. User changes are written directly to the database files. |
0x400 | The database is running in backup mode so all changed made by the users are written to the diff file. |
0x800 | The database is still in backup mode, but changes are being merged from the diff file into the main pages. |
0xC00 | The current database state is unknown and changes need to be read from disc. |
Hdr_shutdown_mask: The shutdown mask uses two bits to indicate the current database shutdown status, as follows:
Flag Value | Description |
---|---|
0x00 (Both bits 7 and 12 are zero) | Database is not shutdown. Any valid user can connect. |
0x80 | The database has been shutdown to, or started up in multi-user maintenance mode. The database can only be conncted to by SYSDBA or the database owner. |
0x1000 | The database has been fully shutdown. No connections are permitted. |
0x1080 | The database has been shutdown to, or started up in single-user maintenance mode. Only one SYSDBA or database owner connection is permitted. |
Hdr_creation_date: Eight bytes, signed. Bytes 0x2c - 0x33 on the page. The data and time (in Firebird's own internal format) that the database was either originally created/rewritten or created from a backup.
Hdr_attachment_id: Four bytes, signed. Bytes 0x34 - 0x37 on the page. The id number that will be assigned to the next connection to this database. As this is signed, the maximum value here is 232-1 and any database which reaches this maximum value must be backed up and restored in order to allow new connections. This field is only valid in the header page of the first file in a multi-file database. The remaining files in the database have this field set to zero.
Hdr_shadow_count: Four bytes, signed. Bytes 0x38 - 0x3c on the page. Holds the event count for shadow file synchronisation for this database. The remaining files in the database have this field set to zero.
Hdr_implementation: Two bytes, signed. Bytes 0x3c and 0x3d on the page. This is a number which indicates the environment on which the database was originally created. It is used to determine if the database file can be used sucessfully on the current hardware. This avoids problems caused by little-endian numerical values as compared with big-endian, for example.
Hdr_ods_minor: Two bytes, unsigned. Bytes 0x3e and 0x3f on the page. The current ODS minor version.
Hdr_ods_minor_original: Two bytes, unsigned. Bytes 0x40 and 0x41 on the page. The ODS minor version when the database was originally created.
Hdr_end: Two bytes, unsigned. Bytes 0x42 and 0x43 on the page. The offset on the page where the hdr_data finishes. In other words, where a new clumplet will be stored if required. This is effectively a pointer to the current location of HDR_end (see clumplet details below) on this page.
Hdr_page_buffers: Four bytes, unsigned. Bytes 0x44 - 0x47 on the page. Holds the number of buffers to be used for the database cache, or zero to indicate that the default value should be used. This field is only valid in the header page of the first file in a multi-file database. The remaining files in the database have this field set to zero.
Hdr_bumped_transaction: Four bytes, signed. Bytes 0x48 - 0x4b on the page. Used to be used for the bumped transaction id for log optimisation, but is currently always set to 0x01. This field is only valid in the header page of the first file in a multi-file database. The remaining files in the database have this field set to zero.
Hdr_oldest_snapshot: Four bytes, signed. Bytes 0x4c - 0x4f on the page. Holds the transaction number for the oldest snapshot of active transactions. This is also documented as the confusing and redundant variant of Oldest Active Transaction.
Hdr_backup_pages: Four bytes, signed. Bytes 0x50 - 0x53 on the page. Holds the number of pages in the database currently locked for a backup using nbackup. This field is only valid in the header page of the first file in a multi-file database. The remaining files in the database have this field set to zero.
Hdr_misc: Twelve bytes. Bytes 0x54 - 0x5f on the page. Set to zero. These 12 bytes are currently unused.
The following is an example of a header page from a multi-file database on a little-endian system:
00000000 01 00 39 30 08 00 00 00 00 00 00 00 00 00 00 00 Standard header 00000010 00 10 hdr_page_size 00000012 0b 80 hdr_ods_version 00000014 03 00 00 00 hdr_PAGES 00000018 00 00 00 00 hdr_next_page 0000001c 01 00 00 00 hdr_oldest_transaction 00000020 02 00 00 00 hdr_oldest_active 00000024 05 00 00 00 hdr_next_transaction 00000028 00 00 hdr_sequence 0000002a 00 01 hdr_flags 0000002c 5e d7 00 00 f4 79 00 23 hdr_creation_date 00000034 01 00 00 00 hdr_attachment_id 00000038 00 00 00 00 hdr_shadow_count 0000003c 13 00 hdr_implementation 0000003e 01 00 hdr_ods_minor 00000040 01 00 hdr_ods_minor_original 00000042 93 00 hdr_end 00000044 00 00 00 00 hdr_page_buffers 00000048 01 00 00 00 hdr_bumped_transaction 0000004c 02 00 00 00 hdr_oldest_snapshot 00000050 00 00 00 00 hdr_backup_pages 00000054 00 00 00 00 00 00 00 00 00 00 00 00 hdr_misc 00000060 hdr_data[]
From Firebird 2.x onwards, there is a system table - MON$DATABASE which has a copy of all of the above data in an easy to obtain format:
tux> isql employee Database: employee SQL> show table mon$database; MON$DATABASE_NAME (RDB$FILE_NAME) VARCHAR(253) Nullable MON$PAGE_SIZE (RDB$PAGE_SIZE) SMALLINT Nullable MON$ODS_MAJOR (RDB$ODS_NUMBER) SMALLINT Nullable MON$ODS_MINOR (RDB$ODS_NUMBER) SMALLINT Nullable MON$OLDEST_TRANSACTION (RDB$TRANSACTION_ID) INTEGER Nullable MON$OLDEST_ACTIVE (RDB$TRANSACTION_ID) INTEGER Nullable MON$OLDEST_SNAPSHOT (RDB$TRANSACTION_ID) INTEGER Nullable MON$NEXT_TRANSACTION (RDB$TRANSACTION_ID) INTEGER Nullable MON$PAGE_BUFFERS (RDB$PAGE_BUFFERS) INTEGER Nullable MON$SQL_DIALECT (RDB$SQL_DIALECT) SMALLINT Nullable MON$SHUTDOWN_MODE (RDB$SHUTDOWN_MODE) SMALLINT Nullable MON$SWEEP_INTERVAL (RDB$SWEEP_INTERVAL) INTEGER Nullable MON$READ_ONLY (RDB$SYSTEM_FLAG) SMALLINT Nullable MON$FORCED_WRITES (RDB$SYSTEM_FLAG) SMALLINT Nullable MON$RESERVE_SPACE (RDB$SYSTEM_FLAG) SMALLINT Nullable MON$CREATION_DATE (RDB$TIMESTAMP) TIMESTAMP Nullable MON$PAGES (RDB$COUNTER) BIGINT Nullable MON$STAT_ID (RDB$STAT_ID) INTEGER Nullable MON$BACKUP_STATE (RDB$BACKUP_STATE) SMALLINT Nullable SQL> commit; SQL> quit;
Hdr_data: The variable data area on the header page begins at offset 0x60. Data stored here is held in clumplets and there are a number of different clumplet types, see below. This area is used to store filenames for the next file and other miscellaneous pieces of data relating to the database.
The format of each clumplet is as follows:
Type_byte: The first byte - unsigned - in each clumplet determines the type of data stored within the clumplet. There are a number of different clumplet types:
Type Name | Value | Description |
---|---|---|
HDR_end | 0x00 | End of clumplets. |
HDR_root_file_name | 0x01 | Original name of the root file for this database. |
HDR_journal_server | 0x02 | Name of the journal server. |
HDR_file | 0x03 | Secondary file name. |
HDR_last_page | 0x04 | Last logical page of the current file. |
HDR_unlicemsed | 0x05 | Count of unlicensed activity. No longer used. |
HDR_sewwp_interval | 0x06 | Number of transactions between sweep. |
HDR_log_name | 0x07 | Replay log name. |
HDR_journal_file | 0x08 | Intermediate journal filename. |
HDR_password_file_key | 0x09 | Key to compare with the password database. |
HDR_backup_info | 0x0a | Write Ahead Log (WAL) backup information. No longer used. |
HDR_cache_file | 0x0b | Shared cache file. No longer used. |
HDR_difference_file | 0x0c | Diff file used during the times when the database is in backup mode. |
HDR_backup_guid | 0x0d | UID generated when database is in backup mode. Overwritten on subsequent backups. |
Length_byte: The second byte - again unsigned - in each clumplet specifies the size of the data that follows.
Data: The next 'n' bytes are the actual clumplet data. The miscellaneous data stored in the header from the above database, at hdr_data, is shown below.
00000060 03 Type = HDR_file 00000061 2b Length = 43 bytes 00000062 2f 75 30 30 2f 66 69 72 65 62 69 72 64 2f Data '/u00/firebird/' 00000070 64 61 74 61 62 61 73 65 73 2f 6d 75 6c 74 69 5f 'databases/multi_' 00000080 65 6d 70 6c 6f 79 65 65 2e 66 64 62 31 'employee.fdb1' 0000008d 04 Type = HDR_last_page 0000008e 04 Length = 4 bytes 0000008f a2 00 00 00 Data 0xa2 = 162 00000093 00 Type = HDR_end.
From the above we can see that in our multi-file database:
The next file (after this one) is named
'/u00/firebird/databases/multi_employee.fdb1
'
The current file has 162 pages only - and with a 4Kb page size this means that the current file should be 663,552 bytes in size, which a quick run of ls -l will confirm.
HDR_end is located at offset 0x93 in the page, exactly as the header field hdr_end told us. (See above).
Firebird Documentation Index → Inside a Firebird Database → Database Header Page - Type 0x01 |