github.com/polarismesh/polaris@v1.17.8/store/mysql/transaction.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 "crypto/rand" 22 "math/big" 23 24 "github.com/pkg/errors" 25 26 "github.com/polarismesh/polaris/common/model" 27 ) 28 29 // transaction 事务; 不支持多协程并发操作,当前先支持单个协程串行操作 30 type transaction struct { 31 tx *BaseTx 32 failed bool // 判断事务执行是否失败 33 commit bool // 判断事务已经提交,如果已经提交,则Commit会立即返回 34 } 35 36 // Commit 提交事务,释放tx 37 func (t *transaction) Commit() error { 38 if t.commit { 39 return nil 40 } 41 42 t.commit = true 43 if t.failed { 44 return t.tx.Rollback() 45 } 46 47 return t.tx.Commit() 48 } 49 50 // LockBootstrap 启动锁,限制Server启动的并发数 51 func (t *transaction) LockBootstrap(key string, server string) error { 52 countStr := "select count(*) from start_lock where lock_key = ?" 53 var count int 54 if err := t.tx.QueryRow(countStr, key).Scan(&count); err != nil { 55 log.Errorf("[Store][database] lock bootstrap scan count err: %s", err.Error()) 56 t.failed = true 57 return err 58 } 59 60 bid, err := rand.Int(rand.Reader, big.NewInt(1024)) 61 if err != nil { 62 log.Errorf("[Store][database] rand int err: %s", err.Error()) 63 return err 64 } 65 66 log.Infof("[Store][database] get rand int: %d", bid.Int64()) 67 id := int(bid.Int64())%count + 1 68 // innodb_lock_wait_timeout这个global变量表示锁超时的时间,cdb为7200秒 69 log.Infof("[Store][database] update start lock_id: %d, lock_key: %s, lock server: %s", id, key, server) 70 lockStr := "update start_lock set server = ? where lock_id = ? and lock_key = ?" 71 if _, err := t.tx.Exec(lockStr, server, id, key); err != nil { 72 log.Errorf("[Store][database] update start lock err: %s", err.Error()) 73 t.failed = true 74 return err 75 } 76 77 return nil 78 } 79 80 // LockNamespace 排它锁,锁住指定命名空间 81 func (t *transaction) LockNamespace(name string) (*model.Namespace, error) { 82 str := genNamespaceSelectSQL() + " where name = ? and flag != 1 for update" 83 return t.getValidNamespace(str, name) 84 } 85 86 // RLockNamespace 共享锁,锁住命名空间 87 func (t *transaction) RLockNamespace(name string) (*model.Namespace, error) { 88 str := genNamespaceSelectSQL() + " where name = ? and flag != 1 lock in share mode" 89 return t.getValidNamespace(str, name) 90 } 91 92 // DeleteNamespace 删除命名空间,并且提交事务 93 func (t *transaction) DeleteNamespace(name string) error { 94 if err := t.finish(); err != nil { 95 return err 96 } 97 98 str := "update namespace set flag = 1, mtime = sysdate() where name = ?" 99 if _, err := t.tx.Exec(str, name); err != nil { 100 t.failed = true 101 } 102 103 return t.Commit() 104 } 105 106 // LockService 排它锁,锁住指定服务 107 func (t *transaction) LockService(name string, namespace string) (*model.Service, error) { 108 str := genServiceSelectSQL() + 109 " from service where name = ? and namespace = ? and flag !=1 for update" 110 return t.getValidService(str, name, namespace) 111 } 112 113 // RLockService 共享锁,锁住指定服务 114 func (t *transaction) RLockService(name string, namespace string) (*model.Service, error) { 115 str := genServiceSelectSQL() + 116 " from service where name = ? and namespace = ? and flag !=1 lock in share mode" 117 return t.getValidService(str, name, namespace) 118 } 119 120 // BatchRLockServices 批量锁住服务 121 func (t *transaction) BatchRLockServices(ids map[string]bool) (map[string]bool, error) { 122 str := "select id, flag from service where id in ( " 123 first := true 124 args := make([]interface{}, 0, len(ids)) 125 for id := range ids { 126 if first { 127 str += "?" 128 first = false 129 } else { 130 str += ", ?" 131 } 132 args = append(args, id) 133 } 134 str += ") and flag != 1 lock in share mode" 135 log.Infof("[Store][database] RLock services: %+v", args) 136 rows, err := t.tx.Query(str, args...) 137 if err != nil { 138 log.Errorf("[Store][database] batch RLock services err: %s", err.Error()) 139 return nil, err 140 } 141 defer rows.Close() 142 143 out := make(map[string]bool) 144 var flag int 145 var id string 146 for rows.Next() { 147 if err := rows.Scan(&id, &flag); err != nil { 148 log.Errorf("[Store][database] RLock services scan err: %s", err.Error()) 149 return nil, err 150 } 151 152 if flag == 0 { 153 out[id] = true 154 } else { 155 out[id] = false 156 } 157 } 158 if err := rows.Err(); err != nil { 159 log.Errorf("[Store][database] RLock service rows next err: %s", err.Error()) 160 return nil, err 161 } 162 163 return out, nil 164 } 165 166 // DeleteService 删除服务,并且提交事务 167 func (t *transaction) DeleteService(name string, namespace string) error { 168 if err := t.finish(); err != nil { 169 return err 170 } 171 172 str := "update service set flag = 1, mtime = sysdate() where name = ? and namespace = ?" 173 if _, err := t.tx.Exec(str, name, namespace); err != nil { 174 log.Errorf("[Store][database] delete service err: %s", err.Error()) 175 t.failed = true 176 return err 177 } 178 179 return nil 180 } 181 182 // DeleteAliasWithSourceID 根据源服务的ID,删除其所有的别名 183 func (t *transaction) DeleteAliasWithSourceID(sourceServiceID string) error { 184 if err := t.finish(); err != nil { 185 return err 186 } 187 188 str := `update service set flag = 1, mtime = sysdate() where reference = ?` 189 if _, err := t.tx.Exec(str, sourceServiceID); err != nil { 190 log.Errorf("[Store][database] delete service alias err: %s", err.Error()) 191 t.failed = false 192 return err 193 } 194 195 return nil 196 } 197 198 // finish 判断事务是否已经提交 199 func (t *transaction) finish() error { 200 if t.failed || t.commit { 201 return errors.New("transaction has failed") 202 } 203 204 return nil 205 } 206 207 // getValidNamespace 获取有效的命名空间数据 208 func (t *transaction) getValidNamespace(sql string, name string) (*model.Namespace, error) { 209 if err := t.finish(); err != nil { 210 return nil, err 211 } 212 213 rows, err := t.tx.Query(sql, name) 214 if err != nil { 215 t.failed = true 216 return nil, err 217 } 218 219 out, err := namespaceFetchRows(rows) 220 if err != nil { 221 t.failed = true 222 return nil, err 223 } 224 225 if len(out) == 0 { 226 return nil, nil 227 } 228 return out[0], nil 229 } 230 231 // getValidService 获取有效的服务数据 232 // 注意:该函数不会返回service_metadata 233 func (t *transaction) getValidService(sql string, name string, namespace string) (*model.Service, error) { 234 if err := t.finish(); err != nil { 235 return nil, err 236 } 237 238 rows, err := t.tx.Query(sql, name, namespace) 239 if err != nil { 240 t.failed = true 241 return nil, err 242 } 243 244 out, err := fetchServiceRows(rows) 245 if err != nil { 246 t.failed = true 247 return nil, err 248 } 249 250 if len(out) == 0 { 251 return nil, nil 252 } 253 254 return out[0], nil 255 }