Incremental dumps/File format

This document describes how I imagine initial version of incremental dump files to look like, along with some improvements (some necessary, others just nice to have). This version (black text only) should be completed by 29 July.

A dump file in the new format will contain:


 * At offset 0: header containing some basic information, especially offsets to indexes.
 * Indexes. These are used to map one value to another, e.g. page title to page id or page id to file offset.
 * Page objects. Equivalent to in XML dumps.
 * Revision objects. Equivalent to in XML.

Most data will be saved directly in a binary format (so, e.g. page id will be 4 bytes). Revision text is handled in a special way.

Indexes
Each index will map from one value to another. A complete dump file will contain the following indexes:


 * fake namespace id → real namespace id + namespace name
 * page namespace + page title → page id
 * page id → file offset of the corresponding page object
 * revision id → file offset of the corresponding revision object
 * user id → user name
 * index of free blocks, sorted by size

An index will be saved as a B-tree, each node of the tree will be relatively big (4K?). Each node will be saved in the file separately, so that the index can easily grow (and shrink).

The file header will contain offsets of the root node for each index.

To save space, string keys will be saved using incremental encoding, integer keys using simple form of delta compression.

Page object
The page object is the equivalent of in XML dumps, so it contains page id, page namespace, page title and a list of revision ids. What revision ids will be present depends on the dump type: “current” dumps will have just the most recent revision, “history” dumps will have the full list.

Revision object
The page object is the equivalent of in XML dumps, so it contains revision id, parent revision id, timestamp, contributor, comment, bot and minor flags and SHA-1.

The initial implementation will save revision text (if present) together with the revision, each revision compressed separately using 7zip or another compression. The final version will use a better compression scheme, either by compressing a group of revisions together or by using some sort of delta compression (similar to git pack files).

Free space and deletions
After an object or index node is deleted, it will leave behind free space. When a new object (or index node) is created, it will first try to fit into one of those free spaces (this will use index of free blocks). If it doesn't fit anywhere, it will be appended to the end of the file. If free space is created next to another one, the two have to merged.

Because of this, a dump file may contain some unused space. Hopefully, this won't be a big issue, because the small page objects will fill most of the space where the large revisions objects won't fit.

Deleting a revision and then adding another one (usually of another size) has to work well, because this will happen extremely often in “current” dumps (basically, every new revision that's not a new page will cause deletion of previous revision of that page).

With improved compression, text of one revision depends on other revisions. In the case of compressing revisions in groups, this would mean recompressing the whole group. In the case of delta compression, this would mean tracking what revisions depend on what revisions and recompressing revisions that directly depend on the deleted one.

Diff dumps
Another feature not in the initial version are “diff dumps”. Along with normal dumps, a “diff” will be produced that will contain all changes since the last dump. This way, a user doesn't have to download the whole dump every time, he can download just the changes and apply them to his previously downloaded dump.

If delta compression is implemented, diff dumps could use a specific form of it: the revision text can be compressed using revisions that are present in the dump that's being updated, but not in the diff dump itself (even if the base revision is to be deleted). This can be especially useful for diff dumps of “current” dumps.