Procházet zdrojové kódy

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.
MHSanaei před 18 hodinami
rodič
revize
20094c8d35
1 změnil soubory, kde provedl 32 přidání a 10 odebrání
  1. 32 10
      internal/web/service/setting.go

+ 32 - 10
internal/web/service/setting.go

@@ -23,6 +23,8 @@ import (
 	"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/xray"
+
+	"gorm.io/gorm"
 )
 
 //go:embed config.json
@@ -1049,17 +1051,37 @@ func (s *SettingService) UpdateAllSetting(allSetting *entity.AllSetting) error {
 	v := reflect.ValueOf(allSetting).Elem()
 	t := reflect.TypeFor[entity.AllSetting]()
 	fields := reflect_util.GetFields(t)
-	errs := make([]error, 0)
-	for _, field := range fields {
-		key := field.Tag.Get("json")
-		fieldV := v.FieldByName(field.Name)
-		value := fmt.Sprint(fieldV.Interface())
-		err := s.saveSetting(key, value)
-		if err != nil {
-			errs = append(errs, err)
+
+	db := database.GetDB()
+	return db.Transaction(func(tx *gorm.DB) error {
+		var existing []*model.Setting
+		if err := tx.Find(&existing).Error; err != nil {
+			return err
 		}
-	}
-	return common.Combine(errs...)
+		byKey := make(map[string]*model.Setting, len(existing))
+		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 {