diff --git a/server/db/settings/setting.go b/server/db/settings/setting.go index f6a07d2c3..2e659494c 100644 --- a/server/db/settings/setting.go +++ b/server/db/settings/setting.go @@ -11,11 +11,11 @@ import ( "strconv" "strings" "sync" - "sync/atomic" "time" "github.com/evcc-io/evcc/server/db" "github.com/evcc-io/evcc/util" + "github.com/samber/lo" "go.yaml.in/yaml/v4" ) @@ -23,6 +23,7 @@ var ErrNotFound = errors.New("not found") // setting is a settings entry type setting struct { + dirty bool Key string `json:"key" gorm:"primarykey"` Value string `json:"value"` } @@ -30,7 +31,6 @@ type setting struct { var ( mu sync.RWMutex settings []setting - dirty int32 ) func Init() error { @@ -42,12 +42,22 @@ func Init() error { } func Persist() error { - dirty := atomic.CompareAndSwapInt32(&dirty, 1, 0) - if !dirty || len(settings) == 0 { - // avoid "empty slice found" - return nil + mu.Lock() + defer mu.Unlock() + + if dirty := lo.FilterMap(settings, func(s setting, _ int) (*setting, bool) { + return &s, s.dirty + }); len(dirty) > 0 { + if err := db.Instance.Save(dirty).Error; err != nil { + return err + } + + for _, s := range dirty { + s.dirty = false + } } - return db.Instance.Save(settings).Error + + return nil } func All() []setting { @@ -88,14 +98,11 @@ func SetString(key string, val string) { mu.Lock() defer mu.Unlock() - idx := slices.IndexFunc(settings, equal(key)) - - if idx < 0 { - settings = append(settings, setting{key, val}) - atomic.StoreInt32(&dirty, 1) + if idx := slices.IndexFunc(settings, equal(key)); idx < 0 { + settings = append(settings, setting{true, key, val}) } else if settings[idx].Value != val { + settings[idx].dirty = true settings[idx].Value = val - atomic.StoreInt32(&dirty, 1) } } @@ -170,7 +177,7 @@ func Float(key string) (float64, error) { func Time(key string) (time.Time, error) { s, err := String(key) if err != nil { - return time.Now(), err + return time.Time{}, err } return time.Parse(time.RFC3339, s) }