Multi-Content Revisions/Page Update Controller

Updating a revision is a complex process, with complicated requirements with regards to the usage of transactional logic and deferred updates. To honor these requirements, a stateful "interactor" objects are defiend in addition to the stateless storage service:

PageUpdater shall be used to create new revisions when a page is edited (or created). RevisionUpdater can be used to update derived content when some dependency (e.g. a template) changes.

Updater behavior:
 * setSlotContent will fail for any virtual slot.
 * RevisionUpdater::setSlotContent will fail for any primary.
 * $content can be set to null to explicitly remove the slot from the revision, preventing any content of that slot to be re-used from earlier revisions.
 * as indicated by the names, begin, rollback and createRevision resp updateRevision shall be used to create a transactional bracket around the calls to setSlotContent. However, no transactional behavior is guaranteed.
 * Implementations shall free any resources (such as database connections) when concluding the transaction.
 * Implementations shall take care to undo any effect any calls to setSlotContent may have had.

createRevision (resp updateRevision) would take the place of WikiPage::doEditConent. All the relevant code should be moved to PageUpdater. WikiPage::doUpdateConent should then be re-implemented based on a (global default) instance of RevisionUpdaterFactory.

TBD: can WikiPage itself act as the factory for PageUpdateController for now?

Note: Maintaining backwards compatibility for hooks may be a major challange.

TBD: it seems something like the PageUpdater is needed on two levels: a high level PageUpdater which automatically generates derived content and takes care of secondary data updates; and a low level PageUpdater which does nothing but store Content objects. It's not clear yet which component/class would be responsible for handling derived content.

Site note: the idea of derived content is tightly bound to dependency tracking: when storing derived content, we should also store what it was derived from. And when the base content changes, we need to update the derived content. Thus, dependency tracking should be implemented on the level of slots, not pages: the wikitext of a page doesn't depend on the templates it uses, but the rendered HTML of the page does.

The initial implementation of the updaters should allow the storage of additional primary and derived slots using MediaWiki's standard storage mechanism (i.e. the text table and/or the ExternalStore mechanism). The association between revisions and content blobs, along with the meta-data for each slot, shall be maintained in a new database table revision_slots with the following fields:

A RevisionContentLookup would need to be implemented on top of this table, replacing the one that was relying on the revision table (and could thus only support the main slot).

The following fields in the revision table should be modified or deprecated (or dropped, at least for new installs):


 * rev_text_id (deprecated, can be kept for B/C if the main slot content is in the text table or external store)
 * rev_deleted (as before - or do we need this per slot?)
 * rev_len (sum of the sized of all primary slots associated with this revision)
 * rev_sha1 (hash of the hashes of all primary slots; for B/C, could be the main slot's hash)
 * rev_content_format (deprecated; could be the format of the main slot for B/C)
 * rev_content_model (deprecated; could be the model of the main slot for B/C)

Note that virtual slots would not have entries in the revision_slots table. It is sufficient for the respective RevisionContentLookup to declare that the slot is available for the given revision. The association between the revision and the content of virtual slots is purely programmatic.