From d1e0a38c0411ba95cafce8eb9989b46d69c3ce14 Mon Sep 17 00:00:00 2001 From: Evgeny Kuznetsov Date: Fri, 28 Feb 2020 22:40:14 +0300 Subject: [PATCH 1/2] build: Fix syso creation (fixes #6386) (#6387) --- build.go | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/build.go b/build.go index a3f64d5f2..45b8c704d 100644 --- a/build.go +++ b/build.go @@ -654,7 +654,11 @@ func shouldBuildSyso(dir string) (string, error) { } jsonPath := filepath.Join(dir, "versioninfo.json") - ioutil.WriteFile(jsonPath, bs, 0644) + err = ioutil.WriteFile(jsonPath, bs, 0644) + if err != nil { + return "", errors.New("failed to create " + jsonPath + ": " + err.Error()) + } + defer func() { if err := os.Remove(jsonPath); err != nil { log.Printf("Warning: unable to remove generated %s: %v. Please remove it manually.", jsonPath, err) @@ -860,13 +864,22 @@ func getVersion() string { return "unknown-dev" } -func semanticVersion() (major, minor, patch, build string) { +func semanticVersion() (major, minor, patch, build int) { r := regexp.MustCompile(`v(?P\d+)\.(?P\d+).(?P\d+).*\+(?P\d+)`) matches := r.FindStringSubmatch(getVersion()) if len(matches) != 5 { - return "0", "0", "0", "0" + return 0, 0, 0, 0 } - return matches[1], matches[2], matches[3], matches[4] + + var ints [4]int + for i := 1; i < 5; i++ { + value, err := strconv.Atoi(matches[i]) + if err != nil { + return 0, 0, 0, 0 + } + ints[i-1] = value + } + return ints[0], ints[1], ints[2], ints[3] } func getBranchSuffix() string { From 52e72e01222df8be766a3b76516a7cfa23b4ed97 Mon Sep 17 00:00:00 2001 From: Jakob Borg Date: Sat, 29 Feb 2020 19:51:32 +0100 Subject: [PATCH 2/2] lib/db: Prevent GC concurrently with migration (fixes #6389) (#6390) --- lib/db/lowlevel.go | 18 +++++++++++++++--- lib/db/schemaupdater.go | 5 +++++ 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/lib/db/lowlevel.go b/lib/db/lowlevel.go index a3ebd3cb6..2b315d56f 100644 --- a/lib/db/lowlevel.go +++ b/lib/db/lowlevel.go @@ -488,8 +488,18 @@ func (db *Lowlevel) dropPrefix(prefix []byte) error { } func (db *Lowlevel) gcRunner() { - t := time.NewTimer(db.timeUntil(indirectGCTimeKey, indirectGCInterval)) + // Calculate the time for the next GC run. Even if we should run GC + // directly, give the system a while to get up and running and do other + // stuff first. (We might have migrations and stuff which would be + // better off running before GC.) + next := db.timeUntil(indirectGCTimeKey, indirectGCInterval) + if next < time.Minute { + next = time.Minute + } + + t := time.NewTimer(next) defer t.Stop() + for { select { case <-db.gcStop: @@ -558,10 +568,11 @@ func (db *Lowlevel) gcIndirect() error { // Iterate the FileInfos, unmarshal the block and version hashes and // add them to the filter. - it, err := db.NewPrefixIterator([]byte{KeyTypeDevice}) + it, err := t.NewPrefixIterator([]byte{KeyTypeDevice}) if err != nil { return err } + defer it.Release() for it.Next() { var bl BlocksHashOnly if err := bl.Unmarshal(it.Value()); err != nil { @@ -579,10 +590,11 @@ func (db *Lowlevel) gcIndirect() error { // Iterate over block lists, removing keys with hashes that don't match // the filter. - it, err = db.NewPrefixIterator([]byte{KeyTypeBlockList}) + it, err = t.NewPrefixIterator([]byte{KeyTypeBlockList}) if err != nil { return err } + defer it.Release() matchedBlocks := 0 for it.Next() { key := blockListKey(it.Key()) diff --git a/lib/db/schemaupdater.go b/lib/db/schemaupdater.go index 0486adfdc..7dd454d29 100644 --- a/lib/db/schemaupdater.go +++ b/lib/db/schemaupdater.go @@ -57,6 +57,11 @@ type schemaUpdater struct { } func (db *schemaUpdater) updateSchema() error { + // Updating the schema can touch any and all parts of the database. Make + // sure we do not run GC concurrently with schema migrations. + db.gcMut.Lock() + defer db.gcMut.Unlock() + miscDB := NewMiscDataNamespace(db.Lowlevel) prevVersion, _, err := miscDB.Int64("dbVersion") if err != nil {