[0.13] core: Track upgrade step within each schema version #474
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
In short
upgrade_###_XXX.sql
) within each schema versionschemaupgradestep
, cleared when a schema version upgrade finishesupdateSchemaVersion()
callThis is applied to
master
here.Rationale
Single query schema versions were handled in pull request #364, and much of the same rational applies here.
When running upgrade queries, track the schema step filename for each intermediate step. This ensures that any interrupted upgrades have a greater chance of resuming correctly after core restart.
Almost all databases make single queries atomic (fully works or fully fails, no partial), and storing progress after each query makes upgrade interruptions much more likely to leave the database in a resumable intermediate schema version.
Examples
Simulated interruptions using debugger
NOTE₁: The storage backend will be disabled on the first error, falling back to an unconfigured state. You will need to restart the Quassel core to resume the upgrade. This feature/issue exists in
0.13
and earlier.NOTE₂: All situations were tested in
0.13
using a rollup of0.13
backport pull requests to save testing time.Bundled PRs: #458, #462, #469, #471, #472, and the current PR. The current
master
branch was briefly tested before.Good scenario 1: Some upgrade queries complete in one version
abstractsqlstorage.cpp
, set a breakpoint onsetSchemaVersionUpgradeStep(queryResource.queryFilename);
coreinfo
'sschemaupgradestep
gets set correctlyupgrade_000_create_sender_tmp
(from SQLite version 29)upgrade_010_alter_sender_64bit_ids
(from PostgreSQL version 29)🆕 New to this PR
Example log (SQLite)
Example log (PostgreSQL)
Good scenario 2: All upgrade queries complete in one version
abstractsqlstorage.cpp
, set a breakpoint onif (!updateSchemaVersion(ver, true)) {
coreinfo
'sschemaupgradestep
gets cleared to empty stringcoreinfo
'sschemaversion
gets incremented correctly🏁 In
0.13
stableExample log (SQLite)
Example log (PostgreSQL)
Bad scenario 3: Some upgrade queries complete in one version, but upgrade step not set
abstractsqlstorage.cpp
, set a breakpoint onsetSchemaVersionUpgradeStep(queryResource.queryFilename);
coreinfo
'sschemaupgradestep
gets set to previous step correctlycoreinfo
'sschemaupgradestep
to the last successful stepupgrade_000_create_sender_tmp
(from SQLite version 29)upgrade_000_update_sender_add_realname
(from PostgreSQL version 27)☑️ Broken before this PR, manual recovery made easier
Example log (SQLite)
Example log (PostgreSQL)
Bad scenario 4: An upgrade query fails in one version
29/upgrade_010_copy_sender_sender_tmp.sql
,INSERT INTO SELECT;
29/upgrade_050_alter_buffer_64bit_ids.sql
,INSERT INTO SELECT;
coreinfo
'sschemaupgradestep
gets set correctlyupgrade_000_create_sender_tmp
(from SQLite version 29)upgrade_050_alter_buffer_64bit_ids
(from PostgreSQL version 29)☑️ Broken before this PR, manual recovery made easier
This mimics the upgrade case for PostgreSQL 8.4, where a
CREATE LANGUAGE plpgsql;
command will need manually run, then the upgrade can resume automatically after that.Example log (SQLite)
Example log (PostgreSQL)
Bad scenario 5: Some upgrade queries complete in one version, Quassel core SQL resources renamed
abstractsqlstorage.cpp
, set a breakpoint onsetSchemaVersionUpgradeStep(queryResource.queryFilename);
coreinfo
'sschemaupgradestep
to an invalid stepupgrade_000_DOES_NOT_EXIST
☑️ Broken before this PR, manual recovery made easier
Example log (SQLite)
Example log (PostgreSQL)
Non-deterministic interruption via
kill
Steps
kill -9
) interrupting upgradeStatistics
kill -9
) 45 times during17
→31
schema upgrade0.1
seconds, manually run (auto-resume worked)kill -9
's every0.1
secondsCommands run
run-profile.sh
is a script to simplify managing multiple testing copies of Quassel and is equivalent to calling the rightquasselcore
with the right optionsQuassel and SQLite commands run for testing and manual recovery
Interrupted upgrade log
Quassel log from interrupted upgrades