Subject Transportable databases (2 of 3)
Author Ann W. Harrison
Implementation details...

Once Firebird has established that a database is "other endian" but
has a matching alignment, it transforms the structure of each page
into the local endian format when the page is read into cache. When
the page is written, Firebird copies it to a scratch buffer and
converts the structural data back to the original endian format.

Specifically... on read or write, a pointer to the page is sent
to the swap code, together with a boolean that indicates whether
the operation is read or write. The code that performs the
inversion is the same for input and output, except where the
page includes a count of the items on it. In that case, the
count must be kept in the local format so iteration works.

The page header of every page is converted.

The conversion then cases on page type to convert the remainder
of the page.

Header page (HDR). The swap code switches each binary field and the
timestamp field in the fixed part of the header. Data stored
in clumplets in the variable portion of the header is not converted
because the clumplets are designed to be architecture independent.

Page Inventory Page (PIP). The swap code fixes the pip_min field
which indicates the lowest unallocated page in the bit vector that
fills the rest of the page. The bit vector is unaffected.

Transaction Inventory Page (TIP). The swap code fixes the page
number of the next TIP. The transaction array is unaffected.

Pointer Page (PPG). If the page is being written, the current
value of ppg_count is saved then inverted, otherwise the count
is inverted and saved. Then the sequence, next page number,
relation id, min_space, and max_space are inverted. Then the
array of page numbers is inverted, using the saved count to
avoid inverting the page fill level information at the bottom
of the pages.

Data Pages (DPG). As with the PPG, save the count in its local
format. Then fix the sequence and relation. Then, using the
count as a limit, iterate through the index changing the offset
and length of each entry. Use the offset to find the header
for each entry. Pass the in/out boolean to the code that
converts headers so it will look at the local version of the
flags word and case on the type : blob, record, or fragmented
record. In the case of a blob header, if the blob is not a
level 0, use the local value of blh_max_sequence as a limit and
invert each page number in the the array of blob pages numbers.

Index Root Pages (IRT). As with PPG, save the count in local
format. Iterate through the descriptors, swapping the binary
values in the descriptors. For each descriptor, also swap the
values in the individual field descriptors. Since field
descriptors come up from the bottom of the page, the routine
that inverts index root pages takes the page size as an
extra parameter.

Index pages (BTR). Invert the fixed information at the top of
the page (sibling, left sibling, prefix total, relation, and
length. For indexes with jump nodes - which is all ODS-11
indexes with a page size > 1024 and large keys and all record
number, also swap the description of the jump node area and the
pointers in the jump nodes.


Blob pages (BLB). Invert the fixed header portion of the page
(lead page, sequence, and length) then if the blob page is not
level zero, iterate through it, inverting the page numbers.
There's nothing interesting at the bottom of a blob page, so
just stop the iteration before the end of the page.

Generator pages (GPG). Invert the fixed header portion of
the page, then starting at the first generator location
invert all the generators - including those allocated and
those that might be allocated in the future. This routine
takes an extra parameter which is the number of generators
that fit on a generator page.

Write ahead log pages - not done.