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 }