From ce03b58247053d4c23631e2002d7c1b649471932 Mon Sep 17 00:00:00 2001 From: zijiren233 Date: Thu, 2 Nov 2023 16:29:58 +0800 Subject: [PATCH] Fix: settings data race --- internal/settings/bool.go | 32 +++++++++++++++++++++++--------- internal/settings/floate64.go | 23 +++++++++++++++++------ internal/settings/int64.go | 18 ++++++++++++++---- internal/settings/string.go | 21 ++++++++++++++++++--- 4 files changed, 72 insertions(+), 22 deletions(-) diff --git a/internal/settings/bool.go b/internal/settings/bool.go index 3ff5f5c9..81de6b57 100644 --- a/internal/settings/bool.go +++ b/internal/settings/bool.go @@ -3,6 +3,7 @@ package settings import ( "fmt" "strconv" + "sync/atomic" "github.com/synctv-org/synctv/internal/db" "github.com/synctv-org/synctv/internal/model" @@ -22,7 +23,7 @@ var _ BoolSetting = (*Bool)(nil) type Bool struct { setting defaultValue bool - value bool + value uint32 } func NewBool(name string, value bool, group model.SettingGroup) *Bool { @@ -33,17 +34,29 @@ func NewBool(name string, value bool, group model.SettingGroup) *Bool { settingType: model.SettingTypeBool, }, defaultValue: value, - value: value, } + b.set(value) return b } +func (b *Bool) set(value bool) { + if value { + atomic.StoreUint32(&b.value, 1) + } else { + atomic.StoreUint32(&b.value, 0) + } +} + +func (b *Bool) Get() bool { + return atomic.LoadUint32(&b.value) == 1 +} + func (b *Bool) Init(value string) error { v, err := b.Parse(value) if err != nil { return err } - b.value = v + b.set(v) return nil } @@ -64,7 +77,7 @@ func (b *Bool) DefaultRaw() string { } func (b *Bool) Raw() string { - return b.Stringify(b.value) + return b.Stringify(b.Get()) } func (b *Bool) DefaultInterface() any { @@ -80,11 +93,12 @@ func (b *Bool) SetRaw(value string) error { } func (b *Bool) Set(value bool) error { - return b.SetRaw(b.Stringify(value)) -} - -func (b *Bool) Get() bool { - return b.value + err := db.UpdateSettingItemValue(b.Name(), b.Stringify(value)) + if err != nil { + return err + } + b.set(value) + return nil } func (b *Bool) Interface() any { diff --git a/internal/settings/floate64.go b/internal/settings/floate64.go index ec7804b8..7a0c24cb 100644 --- a/internal/settings/floate64.go +++ b/internal/settings/floate64.go @@ -2,7 +2,9 @@ package settings import ( "fmt" + "math" "strconv" + "sync/atomic" "github.com/synctv-org/synctv/internal/db" "github.com/synctv-org/synctv/internal/model" @@ -22,7 +24,7 @@ var _ Float64Setting = (*Float64)(nil) type Float64 struct { setting defaultValue float64 - value float64 + value uint64 } func NewFloat64(name string, value float64, group model.SettingGroup) *Float64 { @@ -33,8 +35,8 @@ func NewFloat64(name string, value float64, group model.SettingGroup) *Float64 { settingType: model.SettingTypeFloat64, }, defaultValue: value, - value: value, } + f.set(value) return f } @@ -51,12 +53,12 @@ func (f *Float64) Init(value string) error { if err != nil { return err } - f.value = v + f.set(v) return nil } func (f *Float64) Raw() string { - return f.Stringify(f.value) + return f.Stringify(f.Get()) } func (f *Float64) Default() float64 { @@ -79,12 +81,21 @@ func (f *Float64) SetRaw(value string) error { return db.UpdateSettingItemValue(f.Name(), f.Raw()) } +func (f *Float64) set(value float64) { + atomic.StoreUint64(&f.value, math.Float64bits(value)) +} + func (f *Float64) Set(value float64) error { - return f.SetRaw(f.Stringify(value)) + err := db.UpdateSettingItemValue(f.Name(), f.Stringify(value)) + if err != nil { + return err + } + f.set(value) + return nil } func (f *Float64) Get() float64 { - return f.value + return math.Float64frombits(atomic.LoadUint64(&f.value)) } func (f *Float64) Interface() any { diff --git a/internal/settings/int64.go b/internal/settings/int64.go index b19f66a7..bd84f042 100644 --- a/internal/settings/int64.go +++ b/internal/settings/int64.go @@ -3,6 +3,7 @@ package settings import ( "fmt" "strconv" + "sync/atomic" "github.com/synctv-org/synctv/internal/db" "github.com/synctv-org/synctv/internal/model" @@ -50,7 +51,7 @@ func (i *Int64) Init(value string) error { if err != nil { return err } - i.value = v + i.set(v) return nil } @@ -67,7 +68,7 @@ func (i *Int64) DefaultInterface() any { } func (i *Int64) Raw() string { - return i.Stringify(i.value) + return i.Stringify(i.Get()) } func (i *Int64) SetRaw(value string) error { @@ -78,12 +79,21 @@ func (i *Int64) SetRaw(value string) error { return db.UpdateSettingItemValue(i.Name(), i.Raw()) } +func (i *Int64) set(value int64) { + atomic.StoreInt64(&i.value, value) +} + func (i *Int64) Set(value int64) error { - return i.SetRaw(strconv.FormatInt(value, 10)) + err := db.UpdateSettingItemValue(i.Name(), i.Stringify(value)) + if err != nil { + return err + } + i.set(value) + return nil } func (i *Int64) Get() int64 { - return i.value + return atomic.LoadInt64(&i.value) } func (i *Int64) Interface() any { diff --git a/internal/settings/string.go b/internal/settings/string.go index 094be489..93a94761 100644 --- a/internal/settings/string.go +++ b/internal/settings/string.go @@ -2,6 +2,7 @@ package settings import ( "fmt" + "sync" "github.com/synctv-org/synctv/internal/db" "github.com/synctv-org/synctv/internal/model" @@ -21,6 +22,7 @@ var _ StringSetting = (*String)(nil) type String struct { setting defaultValue string + lock sync.RWMutex value string } @@ -50,7 +52,7 @@ func (s *String) Init(value string) error { if err != nil { return err } - s.value = v + s.set(v) return nil } @@ -67,7 +69,7 @@ func (s *String) DefaultInterface() any { } func (s *String) Raw() string { - return s.Stringify(s.value) + return s.Stringify(s.Get()) } func (s *String) SetRaw(value string) error { @@ -78,11 +80,24 @@ func (s *String) SetRaw(value string) error { return db.UpdateSettingItemValue(s.Name(), s.Raw()) } +func (s *String) set(value string) { + s.lock.Lock() + defer s.lock.Unlock() + s.value = value +} + func (s *String) Set(value string) error { - return s.SetRaw(value) + err := db.UpdateSettingItemValue(s.Name(), s.Stringify(value)) + if err != nil { + return err + } + s.set(value) + return nil } func (s *String) Get() string { + s.lock.RLock() + defer s.lock.RUnlock() return s.value }