fix(cmd): make database migration more robust to write errors (#10278)

Two things:
- We could run into a write error, which would block the progress
forever without an error. This because the writer routine exited, while
the reader was just blocked on sending to it.
- After a failed migration, inserts could fail with unique index
constraint errors because we are reusing the sequence numbers from the
original database. Add a drop folder to the start of migration to handle
this.

Additionally, the drop folder will clear out broken database files due
to killed migrations.
This commit is contained in:
Jakob Borg
2025-08-22 08:08:06 +02:00
committed by GitHub
parent 7bfcdfb577
commit 0416103f26
+15 -2
View File
@@ -197,12 +197,20 @@ func TryMigrateDatabase(deleteRetention time.Duration) error {
var writeErr error
var wg sync.WaitGroup
wg.Add(1)
writerDone := make(chan struct{})
go func() {
defer wg.Done()
defer close(writerDone)
var batch []protocol.FileInfo
files, blocks := 0, 0
t0 := time.Now()
t1 := time.Now()
if writeErr = sdb.DropFolder(folder); writeErr != nil {
slog.Error("Failed database drop", slogutil.Error(writeErr))
return
}
for fi := range fis {
batch = append(batch, fi)
files++
@@ -210,6 +218,7 @@ func TryMigrateDatabase(deleteRetention time.Duration) error {
if len(batch) == 1000 {
writeErr = sdb.Update(folder, protocol.LocalDeviceID, batch)
if writeErr != nil {
slog.Error("Failed database write", slogutil.Error(writeErr))
return
}
batch = batch[:0]
@@ -244,8 +253,12 @@ func TryMigrateDatabase(deleteRetention time.Duration) error {
// criteria in the database
return true
}
fis <- fi
return true
select {
case fis <- fi:
return true
case <-writerDone:
return false
}
})
close(fis)
snap.Release()