# Database schema version ranges Synapse currently has the concept of a database "schema version", which is used to forestall problems where a database update is performed, but the deployment is then rolled back to an earlier version, causing incompatibility. This is implemented via the `synapse.storage.prepare_database.SCHEMA_VERSION` constant and the `schema_version.version` database column. The problem with this approach is that it makes it impossible to roll Synapse back to an earlier version. In practice, we often take a "rolling" approach to schema changes. For example, consider the situation where a database table (say, `old_table`) becomes redundant; we might do the following: * Synapse version N: original version * Synapse version N+1: remove code that *reads* from `old_table`, but keep writing to it in case of rollback to version N. * Synapse version N+2: remove code that *writes* to `old_table`, but don't yet remove the table in case of rollback to version N+1. * Synapse version N+3: remove `old_table` completely. The precise details vary, but such a pattern of gradually evolving database code in a way that maintains compatibility with one or two earlier versions is not uncommon. Ideally, we would complain about attempts to roll back from N+2 to N, whilst allowing roll-back from N+1 to N or N+2 to N+1; however the `schema_version` implementation makes that impossible. ## Proposal * We change the semantics of `schema_version.version` to indicate the *oldest* `SCHEMA_VERSION` that the database is compatible with. * At startup, Synapse continues to abort if `schema_version.version` is greater than `synapse.storage.prepare_database.SCHEMA_VERSION`. * However, `schema_version.version` is no longer set to `prepare_database.SCHEMA_VERSION` (we probably need a different constant for it). In the above example: * Synapse version N+1 would have `prepare_database.SCHEMA_VERSION=N+1`, (and would add its delta files to `delta/<N+1>`) to reflect that it uses the database differently to version N, but would set `schema_version.version=N`, since the database will still be compatible with Synapse version N. * Likewise, Synapse version N+2 would set `prepare_database.SCHEMA_VERSION=N+2`, and must set `schema_version.version=N+1`, to denote that we have broken compatibility with version N.