github.com/wanlay/gorm-dm8@v1.0.5/dmr/zw.go (about) 1 /* 2 * Copyright (c) 2000-2018, 达梦数据库有限公司. 3 * All rights reserved. 4 */ 5 6 package dmr 7 8 import ( 9 "math/rand" 10 "strconv" 11 "time" 12 13 "github.com/wanlay/gorm-dm8/dmr/util" 14 ) 15 16 var rwMap = make(map[string]*rwCounter) 17 18 type rwCounter struct { 19 ntrx_primary int64 20 21 ntrx_total int64 22 23 primaryPercent float64 24 25 standbyPercent float64 26 27 standbyNTrxMap map[string]int64 28 29 standbyIdMap map[string]int32 30 31 standbyCount int32 32 33 flag []int32 34 35 increments []int32 36 } 37 38 func newRWCounter(primaryPercent int32, standbyCount int32) *rwCounter { 39 rwc := new(rwCounter) 40 rwc.standbyNTrxMap = make(map[string]int64) 41 rwc.standbyIdMap = make(map[string]int32) 42 rwc.reset(primaryPercent, standbyCount) 43 return rwc 44 } 45 46 func (rwc *rwCounter) reset(primaryPercent int32, standbyCount int32) { 47 rwc.ntrx_primary = 0 48 rwc.ntrx_total = 0 49 rwc.standbyCount = standbyCount 50 rwc.increments = make([]int32, standbyCount+1) 51 rwc.flag = make([]int32, standbyCount+1) 52 var gcd = util.GCD(primaryPercent*standbyCount, 100-primaryPercent) 53 rwc.increments[0] = primaryPercent * standbyCount / gcd 54 for i, tmp := 1, (100-primaryPercent)/gcd; i < len(rwc.increments); i++ { 55 rwc.increments[i] = tmp 56 } 57 copy(rwc.flag, rwc.increments) 58 59 if standbyCount > 0 { 60 rwc.primaryPercent = float64(primaryPercent) / 100.0 61 rwc.standbyPercent = float64(100-primaryPercent) / 100.0 / float64(standbyCount) 62 } else { 63 rwc.primaryPercent = 1 64 rwc.standbyPercent = 0 65 } 66 } 67 68 // 连接创建成功后调用,需要服务器返回standbyCount 69 func getRwCounterInstance(conn *DmConnection, standbyCount int32) *rwCounter { 70 key := conn.dmConnector.host + "_" + strconv.Itoa(int(conn.dmConnector.port)) + "_" + strconv.Itoa(int(conn.dmConnector.rwPercent)) 71 72 rwc, ok := rwMap[key] 73 if !ok { 74 rwc = newRWCounter(conn.dmConnector.rwPercent, standbyCount) 75 rwMap[key] = rwc 76 } else if rwc.standbyCount != standbyCount { 77 rwc.reset(conn.dmConnector.rwPercent, standbyCount) 78 } 79 return rwc 80 } 81 82 /** 83 * @return 主机; 84 */ 85 func (rwc *rwCounter) countPrimary() RWSiteEnum { 86 rwc.adjustNtrx() 87 rwc.increasePrimaryNtrx() 88 return PRIMARY 89 } 90 91 /** 92 * @param dest 主机; 备机; any; 93 * @return 主机; 备机 94 */ 95 func (rwc *rwCounter) count(dest RWSiteEnum, standby *DmConnection) RWSiteEnum { 96 rwc.adjustNtrx() 97 switch dest { 98 case ANYSITE: 99 { 100 if rwc.primaryPercent == 1 || (rwc.flag[0] > rwc.getStandbyFlag(standby) && rwc.flag[0] > util.Sum(rwc.flag[1:])) { 101 rwc.increasePrimaryNtrx() 102 dest = PRIMARY 103 } else { 104 rwc.increaseStandbyNtrx(standby) 105 dest = STANDBY 106 } 107 } 108 case STANDBY: 109 { 110 rwc.increaseStandbyNtrx(standby) 111 } 112 case PRIMARY: 113 { 114 rwc.increasePrimaryNtrx() 115 } 116 } 117 return dest 118 } 119 120 /** 121 * 防止ntrx超出有效范围,等比调整 122 */ 123 func (rwc *rwCounter) adjustNtrx() { 124 if rwc.ntrx_total >= INT64_MAX { 125 var min int64 126 var i = 0 127 for _, num := range rwc.standbyNTrxMap { 128 if i == 0 || num < min { 129 min = num 130 } 131 i++ 132 } 133 if rwc.ntrx_primary < min { 134 min = rwc.ntrx_primary 135 } 136 rwc.ntrx_primary /= min 137 rwc.ntrx_total /= min 138 for k, v := range rwc.standbyNTrxMap { 139 rwc.standbyNTrxMap[k] = v / min 140 } 141 } 142 143 if rwc.flag[0] <= 0 && util.Sum(rwc.flag[1:]) <= 0 { 144 // 如果主库事务数以及所有备库事务数的总和 都 <= 0, 重置事务计数,给每个库的事务计数加上初始计数值 145 for i := 0; i < len(rwc.flag); i++ { 146 rwc.flag[i] += rwc.increments[i] 147 } 148 } 149 } 150 151 func (rwc *rwCounter) increasePrimaryNtrx() { 152 rwc.ntrx_primary++ 153 rwc.flag[0]-- 154 rwc.ntrx_total++ 155 } 156 157 // func (rwc *rwCounter) getStandbyNtrx(standby *DmConnection) int64 { 158 // key := standby.dmConnector.host + ":" + strconv.Itoa(int(standby.dmConnector.port)) 159 // ret, ok := rwc.standbyNTrxMap[key] 160 // if !ok { 161 // ret = 0 162 // } 163 // 164 // return ret 165 // } 166 167 func (rwc *rwCounter) getStandbyId(standby *DmConnection) int32 { 168 key := standby.dmConnector.host + ":" + strconv.Itoa(int(standby.dmConnector.port)) 169 sid, ok := rwc.standbyIdMap[key] 170 if !ok { 171 sid = int32(len(rwc.standbyIdMap) + 1) // 下标0是primary 172 if sid > rwc.standbyCount { 173 // 不在有效备库中 174 return -1 175 } 176 rwc.standbyIdMap[key] = sid 177 } 178 return sid 179 } 180 181 func (rwc *rwCounter) getStandbyFlag(standby *DmConnection) int32 { 182 sid := rwc.getStandbyId(standby) 183 if sid > 0 && sid < int32(len(rwc.flag)) { 184 // 保证备库有效 185 return rwc.flag[sid] 186 } 187 return 0 188 } 189 190 func (rwc *rwCounter) increaseStandbyNtrx(standby *DmConnection) { 191 key := standby.dmConnector.host + ":" + strconv.Itoa(int(standby.dmConnector.port)) 192 ret, ok := rwc.standbyNTrxMap[key] 193 if ok { 194 ret += 1 195 } else { 196 ret = 1 197 } 198 rwc.standbyNTrxMap[key] = ret 199 sid, ok := rwc.standbyIdMap[key] 200 if !ok { 201 sid = int32(len(rwc.standbyIdMap) + 1) // 下标0是primary 202 rwc.standbyIdMap[key] = sid 203 } 204 rwc.flag[sid]-- 205 rwc.ntrx_total++ 206 } 207 208 func (rwc *rwCounter) random(rowCount int32) int32 { 209 rand.Seed(time.Now().UnixNano()) 210 if rowCount > rwc.standbyCount { 211 return rand.Int31n(rwc.standbyCount) 212 } else { 213 return rand.Int31n(rowCount) 214 } 215 } 216 217 func (rwc *rwCounter) String() string { 218 return "PERCENT(P/S) : " + strconv.FormatFloat(rwc.primaryPercent, 'f', -1, 64) + "/" + strconv.FormatFloat(rwc.standbyPercent, 'f', -1, 64) + "\nNTRX_PRIMARY : " + 219 strconv.FormatInt(rwc.ntrx_primary, 10) + "\nNTRX_TOTAL : " + strconv.FormatInt(rwc.ntrx_total, 10) + "\nNTRX_STANDBY : " 220 }