perf(settings): save all settings in one transaction

UpdateAllSetting issued a separate SELECT plus Save per field in its own
autocommit transaction, so each panel-settings save triggered 100+ SQLite
write transactions (one fsync each). Wrap the whole update in a single
transaction, read existing rows once, and skip unchanged values.
This commit is contained in:
MHSanaei
2026-06-22 22:01:22 +02:00
parent a7e959ff49
commit 20094c8d35
+32 -10
View File
@@ -23,6 +23,8 @@ import (
"github.com/mhsanaei/3x-ui/v3/internal/util/reflect_util" "github.com/mhsanaei/3x-ui/v3/internal/util/reflect_util"
"github.com/mhsanaei/3x-ui/v3/internal/web/entity" "github.com/mhsanaei/3x-ui/v3/internal/web/entity"
"github.com/mhsanaei/3x-ui/v3/internal/xray" "github.com/mhsanaei/3x-ui/v3/internal/xray"
"gorm.io/gorm"
) )
//go:embed config.json //go:embed config.json
@@ -1049,17 +1051,37 @@ func (s *SettingService) UpdateAllSetting(allSetting *entity.AllSetting) error {
v := reflect.ValueOf(allSetting).Elem() v := reflect.ValueOf(allSetting).Elem()
t := reflect.TypeFor[entity.AllSetting]() t := reflect.TypeFor[entity.AllSetting]()
fields := reflect_util.GetFields(t) fields := reflect_util.GetFields(t)
errs := make([]error, 0)
for _, field := range fields { db := database.GetDB()
key := field.Tag.Get("json") return db.Transaction(func(tx *gorm.DB) error {
fieldV := v.FieldByName(field.Name) var existing []*model.Setting
value := fmt.Sprint(fieldV.Interface()) if err := tx.Find(&existing).Error; err != nil {
err := s.saveSetting(key, value) return err
if err != nil {
errs = append(errs, err)
} }
} byKey := make(map[string]*model.Setting, len(existing))
return common.Combine(errs...) for _, st := range existing {
byKey[st.Key] = st
}
for _, field := range fields {
key := field.Tag.Get("json")
fieldV := v.FieldByName(field.Name)
value := fmt.Sprint(fieldV.Interface())
if st, ok := byKey[key]; ok {
if st.Value == value {
continue
}
st.Value = value
if err := tx.Save(st).Error; err != nil {
return err
}
continue
}
if err := tx.Create(&model.Setting{Key: key, Value: value}).Error; err != nil {
return err
}
}
return nil
})
} }
func (s *SettingService) preserveRedactedSecrets(allSetting *entity.AllSetting) error { func (s *SettingService) preserveRedactedSecrets(allSetting *entity.AllSetting) error {