github.com/polarismesh/polaris@v1.17.8/store/mysql/fault_detect_config.go (about)

     1  /**
     2   * Tencent is pleased to support the open source community by making Polaris available.
     3   *
     4   * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
     5   *
     6   * Licensed under the BSD 3-Clause License (the "License");
     7   * you may not use this file except in compliance with the License.
     8   * You may obtain a copy of the License at
     9   *
    10   * https://opensource.org/licenses/BSD-3-Clause
    11   *
    12   * Unless required by applicable law or agreed to in writing, software distributed
    13   * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
    14   * CONDITIONS OF ANY KIND, either express or implied. See the License for the
    15   * specific language governing permissions and limitations under the License.
    16   */
    17  
    18  package sqldb
    19  
    20  import (
    21  	"database/sql"
    22  	"fmt"
    23  	"strings"
    24  	"time"
    25  
    26  	"github.com/polarismesh/polaris/common/model"
    27  	"github.com/polarismesh/polaris/store"
    28  )
    29  
    30  var _ store.FaultDetectRuleStore = (*faultDetectRuleStore)(nil)
    31  
    32  type faultDetectRuleStore struct {
    33  	master *BaseDB
    34  	slave  *BaseDB
    35  }
    36  
    37  const (
    38  	labelCreateFaultDetectRule = "createFaultDetectRule"
    39  	labelUpdateFaultDetectRule = "updateFaultDetectRule"
    40  	labelDeleteFaultDetectRule = "deleteFaultDetectRule"
    41  )
    42  
    43  const (
    44  	insertFaultDetectSql = `insert into fault_detect_rule(
    45  			id, name, namespace, revision, description, dst_service, dst_namespace, dst_method, config, ctime, mtime)
    46  			values(?,?,?,?,?,?,?,?,?, sysdate(),sysdate())`
    47  	updateFaultDetectSql = `update fault_detect_rule set name = ?, namespace = ?, revision = ?, description = ?,
    48  			dst_service = ?, dst_namespace = ?, dst_method = ?, config = ?, mtime = sysdate() where id = ?`
    49  	deleteFaultDetectSql    = `update fault_detect_rule set flag = 1, mtime = sysdate() where id = ?`
    50  	countFaultDetectSql     = `select count(*) from fault_detect_rule where flag = 0`
    51  	queryFaultDetectFullSql = `select id, name, namespace, revision, description, dst_service, 
    52  			dst_namespace, dst_method, config, unix_timestamp(ctime), unix_timestamp(mtime)
    53              from fault_detect_rule where flag = 0`
    54  	queryFaultDetectBriefSql = `select id, name, namespace, revision, description, dst_service, 
    55  			dst_namespace, dst_method, unix_timestamp(ctime), unix_timestamp(mtime)
    56              from fault_detect_rule where flag = 0`
    57  	queryFaultDetectCacheSql = `select id, name, namespace, revision, description, dst_service, 
    58  			dst_namespace, dst_method, config, flag, unix_timestamp(ctime), unix_timestamp(mtime)
    59  			from fault_detect_rule where mtime > FROM_UNIXTIME(?)`
    60  )
    61  
    62  // CreateFaultDetectRule create fault detect rule
    63  func (f *faultDetectRuleStore) CreateFaultDetectRule(fdRule *model.FaultDetectRule) error {
    64  	err := RetryTransaction(labelCreateFaultDetectRule, func() error {
    65  		return f.createFaultDetectRule(fdRule)
    66  	})
    67  	return store.Error(err)
    68  }
    69  
    70  func (f *faultDetectRuleStore) createFaultDetectRule(fdRule *model.FaultDetectRule) error {
    71  	return f.master.processWithTransaction(labelCreateFaultDetectRule, func(tx *BaseTx) error {
    72  		if _, err := tx.Exec(insertFaultDetectSql, fdRule.ID, fdRule.Name, fdRule.Namespace, fdRule.Revision,
    73  			fdRule.Description, fdRule.DstService, fdRule.DstNamespace, fdRule.DstMethod, fdRule.Rule); err != nil {
    74  			log.Errorf("[Store][database] fail to %s exec sql, rule(%+v), err: %s",
    75  				labelCreateFaultDetectRule, fdRule, err.Error())
    76  			return err
    77  		}
    78  
    79  		if err := tx.Commit(); err != nil {
    80  			log.Errorf("[Store][database] fail to %s commit tx, rule(%+v), err: %s",
    81  				labelCreateFaultDetectRule, fdRule, err.Error())
    82  			return err
    83  		}
    84  		return nil
    85  	})
    86  }
    87  
    88  // UpdateFaultDetectRule update fault detect rule
    89  func (f *faultDetectRuleStore) UpdateFaultDetectRule(fdRule *model.FaultDetectRule) error {
    90  	err := RetryTransaction(labelUpdateFaultDetectRule, func() error {
    91  		return f.updateFaultDetectRule(fdRule)
    92  	})
    93  	return store.Error(err)
    94  }
    95  
    96  func (f *faultDetectRuleStore) updateFaultDetectRule(fdRule *model.FaultDetectRule) error {
    97  	return f.master.processWithTransaction(labelUpdateFaultDetectRule, func(tx *BaseTx) error {
    98  		if _, err := tx.Exec(updateFaultDetectSql, fdRule.Name, fdRule.Namespace, fdRule.Revision,
    99  			fdRule.Description, fdRule.DstService, fdRule.DstNamespace, fdRule.DstMethod, fdRule.Rule, fdRule.ID); err != nil {
   100  			log.Errorf("[Store][database] fail to %s exec sql, rule(%+v), err: %s",
   101  				labelUpdateFaultDetectRule, fdRule, err.Error())
   102  			return err
   103  		}
   104  
   105  		if err := tx.Commit(); err != nil {
   106  			log.Errorf("[Store][database] fail to %s commit tx, rule(%+v), err: %s",
   107  				labelUpdateFaultDetectRule, fdRule, err.Error())
   108  			return err
   109  		}
   110  		return nil
   111  	})
   112  }
   113  
   114  // DeleteFaultDetectRule delete fault detect rule
   115  func (f *faultDetectRuleStore) DeleteFaultDetectRule(id string) error {
   116  	err := RetryTransaction(labelDeleteFaultDetectRule, func() error {
   117  		return f.deleteFaultDetectRule(id)
   118  	})
   119  	return store.Error(err)
   120  }
   121  
   122  func (f *faultDetectRuleStore) deleteFaultDetectRule(id string) error {
   123  	return f.master.processWithTransaction(labelDeleteFaultDetectRule, func(tx *BaseTx) error {
   124  		if _, err := tx.Exec(deleteFaultDetectSql, id); err != nil {
   125  			log.Errorf("[Store][database] fail to %s exec sql, rule(%s), err: %s",
   126  				labelDeleteFaultDetectRule, id, err.Error())
   127  			return err
   128  		}
   129  
   130  		if err := tx.Commit(); err != nil {
   131  			log.Errorf("[Store][database] fail to %s commit tx, rule(%s), err: %s",
   132  				labelDeleteFaultDetectRule, id, err.Error())
   133  			return err
   134  		}
   135  		return nil
   136  	})
   137  }
   138  
   139  // HasFaultDetectRule check fault detect rule exists
   140  func (f *faultDetectRuleStore) HasFaultDetectRule(id string) (bool, error) {
   141  	queryParams := map[string]string{"id": id}
   142  	count, err := f.getFaultDetectRulesCount(queryParams)
   143  	if nil != err {
   144  		return false, err
   145  	}
   146  	return count > 0, nil
   147  }
   148  
   149  // HasFaultDetectRuleByName check fault detect rule exists by name
   150  func (f *faultDetectRuleStore) HasFaultDetectRuleByName(name string, namespace string) (bool, error) {
   151  	queryParams := map[string]string{exactName: name, "namespace": namespace}
   152  	count, err := f.getFaultDetectRulesCount(queryParams)
   153  	if nil != err {
   154  		return false, err
   155  	}
   156  	return count > 0, nil
   157  }
   158  
   159  // HasFaultDetectRuleByNameExcludeId check fault detect rule exists by name not this id
   160  func (f *faultDetectRuleStore) HasFaultDetectRuleByNameExcludeId(
   161  	name string, namespace string, id string) (bool, error) {
   162  	queryParams := map[string]string{exactName: name, "namespace": namespace, excludeId: id}
   163  	count, err := f.getFaultDetectRulesCount(queryParams)
   164  	if nil != err {
   165  		return false, err
   166  	}
   167  	return count > 0, nil
   168  }
   169  
   170  // GetFaultDetectRules get all fault detect rules by query and limit
   171  func (f *faultDetectRuleStore) GetFaultDetectRules(
   172  	filter map[string]string, offset uint32, limit uint32) (uint32, []*model.FaultDetectRule, error) {
   173  	var out []*model.FaultDetectRule
   174  	var err error
   175  
   176  	bValue, ok := filter[briefSearch]
   177  	var isBrief = ok && strings.ToLower(bValue) == "true"
   178  	delete(filter, briefSearch)
   179  
   180  	if isBrief {
   181  		out, err = f.getBriefFaultDetectRules(filter, offset, limit)
   182  	} else {
   183  		out, err = f.getFullFaultDetectRules(filter, offset, limit)
   184  	}
   185  	if err != nil {
   186  		return 0, nil, err
   187  	}
   188  	num, err := f.getFaultDetectRulesCount(filter)
   189  	if err != nil {
   190  		return 0, nil, err
   191  	}
   192  	return num, out, nil
   193  }
   194  
   195  // GetFaultDetectRulesForCache get increment circuitbreaker rules
   196  func (f *faultDetectRuleStore) GetFaultDetectRulesForCache(
   197  	mtime time.Time, firstUpdate bool) ([]*model.FaultDetectRule, error) {
   198  	str := queryFaultDetectCacheSql
   199  	if firstUpdate {
   200  		str += " and flag != 1"
   201  	}
   202  	rows, err := f.slave.Query(str, timeToTimestamp(mtime))
   203  	if err != nil {
   204  		log.Errorf("[Store][database] query fault detect rules with mtime err: %s", err.Error())
   205  		return nil, err
   206  	}
   207  	fdRules, err := fetchFaultDetectRulesRows(rows)
   208  	if err != nil {
   209  		return nil, err
   210  	}
   211  	return fdRules, nil
   212  }
   213  
   214  func fetchFaultDetectRulesRows(rows *sql.Rows) ([]*model.FaultDetectRule, error) {
   215  	defer rows.Close()
   216  	var out []*model.FaultDetectRule
   217  	for rows.Next() {
   218  		var fdRule model.FaultDetectRule
   219  		var flag int
   220  		var ctime, mtime int64
   221  		err := rows.Scan(&fdRule.ID, &fdRule.Name, &fdRule.Namespace, &fdRule.Revision,
   222  			&fdRule.Description, &fdRule.DstService, &fdRule.DstNamespace,
   223  			&fdRule.DstMethod, &fdRule.Rule, &flag, &ctime, &mtime)
   224  		if err != nil {
   225  			log.Errorf("[Store][database] fetch brief fault detect rule scan err: %s", err.Error())
   226  			return nil, err
   227  		}
   228  		fdRule.CreateTime = time.Unix(ctime, 0)
   229  		fdRule.ModifyTime = time.Unix(mtime, 0)
   230  		fdRule.Valid = true
   231  		if flag == 1 {
   232  			fdRule.Valid = false
   233  		}
   234  		out = append(out, &fdRule)
   235  	}
   236  	if err := rows.Err(); err != nil {
   237  		log.Errorf("[Store][database] fetch brief fault detect rule next err: %s", err.Error())
   238  		return nil, err
   239  	}
   240  	return out, nil
   241  }
   242  
   243  func genFaultDetectRuleSQL(query map[string]string) (string, []interface{}) {
   244  	str := ""
   245  	args := make([]interface{}, 0, len(query))
   246  	var svcNamespaceQueryValue string
   247  	var svcQueryValue string
   248  	for key, value := range query {
   249  		if len(value) == 0 {
   250  			continue
   251  		}
   252  		if key == svcSpecificQueryKeyService {
   253  			svcQueryValue = value
   254  			continue
   255  		}
   256  		if key == svcSpecificQueryKeyNamespace {
   257  			svcNamespaceQueryValue = value
   258  			continue
   259  		}
   260  		storeKey := toUnderscoreName(key)
   261  		if _, ok := blurQueryKeys[key]; ok {
   262  			str += fmt.Sprintf(" and %s like ?", storeKey)
   263  			args = append(args, "%"+value+"%")
   264  		} else if key == exactName {
   265  			str += " and name = ?"
   266  			args = append(args, value)
   267  		} else if key == excludeId {
   268  			str += " and id != ?"
   269  			args = append(args, value)
   270  		} else {
   271  			str += fmt.Sprintf(" and %s = ?", storeKey)
   272  			args = append(args, value)
   273  		}
   274  	}
   275  	if len(svcQueryValue) > 0 {
   276  		str += " and (dst_service = ? or dst_service = '*')"
   277  		args = append(args, svcQueryValue)
   278  	}
   279  	if len(svcNamespaceQueryValue) > 0 {
   280  		str += " and (dst_namespace = ? or dst_namespace = '*')"
   281  		args = append(args, svcNamespaceQueryValue)
   282  	}
   283  	return str, args
   284  }
   285  
   286  func (f *faultDetectRuleStore) getFaultDetectRulesCount(filter map[string]string) (uint32, error) {
   287  	queryStr, args := genFaultDetectRuleSQL(filter)
   288  	str := countFaultDetectSql + queryStr
   289  	var total uint32
   290  	err := f.master.QueryRow(str, args...).Scan(&total)
   291  	switch {
   292  	case err == sql.ErrNoRows:
   293  		return 0, nil
   294  	case err != nil:
   295  		log.Errorf("[Store][database] get fault detect rule count err: %s", err.Error())
   296  		return 0, err
   297  	default:
   298  	}
   299  	return total, nil
   300  }
   301  
   302  func (f *faultDetectRuleStore) getBriefFaultDetectRules(
   303  	filter map[string]string, offset uint32, limit uint32) ([]*model.FaultDetectRule, error) {
   304  	queryStr, args := genFaultDetectRuleSQL(filter)
   305  	args = append(args, offset, limit)
   306  	str := queryFaultDetectBriefSql + queryStr + ` order by mtime desc limit ?, ?`
   307  
   308  	rows, err := f.master.Query(str, args...)
   309  	if err != nil {
   310  		log.Errorf("[Store][database] query brief fault detect rule rules err: %s", err.Error())
   311  		return nil, err
   312  	}
   313  	out, err := fetchBriefFaultDetectRules(rows)
   314  	if err != nil {
   315  		return nil, err
   316  	}
   317  	return out, nil
   318  }
   319  
   320  func fetchBriefFaultDetectRules(rows *sql.Rows) ([]*model.FaultDetectRule, error) {
   321  	defer rows.Close()
   322  	var out []*model.FaultDetectRule
   323  	for rows.Next() {
   324  		var fdRule model.FaultDetectRule
   325  		var ctime, mtime int64
   326  		err := rows.Scan(&fdRule.ID, &fdRule.Name, &fdRule.Namespace, &fdRule.Revision,
   327  			&fdRule.Description, &fdRule.DstService, &fdRule.DstNamespace,
   328  			&fdRule.DstMethod, &ctime, &mtime)
   329  		if err != nil {
   330  			log.Errorf("[Store][database] fetch brief fault detect rule scan err: %s", err.Error())
   331  			return nil, err
   332  		}
   333  		fdRule.CreateTime = time.Unix(ctime, 0)
   334  		fdRule.ModifyTime = time.Unix(mtime, 0)
   335  		out = append(out, &fdRule)
   336  	}
   337  	if err := rows.Err(); err != nil {
   338  		log.Errorf("[Store][database] fetch brief fault detect rule next err: %s", err.Error())
   339  		return nil, err
   340  	}
   341  	return out, nil
   342  }
   343  
   344  func (f *faultDetectRuleStore) getFullFaultDetectRules(
   345  	filter map[string]string, offset uint32, limit uint32) ([]*model.FaultDetectRule, error) {
   346  	queryStr, args := genFaultDetectRuleSQL(filter)
   347  	args = append(args, offset, limit)
   348  	str := queryFaultDetectFullSql + queryStr + ` order by mtime desc limit ?, ?`
   349  
   350  	rows, err := f.master.Query(str, args...)
   351  	if err != nil {
   352  		log.Errorf("[Store][database] query brief fault detect rules err: %s", err.Error())
   353  		return nil, err
   354  	}
   355  	out, err := fetchFullFaultDetectRules(rows)
   356  	if err != nil {
   357  		return nil, err
   358  	}
   359  	return out, nil
   360  }
   361  
   362  func fetchFullFaultDetectRules(rows *sql.Rows) ([]*model.FaultDetectRule, error) {
   363  	defer rows.Close()
   364  	var out []*model.FaultDetectRule
   365  	for rows.Next() {
   366  		var fdRule model.FaultDetectRule
   367  		var ctime, mtime int64
   368  		err := rows.Scan(&fdRule.ID, &fdRule.Name, &fdRule.Namespace, &fdRule.Revision,
   369  			&fdRule.Description, &fdRule.DstService, &fdRule.DstNamespace,
   370  			&fdRule.DstMethod, &fdRule.Rule, &ctime, &mtime)
   371  		if err != nil {
   372  			log.Errorf("[Store][database] fetch brief fault detect rule scan err: %s", err.Error())
   373  			return nil, err
   374  		}
   375  		fdRule.CreateTime = time.Unix(ctime, 0)
   376  		fdRule.ModifyTime = time.Unix(mtime, 0)
   377  		out = append(out, &fdRule)
   378  	}
   379  	if err := rows.Err(); err != nil {
   380  		log.Errorf("[Store][database] fetch brief fault detect rule next err: %s", err.Error())
   381  		return nil, err
   382  	}
   383  	return out, nil
   384  }