Problem/Motivation
This is an issue that we haven't had to deal with since the Drupal 6 to Drupal 7 upgrade path, but now we do again.
The following scenarios are broken:
hook_update_N()
system_update_100000()
is added to 11.0.x and 10.3.x
[time elapses]
system_update_100100()
is added to 11.1.x to support a new feature, it is not backported to 10.4.x
[time elapses]
A critical bug fix which is eligible for backport to 10.4.x, but requires a small update, is committed to 11.1.x
[dragons emerge from the darkness, volcanos erupt]
If this update is added as system_update_100101()
and backported to 10.4.x, then when 10.4.x sites are updated to 11.1.x, they won't run system_update_100100() because their schema version will be higher already.
If this update is added as system_update_100001() in 11.1.x, and 10.4.x
, it won't run on 11.x sites because their schema version will be 100100
already.
hook_post_update_NAME()
This is less of an issue, but still a problem:
system_post_update_fix_config() is added to 11.1.x, it is backported to 10.4.x, but not 11.0.x because it's security-only.
If a site updates from 10.4.x to 11.0.x, then the post update goes 'missing' from the code base. It will then re-emerge when the site updates again to 11.1.x or 11.2.x
Sequential backports to minor branches without skipping a release are OK though for post updates regardless of how far they go back, since they don't interfere with other post updates.
Proposed resolution
This is only a serious problem for hook_update_N() due to sequential update ordering. Because post updates are tracked individually and order isn't guaranteed, the only issue with those is a site updating from 10.4 to 11.0 (i.e. 'backwards' in terms of minor release parity).
For hook_update_N(), we can add a small API addition to the update system, which will probably be exclusively used by core updates.
1. An 11.x hook_update_N() would be added as normal, with no extra method calls or metadata. Let's say system_update_11100()
2. When that same update is backported to 10.x, we backport it with it's own update number, say system_update_10400().
In system_update_10400(), we call \Drupal::service('update.update_hook_registry')->skipUpdate(11100)
This logs the module, update being run, and future update, to a key value collection.
When a site updates to 11.1 from 10.4, it will have this information in key value. In update_do_one() we then check against the key value collection, and if an 11.1 update should be skipped, we skip it and log a success message.
The huge advantage of this is that there is no 11.x-specific code dealing with the 10.4.x update numbers, we just need the API in place to check key/value and that's it. 11.x updates can be committed with no API changes. 10.4 update backports need to call one method with a small amount of information.
If a site tries to update to 11.0 from 10.4, then in terms of database updates it will be going 'backwards' - however because we have the key value store, we can detect this, and issue an update requirements error telling them to go to 11.1 instead.
Remaining tasks
User interface changes
API changes
Data model changes
Release notes snippet