github.com/polarismesh/polaris@v1.17.8/store/mysql/routing_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  	"errors"
    23  	"fmt"
    24  	"time"
    25  
    26  	"github.com/polarismesh/polaris/common/model"
    27  	"github.com/polarismesh/polaris/store"
    28  )
    29  
    30  // RoutingConfigStore的实现
    31  type routingConfigStore struct {
    32  	master *BaseDB
    33  	slave  *BaseDB
    34  }
    35  
    36  // CreateRoutingConfig 新建RoutingConfig
    37  func (rs *routingConfigStore) CreateRoutingConfig(conf *model.RoutingConfig) error {
    38  	if conf.ID == "" || conf.Revision == "" {
    39  		log.Errorf("[Store][database] create routing config missing service id or revision")
    40  		return store.NewStatusError(store.EmptyParamsErr, "missing service id or revision")
    41  	}
    42  	if conf.InBounds == "" || conf.OutBounds == "" {
    43  		log.Errorf("[Store][database] create routing config missing params")
    44  		return store.NewStatusError(store.EmptyParamsErr, "missing some params")
    45  	}
    46  
    47  	return RetryTransaction("createRoutingConfig", func() error {
    48  		return rs.master.processWithTransaction("createRoutingConfig", func(tx *BaseTx) error {
    49  			// 新建之前,先清理老数据
    50  			if err := cleanRoutingConfig(tx, conf.ID); err != nil {
    51  				return store.Error(err)
    52  			}
    53  
    54  			// 服务配置的创建由外层进行服务的保护,这里不需要加锁
    55  			str := `insert into routing_config(id, in_bounds, out_bounds, revision, ctime, mtime)
    56  			values(?,?,?,?,sysdate(),sysdate())`
    57  			if _, err := tx.Exec(str, conf.ID, conf.InBounds, conf.OutBounds, conf.Revision); err != nil {
    58  				log.Errorf("[Store][database] create routing(%+v) err: %s", conf, err.Error())
    59  				return store.Error(err)
    60  			}
    61  
    62  			if err := tx.Commit(); err != nil {
    63  				log.Errorf("[Store][database] fail to create routing commit tx, rule(%+v) commit tx err: %s",
    64  					conf, err.Error())
    65  				return err
    66  			}
    67  			return nil
    68  		})
    69  	})
    70  }
    71  
    72  // UpdateRoutingConfig 更新
    73  func (rs *routingConfigStore) UpdateRoutingConfig(conf *model.RoutingConfig) error {
    74  	if conf.ID == "" || conf.Revision == "" {
    75  		log.Errorf("[Store][database] update routing config missing service id or revision")
    76  		return store.NewStatusError(store.EmptyParamsErr, "missing service id or revision")
    77  	}
    78  	if conf.InBounds == "" || conf.OutBounds == "" {
    79  		log.Errorf("[Store][database] update routing config missing params")
    80  		return store.NewStatusError(store.EmptyParamsErr, "missing some params")
    81  	}
    82  	return RetryTransaction("updateRoutingConfig", func() error {
    83  		return rs.master.processWithTransaction("updateRoutingConfig", func(tx *BaseTx) error {
    84  			str := `update routing_config set in_bounds = ?, out_bounds = ?, revision = ?, mtime = sysdate() where id = ?`
    85  			if _, err := tx.Exec(str, conf.InBounds, conf.OutBounds, conf.Revision, conf.ID); err != nil {
    86  				log.Errorf("[Store][database] update routing config(%+v) exec err: %s", conf, err.Error())
    87  				return store.Error(err)
    88  			}
    89  
    90  			if err := tx.Commit(); err != nil {
    91  				log.Errorf("[Store][database] fail to update routing commit tx, rule(%+v) commit tx err: %s",
    92  					conf, err.Error())
    93  				return err
    94  			}
    95  			return nil
    96  		})
    97  	})
    98  }
    99  
   100  // DeleteRoutingConfig 删除
   101  func (rs *routingConfigStore) DeleteRoutingConfig(serviceID string) error {
   102  	if serviceID == "" {
   103  		log.Errorf("[Store][database] delete routing config missing service id")
   104  		return store.NewStatusError(store.EmptyParamsErr, "missing service id")
   105  	}
   106  	return RetryTransaction("deleteRoutingConfig", func() error {
   107  		return rs.master.processWithTransaction("deleteRoutingConfig", func(tx *BaseTx) error {
   108  			str := `update routing_config set flag = 1, mtime = sysdate() where id = ?`
   109  			if _, err := tx.Exec(str, serviceID); err != nil {
   110  				log.Errorf("[Store][database] delete routing config(%s) err: %s", serviceID, err.Error())
   111  				return store.Error(err)
   112  			}
   113  
   114  			if err := tx.Commit(); err != nil {
   115  				log.Errorf("[Store][database] fail to delete routing commit tx, rule(%s) commit tx err: %s",
   116  					serviceID, err.Error())
   117  				return err
   118  			}
   119  			return nil
   120  		})
   121  	})
   122  }
   123  
   124  // DeleteRoutingConfigTx 删除
   125  func (rs *routingConfigStore) DeleteRoutingConfigTx(tx store.Tx, serviceID string) error {
   126  	if tx == nil {
   127  		return errors.New("transaction is nil")
   128  	}
   129  
   130  	if serviceID == "" {
   131  		log.Errorf("[Store][database] delete routing config missing service id")
   132  		return store.NewStatusError(store.EmptyParamsErr, "missing service id")
   133  	}
   134  
   135  	dbTx := tx.GetDelegateTx().(*BaseTx)
   136  
   137  	str := `update routing_config set flag = 1, mtime = sysdate() where id = ?`
   138  	if _, err := dbTx.Exec(str, serviceID); err != nil {
   139  		log.Errorf("[Store][database] delete routing config(%s) err: %s", serviceID, err.Error())
   140  		return store.Error(err)
   141  	}
   142  	return nil
   143  }
   144  
   145  // GetRoutingConfigsForCache 缓存增量拉取
   146  func (rs *routingConfigStore) GetRoutingConfigsForCache(
   147  	mtime time.Time, firstUpdate bool) ([]*model.RoutingConfig, error) {
   148  	str := `select id, in_bounds, out_bounds, revision,
   149  			flag, unix_timestamp(ctime), unix_timestamp(mtime)  
   150  			from routing_config where mtime > FROM_UNIXTIME(?)`
   151  	if firstUpdate {
   152  		str += " and flag != 1"
   153  	}
   154  	rows, err := rs.slave.Query(str, timeToTimestamp(mtime))
   155  	if err != nil {
   156  		log.Errorf("[Store][database] query routing configs with mtime err: %s", err.Error())
   157  		return nil, err
   158  	}
   159  	out, err := fetchRoutingConfigRows(rows)
   160  	if err != nil {
   161  		return nil, err
   162  	}
   163  
   164  	return out, nil
   165  }
   166  
   167  // GetRoutingConfigWithService 根据服务名+namespace获取对应的配置
   168  func (rs *routingConfigStore) GetRoutingConfigWithService(
   169  	name string, namespace string) (*model.RoutingConfig, error) {
   170  	// 只查询到flag=0的数据
   171  	str := `select routing_config.id, in_bounds, out_bounds, revision, flag,
   172  			unix_timestamp(ctime), unix_timestamp(mtime)  
   173  			from (select id from service where name = ? and namespace = ?) as service, routing_config 
   174  			where service.id = routing_config.id and routing_config.flag = 0`
   175  	rows, err := rs.master.Query(str, name, namespace)
   176  	if err != nil {
   177  		log.Errorf("[Store][database] query routing config with service(%s, %s) err: %s",
   178  			name, namespace, err.Error())
   179  		return nil, err
   180  	}
   181  
   182  	out, err := fetchRoutingConfigRows(rows)
   183  	if err != nil {
   184  		return nil, err
   185  	}
   186  
   187  	if len(out) == 0 {
   188  		return nil, nil
   189  	}
   190  
   191  	return out[0], nil
   192  }
   193  
   194  // GetRoutingConfigWithID 根据服务ID获取对应的配置
   195  func (rs *routingConfigStore) GetRoutingConfigWithID(id string) (*model.RoutingConfig, error) {
   196  	str := `select routing_config.id, in_bounds, out_bounds, revision, flag,
   197  			unix_timestamp(ctime), unix_timestamp(mtime)
   198  			from routing_config 
   199  			where id = ? and flag = 0`
   200  	rows, err := rs.master.Query(str, id)
   201  	if err != nil {
   202  		log.Errorf("[Store][database] query routing with id(%s) err: %s", id, err.Error())
   203  		return nil, err
   204  	}
   205  
   206  	out, err := fetchRoutingConfigRows(rows)
   207  	if err != nil {
   208  		return nil, err
   209  	}
   210  
   211  	if len(out) == 0 {
   212  		return nil, nil
   213  	}
   214  
   215  	return out[0], nil
   216  }
   217  
   218  // GetRoutingConfigs 获取路由配置列表
   219  func (rs *routingConfigStore) GetRoutingConfigs(filter map[string]string,
   220  	offset uint32, limit uint32) (uint32, []*model.ExtendRoutingConfig, error) {
   221  
   222  	filterStr, args := genFilterRoutingConfigSQL(filter)
   223  	countStr := genQueryRoutingConfigCountSQL() + filterStr
   224  	var total uint32
   225  	err := rs.master.QueryRow(countStr, args...).Scan(&total)
   226  	switch {
   227  	case err == sql.ErrNoRows:
   228  		return 0, nil, nil
   229  	case err != nil:
   230  		log.Errorf("[Store][database] get routing config query count err: %s", err.Error())
   231  		return 0, nil, err
   232  	default:
   233  	}
   234  
   235  	str := genQueryRoutingConfigSQL() + filterStr + " order by routing_config.mtime desc limit ?, ?"
   236  	args = append(args, offset, limit)
   237  	rows, err := rs.master.Query(str, args...)
   238  	if err != nil {
   239  		log.Errorf("[Store][database] get routing configs query err: %s", err.Error())
   240  		return 0, nil, err
   241  	}
   242  	defer rows.Close()
   243  
   244  	var out []*model.ExtendRoutingConfig
   245  	for rows.Next() {
   246  		var tmp model.ExtendRoutingConfig
   247  		tmp.Config = &model.RoutingConfig{}
   248  		var ctime, mtime int64
   249  		err := rows.Scan(&tmp.ServiceName, &tmp.NamespaceName, &tmp.Config.ID,
   250  			&tmp.Config.InBounds, &tmp.Config.OutBounds, &ctime, &mtime)
   251  		if err != nil {
   252  			log.Errorf("[Store][database] query routing configs rows scan err: %s", err.Error())
   253  			return 0, nil, err
   254  		}
   255  
   256  		tmp.Config.CreateTime = time.Unix(ctime, 0)
   257  		tmp.Config.ModifyTime = time.Unix(mtime, 0)
   258  
   259  		out = append(out, &tmp)
   260  	}
   261  	if err := rows.Err(); err != nil {
   262  		log.Errorf("[Store][database] query routing configs rows next err: %s", err.Error())
   263  		return 0, nil, err
   264  	}
   265  
   266  	return total, out, nil
   267  }
   268  
   269  // cleanRoutingConfig 从数据库彻底清理路由配置
   270  func cleanRoutingConfig(tx *BaseTx, serviceID string) error {
   271  	str := `delete from routing_config where id = ? and flag = 1`
   272  	if _, err := tx.Exec(str, serviceID); err != nil {
   273  		log.Errorf("[Store][database] clean routing config(%s) err: %s", serviceID, err.Error())
   274  		return err
   275  	}
   276  
   277  	return nil
   278  }
   279  
   280  // fetchRoutingConfigRows 读取数据库的数据,并且释放rows
   281  func fetchRoutingConfigRows(rows *sql.Rows) ([]*model.RoutingConfig, error) {
   282  	defer rows.Close()
   283  	var out []*model.RoutingConfig
   284  	for rows.Next() {
   285  		var entry model.RoutingConfig
   286  		var flag int
   287  		var ctime, mtime int64
   288  		err := rows.Scan(&entry.ID, &entry.InBounds, &entry.OutBounds, &entry.Revision,
   289  			&flag, &ctime, &mtime)
   290  		if err != nil {
   291  			log.Errorf("[database][store] fetch routing config scan err: %s", err.Error())
   292  			return nil, err
   293  		}
   294  
   295  		entry.CreateTime = time.Unix(ctime, 0)
   296  		entry.ModifyTime = time.Unix(mtime, 0)
   297  		entry.Valid = true
   298  		if flag == 1 {
   299  			entry.Valid = false
   300  		}
   301  
   302  		out = append(out, &entry)
   303  	}
   304  	if err := rows.Err(); err != nil {
   305  		log.Errorf("[database][store] fetch routing config next err: %s", err.Error())
   306  		return nil, err
   307  	}
   308  
   309  	return out, nil
   310  }
   311  
   312  // genQueryRoutingConfigSQL 查询路由配置的语句
   313  func genQueryRoutingConfigSQL() string {
   314  	str := `select name, namespace, routing_config.id, in_bounds, out_bounds,
   315  			unix_timestamp(routing_config.ctime), unix_timestamp(routing_config.mtime)  
   316  			from routing_config, service 
   317  			where routing_config.id = service.id 
   318  			and routing_config.flag = 0`
   319  	return str
   320  }
   321  
   322  // genQueryRoutingConfigCountSQL 获取路由配置指定过滤条件下的总条目数
   323  func genQueryRoutingConfigCountSQL() string {
   324  	str := `select count(*) from routing_config, service
   325  			where routing_config.id = service.id 
   326  			and routing_config.flag = 0`
   327  	return str
   328  }
   329  
   330  // genFilterRoutingConfigSQL 生成过滤语句
   331  func genFilterRoutingConfigSQL(filters map[string]string) (string, []interface{}) {
   332  	str := ""
   333  	args := make([]interface{}, 0, len(filters))
   334  	for key, value := range filters {
   335  		str += fmt.Sprintf(" and %s = ? ", key)
   336  		args = append(args, value)
   337  	}
   338  
   339  	return str, args
   340  }