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  }