From 40580d8b9b2d72e0ddd5c46ab5b8c790ba6d8134 Mon Sep 17 00:00:00 2001 From: Simon Frei Date: Thu, 19 Mar 2020 14:30:20 +0100 Subject: [PATCH] lib/db: Remove emptied global list in checkGlobals (fixes #6425) (#6426) --- lib/db/db_test.go | 37 +++++++++++++++++++++++++++++++++++++ lib/db/lowlevel.go | 6 +++++- lib/db/structs.go | 3 +-- lib/db/transactions.go | 4 ---- 4 files changed, 43 insertions(+), 7 deletions(-) diff --git a/lib/db/db_test.go b/lib/db/db_test.go index a80656e35..9266e99ca 100644 --- a/lib/db/db_test.go +++ b/lib/db/db_test.go @@ -440,3 +440,40 @@ func TestDowngrade(t *testing.T) { t.Fatalf("Error has %v as min Syncthing version, expected %v", err.minSyncthingVersion, dbMinSyncthingVersion) } } + +func TestCheckGlobals(t *testing.T) { + db := NewLowlevel(backend.OpenMemory()) + defer db.Close() + + fs := NewFileSet("test", fs.NewFilesystem(fs.FilesystemTypeFake, ""), db) + + // Add any file + name := "foo" + fs.Update(protocol.LocalDeviceID, []protocol.FileInfo{ + { + Name: name, + Type: protocol.FileInfoTypeFile, + Version: protocol.Vector{Counters: []protocol.Counter{{ID: 1, Value: 1001}}}, + }, + }) + + // Remove just the file entry + if err := db.dropPrefix([]byte{KeyTypeDevice}); err != nil { + t.Fatal(err) + } + + // Clean up global entry of the now missing file + if err := db.checkGlobals([]byte(fs.folder), fs.meta); err != nil { + t.Fatal(err) + } + + // Check that the global entry is gone + gk, err := db.keyer.GenerateGlobalVersionKey(nil, []byte(fs.folder), []byte(name)) + if err != nil { + t.Fatal(err) + } + _, err = db.Get(gk) + if !backend.IsNotFound(err) { + t.Error("Expected key missing error, got", err) + } +} diff --git a/lib/db/lowlevel.go b/lib/db/lowlevel.go index c5eae55a9..1ef27096d 100644 --- a/lib/db/lowlevel.go +++ b/lib/db/lowlevel.go @@ -417,7 +417,11 @@ func (db *Lowlevel) checkGlobals(folder []byte, meta *metadataTracker) error { } } - if len(newVL.Versions) != len(vl.Versions) { + if newLen := len(newVL.Versions); newLen == 0 { + if err := t.Delete(dbi.Key()); err != nil { + return err + } + } else if newLen != len(vl.Versions) { if err := t.Put(dbi.Key(), mustMarshal(&newVL)); err != nil { return err } diff --git a/lib/db/structs.go b/lib/db/structs.go index 009f0a278..af8a629af 100644 --- a/lib/db/structs.go +++ b/lib/db/structs.go @@ -257,14 +257,13 @@ func (vl VersionList) insertAt(i int, v FileVersion) VersionList { // as the removed FileVersion and the position, where that FileVersion was. // If there is no FileVersion for the given device, the position is -1. func (vl VersionList) pop(device []byte) (VersionList, FileVersion, int) { - removedAt := -1 for i, v := range vl.Versions { if bytes.Equal(v.Device, device) { vl.Versions = append(vl.Versions[:i], vl.Versions[i+1:]...) return vl, v, i } } - return vl, FileVersion{}, removedAt + return vl, FileVersion{}, -1 } func (vl VersionList) Get(device []byte) (FileVersion, bool) { diff --git a/lib/db/transactions.go b/lib/db/transactions.go index cac81f5cf..3d205a60e 100644 --- a/lib/db/transactions.go +++ b/lib/db/transactions.go @@ -485,10 +485,6 @@ func (t readWriteTransaction) updateGlobal(gk, keyBuf, folder, device []byte, fi if err != nil { return nil, false, err } - if insertedAt == -1 { - l.Debugln("update global; same version, global unchanged") - return keyBuf, false, nil - } name := []byte(file.Name)