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, stateful "interactor" objects is used to manage the update.

Interface
(Code experiment: https://gerrit.wikimedia.org/r/#/c/217710/) In order to support updating derived content, a RevisionUpdateController could be defined on the same level as PageUpdater. There is no need to implement RevisionUpdateController initially, but the concept should be kept in mind.
 * PageUpdater shall be used to create new revisions when a page is edited (or created).
 * Application code can acquire an PageUpdater from a factory. As a first step, WikiPage can act as that factory.
 * The logic for updating the page and revision tables will move from WikiPage (and Revision) to PageUpdater. The save method will take the place of WikiPage::doEditConent.
 * PageUpdater will rely on the RevisionSlotStore to store content meta-data, and on BlobStore (or ContentStore) to store the actual content.

Page Update Process

 * When a page is edited, the content of at least one slot is updated. It does not matter whether a slot with the same role existed in the previous revision.
 * One edit (user interaction) creates one revision, regardless of how many slots were updated (see also Content Meta-Data).


 * Unchanged content of slots is re-used from previous revisions (see Content Meta-Data Data Model). E.g.:
 * Revision 1 has two slots, A and B, with content ( A1, B1 )
 * Now, slot A is edited, but slot B is untouched. Then revision 2 is ( A2, B1 ). That is, slot B in revision two is the same content as slot B of revision 1.

If support for derived content is desired, derived content can be re-calcuated when a revision is saved. Such "materialized" derived content could be saved along with the primary content, and it could provide it's own secondary data updates like LinksUpdate. Note that derived content of a revision can be updated later without creating a new revision.
 * SecondaryDataUpdates are created and executed for all content objects of a revision. If the content of a slot is not modified by a new revisions, it may be possible to omit or optimize the SecondaryDataUpdates for that content object.