From 2ba3be5e4dc538e3883e32be1d0ad12b45a02746 Mon Sep 17 00:00:00 2001 From: Simon Frei Date: Wed, 21 Oct 2020 14:21:09 +0200 Subject: [PATCH] lib/db: Add mechanism to repair db without schema update (ref #7044) (#7047) --- lib/db/schemaupdater.go | 63 ++++++++++++++++++++++++++++++----------- 1 file changed, 46 insertions(+), 17 deletions(-) diff --git a/lib/db/schemaupdater.go b/lib/db/schemaupdater.go index 6a998d2a4..c33c3a252 100644 --- a/lib/db/schemaupdater.go +++ b/lib/db/schemaupdater.go @@ -28,8 +28,12 @@ import ( // 10-11: v1.6.0 // 12-13: v1.7.0 // 14: v1.9.0 +// +// dbMigrationVersion is for migrations that do not change the schema and thus +// do not put restrictions on downgrades (e.g. for repairs after a bugfix). const ( dbVersion = 14 + dbMigrationVersion = 15 dbMinSyncthingVersion = "v1.9.0" ) @@ -46,6 +50,8 @@ func (e *databaseDowngradeError) Error() string { return fmt.Sprintf("Syncthing %s required", e.minSyncthingVersion) } +// UpdateSchema updates a possibly outdated database to the current schema and +// also does repairs where necessary. func UpdateSchema(db *Lowlevel) error { updater := &schemaUpdater{db} return updater.updateSchema() @@ -77,33 +83,44 @@ func (db *schemaUpdater) updateSchema() error { return err } - if prevVersion == dbVersion { + prevMigration, _, err := miscDB.Int64("dbMigrationVersion") + if err != nil { + return err + } + // Cover versions before adding `dbMigrationVersion` (== 0) and possible future weirdness. + if prevMigration < prevVersion { + prevMigration = prevVersion + } + + if prevVersion == dbVersion && prevMigration >= dbMigrationVersion { return nil } type migration struct { - schemaVersion int64 - migration func(prevVersion int) error + schemaVersion int64 + migrationVersion int64 + migration func(prevSchema int) error } var migrations = []migration{ - {1, db.updateSchema0to1}, - {2, db.updateSchema1to2}, - {3, db.updateSchema2to3}, - {5, db.updateSchemaTo5}, - {6, db.updateSchema5to6}, - {7, db.updateSchema6to7}, - {9, db.updateSchemaTo9}, - {10, db.updateSchemaTo10}, - {11, db.updateSchemaTo11}, - {13, db.updateSchemaTo13}, - {14, db.updateSchemaTo14}, + {1, 1, db.updateSchema0to1}, + {2, 2, db.updateSchema1to2}, + {3, 3, db.updateSchema2to3}, + {5, 5, db.updateSchemaTo5}, + {6, 6, db.updateSchema5to6}, + {7, 7, db.updateSchema6to7}, + {9, 9, db.updateSchemaTo9}, + {10, 10, db.updateSchemaTo10}, + {11, 11, db.updateSchemaTo11}, + {13, 13, db.updateSchemaTo13}, + {14, 14, db.updateSchemaTo14}, + {14, 15, db.migration15}, } for _, m := range migrations { - if prevVersion < m.schemaVersion { - l.Infof("Migrating database to schema version %d...", m.schemaVersion) + if prevMigration < m.migrationVersion { + l.Infof("Running database migration %d...", m.migrationVersion) if err := m.migration(int(prevVersion)); err != nil { - return fmt.Errorf("failed migrating to version %v: %w", m.schemaVersion, err) + return fmt.Errorf("failed to do migration %v: %w", m.migrationVersion, err) } } } @@ -114,6 +131,9 @@ func (db *schemaUpdater) updateSchema() error { if err := miscDB.PutString("dbMinSyncthingVersion", dbMinSyncthingVersion); err != nil { return err } + if err := miscDB.PutInt64("dbMigrationVersion", dbMigrationVersion); err != nil { + return err + } l.Infoln("Compacting database after migration...") return db.Compact() @@ -749,6 +769,15 @@ func (db *schemaUpdater) updateSchemaTo14(_ int) error { return nil } +func (db *schemaUpdater) migration15(_ int) error { + for _, folder := range db.ListFolders() { + if _, err := db.recalcMeta(folder); err != nil { + return err + } + } + return nil +} + func (db *schemaUpdater) rewriteGlobals(t readWriteTransaction) error { it, err := t.NewPrefixIterator([]byte{KeyTypeGlobal}) if err != nil {