github.com/xiyichan/dm8@v0.0.0-20211213021639-be727be3e136/zzl.go (about)

     1  /*
     2   * Copyright (c) 2000-2018, 达梦数据库有限公司.
     3   * All rights reserved.
     4   */
     5  
     6  package dm
     7  
     8  import (
     9  	"bufio"
    10  	"github.com/xiyichan/dm8/util"
    11  	"io"
    12  	"os"
    13  	"runtime"
    14  	"strconv"
    15  	"strings"
    16  )
    17  
    18  var LogDirDef, _ = os.Getwd()
    19  
    20  var StatDirDef, _ = os.Getwd()
    21  
    22  const (
    23  	DEFAULT_PORT int = 5236
    24  
    25  	//log level
    26  	LOG_OFF int = 0
    27  
    28  	LOG_ERROR int = 1
    29  
    30  	LOG_WARN int = 2
    31  
    32  	LOG_SQL int = 3
    33  
    34  	LOG_INFO int = 4
    35  
    36  	LOG_DEBUG int = 5
    37  
    38  	LOG_ALL int = 9
    39  
    40  	//stat
    41  	STAT_SQL_REMOVE_LATEST int = 0
    42  
    43  	STAT_SQL_REMOVE_OLDEST int = 1
    44  
    45  	// 编码字符集
    46  	ENCODING_UTF8 string = "UTF-8"
    47  
    48  	ENCODING_EUCKR string = "EUC-KR"
    49  
    50  	ENCODING_GB18030 string = "GB18030"
    51  
    52  	DbAliveCheckFreqDef = 0
    53  
    54  	LocaleDef = 0
    55  
    56  	// log
    57  	LogLevelDef = LOG_OFF // 日志级别:off, error, warn, sql, info, all
    58  
    59  	LogFlushFreqDef = 10 // 日志刷盘时间s (>=0)
    60  
    61  	LogFlushQueueSizeDef = 100 //日志队列大小
    62  
    63  	LogBufferSizeDef = 32 * 1024 // 日志缓冲区大小 (>0)
    64  
    65  	// stat
    66  	StatEnableDef = false //
    67  
    68  	StatFlushFreqDef = 3 // 日志刷盘时间s (>=0)
    69  
    70  	StatSlowSqlCountDef = 100 // 慢sql top行数,(0-1000)
    71  
    72  	StatHighFreqSqlCountDef = 100 // 高频sql top行数, (0-1000)
    73  
    74  	StatSqlMaxCountDef = 100000 // sql 统计最大值(0-100000)
    75  
    76  	StatSqlRemoveModeDef = STAT_SQL_REMOVE_LATEST // 记录sql数超过最大值时,sql淘汰方式
    77  )
    78  
    79  var (
    80  	DbAliveCheckFreq = DbAliveCheckFreqDef
    81  
    82  	Locale = LocaleDef // 0:简体中文 1:英文 2:繁体中文
    83  
    84  	// log
    85  	LogLevel = LogLevelDef // 日志级别:off, error, warn, sql, info, all
    86  
    87  	LogDir = LogDirDef
    88  
    89  	LogFlushFreq = LogFlushFreqDef // 日志刷盘时间s (>=0)
    90  
    91  	LogFlushQueueSize = LogFlushQueueSizeDef
    92  
    93  	LogBufferSize = LogBufferSizeDef // 日志缓冲区大小 (>0)
    94  
    95  	// stat
    96  	StatEnable = StatEnableDef //
    97  
    98  	StatDir = StatDirDef // jdbc工作目录,所有生成的文件都在该目录下
    99  
   100  	StatFlushFreq = StatFlushFreqDef // 日志刷盘时间s (>=0)
   101  
   102  	StatSlowSqlCount = StatSlowSqlCountDef // 慢sql top行数,(0-1000)
   103  
   104  	StatHighFreqSqlCount = StatHighFreqSqlCountDef // 高频sql top行数, (0-1000)
   105  
   106  	StatSqlMaxCount = StatSqlMaxCountDef // sql 统计最大值(0-100000)
   107  
   108  	StatSqlRemoveMode = StatSqlRemoveModeDef // 记录sql数超过最大值时,sql淘汰方式
   109  
   110  	/*---------------------------------------------------------------*/
   111  	ServerGroupMap = make(map[string]*DBGroup)
   112  
   113  	GlobalProperties *Properties
   114  
   115  	addressRemap = make(map[string]string)
   116  
   117  	userRemap = make(map[string]string)
   118  )
   119  
   120  func AddressRemap(url string) string {
   121  	if url != "" {
   122  		startIdx := strings.Index(url, "//")
   123  		endIdx := strings.Index(url, "?")
   124  
   125  		if startIdx != -1 {
   126  			startIdx += 2
   127  		}
   128  
   129  		if endIdx == -1 {
   130  			endIdx = len(url)
   131  		}
   132  
   133  		if startIdx != -1 {
   134  			newAddress, ok := addressRemap[strings.TrimSpace(url[startIdx:endIdx])]
   135  			if ok && newAddress != "" {
   136  				url = url[0:startIdx] + newAddress + url[endIdx:]
   137  			}
   138  		}
   139  	}
   140  	return url
   141  }
   142  
   143  func UserRemap(props *Properties) {
   144  	user := props.GetString("user", "")
   145  
   146  	if user == "" {
   147  		return
   148  	}
   149  
   150  	tmp, ok := userRemap[user]
   151  	if ok {
   152  		user = tmp
   153  	}
   154  	props.Set("user", user)
   155  }
   156  
   157  // filePath: dm_svc.conf 文件路径
   158  func load(filePath string) {
   159  	if filePath == "" {
   160  		switch runtime.GOOS {
   161  		case "windows":
   162  			filePath = os.Getenv("SystemRoot") + "\\system32\\dm_svc.conf"
   163  		case "linux":
   164  			filePath = "/etc/dm_svc.conf"
   165  		default:
   166  			return
   167  		}
   168  	}
   169  	file, err := os.Open(filePath)
   170  	defer file.Close()
   171  	if err != nil {
   172  		return
   173  	}
   174  	fileReader := bufio.NewReader(file)
   175  
   176  	GlobalProperties = NewProperties()
   177  	var groupProps *Properties
   178  	var line string //dm_svc.conf读取到的一行
   179  
   180  	for line, err = fileReader.ReadString('\n'); line != "" && (err == nil || err == io.EOF); line, err = fileReader.ReadString('\n') {
   181  		// 去除#标记的注释
   182  		if notesIndex := strings.IndexByte(line, '#'); notesIndex != -1 {
   183  			line = line[:notesIndex]
   184  		}
   185  		// 去除前后多余的空格
   186  		line = strings.TrimSpace(line)
   187  		if line == "" {
   188  			continue
   189  		}
   190  
   191  		if strings.HasPrefix(line, "[") && strings.HasSuffix(line, "]") {
   192  			groupName := strings.ToLower(line[1 : len(line)-1])
   193  			dbGroup, ok := ServerGroupMap[groupName]
   194  			if groupName == "" || !ok {
   195  				continue
   196  			}
   197  			groupProps = dbGroup.Props
   198  			if groupProps.IsNil() {
   199  				groupProps = NewProperties()
   200  				groupProps.SetProperties(GlobalProperties)
   201  				dbGroup.Props = groupProps
   202  			}
   203  
   204  		} else {
   205  			cfgInfo := strings.Split(line, "=")
   206  			if len(cfgInfo) < 2 {
   207  				continue
   208  			}
   209  			key := strings.TrimSpace(cfgInfo[0])
   210  			value := strings.TrimSpace(cfgInfo[1])
   211  			if strings.HasPrefix(value, "(") && strings.HasSuffix(value, ")") {
   212  				value = strings.TrimSpace(value[1 : len(value)-1])
   213  			} else {
   214  				continue
   215  			}
   216  			if key == "" || value == "" {
   217  				continue
   218  			}
   219  			// 区分属性是全局的还是组的
   220  			var success bool
   221  			if groupProps.IsNil() {
   222  				success = SetServerGroupProperties(GlobalProperties, key, value)
   223  			} else {
   224  				success = SetServerGroupProperties(groupProps, key, value)
   225  			}
   226  			if !success {
   227  				var serverGroup = parseServerName(key, value)
   228  				if serverGroup != nil {
   229  					serverGroup.Props = NewProperties()
   230  					serverGroup.Props.SetProperties(GlobalProperties)
   231  					ServerGroupMap[strings.ToLower(key)] = serverGroup
   232  				}
   233  			}
   234  		}
   235  	}
   236  }
   237  
   238  func SetServerGroupProperties(props *Properties, key string, value string) bool {
   239  	if util.StringUtil.EqualsIgnoreCase(key, "ALWAYS_ALLOW_COMMIT") {
   240  		props.Set(AlwayseAllowCommitKey, value)
   241  	} else if util.StringUtil.EqualsIgnoreCase(key, "APP_NAME") {
   242  		props.Set(AppNameKey, value)
   243  	} else if util.StringUtil.EqualsIgnoreCase(key, "AUTO_COMMIT") {
   244  		props.Set(AutoCommitKey, value)
   245  	} else if util.StringUtil.EqualsIgnoreCase(key, "BATCH_CONTINUE_ON_ERROR") ||
   246  		util.StringUtil.EqualsIgnoreCase(key, "CONTINUE_BATCH_ON_ERROR") {
   247  		props.Set(ContinueBatchOnErrorKey, value)
   248  	} else if util.StringUtil.EqualsIgnoreCase(key, "BUF_PREFETCH") {
   249  		props.Set(BufPrefetchKey, value)
   250  	} else if util.StringUtil.EqualsIgnoreCase(key, "CIPHER_PATH") {
   251  		props.Set(CipherPathKey, value)
   252  	} else if util.StringUtil.EqualsIgnoreCase(key, "COMPATIBLE_MODE") {
   253  		props.Set(CompatibleModeKey, value)
   254  	} else if util.StringUtil.EqualsIgnoreCase(key, "COMPRESS") ||
   255  		util.StringUtil.EqualsIgnoreCase(key, "COMPRESS_MSG") {
   256  		props.Set(CompressKey, value)
   257  	} else if util.StringUtil.EqualsIgnoreCase(key, "COMPRESS_ID") {
   258  		props.Set(CompressIdKey, value)
   259  	} else if util.StringUtil.EqualsIgnoreCase(key, "CONNECT_TIMEOUT") {
   260  		props.Set(ConnectTimeoutKey, value)
   261  	} else if util.StringUtil.EqualsIgnoreCase(key, "DO_SWITCH") {
   262  		props.Set(DoSwitchKey, value)
   263  	} else if util.StringUtil.EqualsIgnoreCase(key, "ENABLE_RS_CACHE") {
   264  		props.Set(EnRsCacheKey, value)
   265  	} else if util.StringUtil.EqualsIgnoreCase(key, "ESCAPE_PROCESS") {
   266  		props.Set(EscapeProcessKey, value)
   267  	} else if util.StringUtil.EqualsIgnoreCase(key, "IS_BDTA_RS") {
   268  		props.Set(IsBdtaRSKey, value)
   269  	} else if util.StringUtil.EqualsIgnoreCase(key, "KEY_WORDS") ||
   270  		util.StringUtil.EqualsIgnoreCase(key, "KEYWORDS") {
   271  		props.Set(KeywordsKey, value)
   272  	} else if util.StringUtil.EqualsIgnoreCase(key, "LANGUAGE") {
   273  		props.Set(LanguageKey, value)
   274  	} else if util.StringUtil.EqualsIgnoreCase(key, "LOB_MODE") {
   275  		props.Set(LobModeKey, value)
   276  	} else if util.StringUtil.EqualsIgnoreCase(key, "LOG_DIR") {
   277  		props.Set(LogDirKey, value)
   278  	} else if util.StringUtil.EqualsIgnoreCase(key, "LOG_FLUSH_FREQ") {
   279  		props.Set(LogFlushFreqKey, value)
   280  	} else if util.StringUtil.EqualsIgnoreCase(key, "LOG_LEVEL") {
   281  		props.Set(LogLevelKey, value)
   282  	} else if util.StringUtil.EqualsIgnoreCase(key, "LOGIN_ENCRYPT") {
   283  		props.Set(LoginEncryptKey, value)
   284  	} else if util.StringUtil.EqualsIgnoreCase(key, "LOGIN_MODE") {
   285  		props.Set(LoginModeKey, value)
   286  	} else if util.StringUtil.EqualsIgnoreCase(key, "LOGIN_STATUS") {
   287  		props.Set(LoginStatusKey, value)
   288  	} else if util.StringUtil.EqualsIgnoreCase(key, "MAX_ROWS") {
   289  		props.Set(MaxRowsKey, value)
   290  	} else if util.StringUtil.EqualsIgnoreCase(key, "MPP_LOCAL") {
   291  		props.Set(MppLocalKey, value)
   292  	} else if util.StringUtil.EqualsIgnoreCase(key, "RS_CACHE_SIZE") {
   293  		props.Set(RsCacheSizeKey, value)
   294  	} else if util.StringUtil.EqualsIgnoreCase(key, "RS_REFRESH_FREQ") {
   295  		props.Set(RsRefreshFreqKey, value)
   296  	} else if util.StringUtil.EqualsIgnoreCase(key, "RW_HA") {
   297  		props.Set(RwHAKey, value)
   298  	} else if util.StringUtil.EqualsIgnoreCase(key, "RW_PERCENT") {
   299  		props.Set(RwPercentKey, value)
   300  	} else if util.StringUtil.EqualsIgnoreCase(key, "RW_SEPARATE") {
   301  		props.Set(RwSeparateKey, value)
   302  	} else if util.StringUtil.EqualsIgnoreCase(key, "RW_STANDBY_RECOVER_TIME") {
   303  		props.Set(RwStandbyRecoverTimeKey, value)
   304  	} else if util.StringUtil.EqualsIgnoreCase(key, "SCHEMA") {
   305  		props.Set(SchemaKey, value)
   306  	} else if util.StringUtil.EqualsIgnoreCase(key, "SESS_ENCODE") {
   307  		if IsSupportedCharset(value) {
   308  			props.Set("sessEncode", value)
   309  		}
   310  	} else if util.StringUtil.EqualsIgnoreCase(key, "SESSION_TIMEOUT") {
   311  		props.Set(SessionTimeoutKey, value)
   312  	} else if util.StringUtil.EqualsIgnoreCase(key, "SOCKET_TIMEOUT") {
   313  		props.Set(SocketTimeoutKey, value)
   314  	} else if util.StringUtil.EqualsIgnoreCase(key, "SSL_FILES_PATH") {
   315  		props.Set(SslFilesPathKey, value)
   316  	} else if util.StringUtil.EqualsIgnoreCase(key, "STAT_DIR") {
   317  		props.Set(StatDirKey, value)
   318  	} else if util.StringUtil.EqualsIgnoreCase(key, "STAT_ENABLE") {
   319  		props.Set(StatEnableKey, value)
   320  	} else if util.StringUtil.EqualsIgnoreCase(key, "STAT_FLUSH_FREQ") {
   321  		props.Set(StatFlushFreqKey, value)
   322  	} else if util.StringUtil.EqualsIgnoreCase(key, "STAT_HIGH_FREQ_SQL_COUNT") {
   323  		props.Set(StatHighFreqSqlCountKey, value)
   324  	} else if util.StringUtil.EqualsIgnoreCase(key, "STAT_SLOW_SQL_COUNT") {
   325  		props.Set(StatSlowSqlCountKey, value)
   326  	} else if util.StringUtil.EqualsIgnoreCase(key, "STAT_SQL_MAX_COUNT") {
   327  		props.Set(StatSqlMaxCountKey, value)
   328  	} else if util.StringUtil.EqualsIgnoreCase(key, "STAT_SQL_REMOVE_MODE") {
   329  		props.Set(StatSqlRemoveModeKey, value)
   330  	} else if util.StringUtil.EqualsIgnoreCase(key, "SWITCH_INTERVAL") {
   331  		props.Set(SwitchIntervalKey, value)
   332  	} else if util.StringUtil.EqualsIgnoreCase(key, "SWITCH_TIME") ||
   333  		util.StringUtil.EqualsIgnoreCase(key, "SWITCH_TIMES") {
   334  		props.Set(SwitchTimesKey, value)
   335  	} else if util.StringUtil.EqualsIgnoreCase(key, "TIME_ZONE") {
   336  		props.Set(TimeZoneKey, value)
   337  		props.Set("localTimezone", value)
   338  	} else {
   339  		return false
   340  	}
   341  	return true
   342  }
   343  
   344  func parseServerName(name string, value string) *DBGroup {
   345  	values := strings.Split(value, ",")
   346  
   347  	var tmpVals []string
   348  	var tmpName string
   349  	var tmpPort int
   350  	var svrList = make([]DB, 0, len(values))
   351  
   352  	for _, v := range values {
   353  
   354  		var tmp DB
   355  		// 先查找IPV6,以[]包括
   356  		begin := strings.IndexByte(v, '[')
   357  		end := -1
   358  		if begin != -1 {
   359  			end = strings.IndexByte(v[begin:], ']')
   360  		}
   361  		if end != -1 {
   362  			tmpName = v[begin+1 : end]
   363  
   364  			// port
   365  			if portIndex := strings.IndexByte(v[end:], ':'); portIndex != -1 {
   366  				tmpPort, _ = strconv.Atoi(strings.TrimSpace(v[portIndex+1:]))
   367  			} else {
   368  				tmpPort = DEFAULT_PORT
   369  			}
   370  			tmp = DB{host: tmpName, port: tmpPort}
   371  			svrList = append(svrList, tmp)
   372  			continue
   373  		}
   374  		// IPV4
   375  		tmpVals = strings.Split(v, ":")
   376  		tmpName = strings.TrimSpace(tmpVals[0])
   377  		if len(tmpVals) >= 2 {
   378  			tmpPort, _ = strconv.Atoi(tmpVals[1])
   379  		} else {
   380  			tmpPort = DEFAULT_PORT
   381  		}
   382  		tmp = DB{host: tmpName, port: tmpPort}
   383  		svrList = append(svrList, tmp)
   384  	}
   385  
   386  	if len(svrList) == 0 {
   387  		return nil
   388  	}
   389  	return &DBGroup{
   390  		Name:       name,
   391  		ServerList: svrList,
   392  	}
   393  }
   394  
   395  func setDriverAttributes(props *Properties) {
   396  	if props == nil || props.Len() == 0 {
   397  		return
   398  	}
   399  
   400  	parseLanguage(props.GetString(LanguageKey, "cn"))
   401  	DbAliveCheckFreq = props.GetInt(DbAliveCheckFreqKey, DbAliveCheckFreqDef, 1, int(INT32_MAX))
   402  
   403  	//// log
   404  	//LogLevel = ParseLogLevel(props)
   405  	//LogDir = util.StringUtil.FormatDir(props.GetTrimString(LogDirKey, LogDirDef))
   406  	//LogBufferSize = props.GetInt(LogBufferSizeKey, LogBufferSizeDef, 1, int(INT32_MAX))
   407  	//LogFlushFreq = props.GetInt(LogFlushFreqKey, LogFlushFreqDef, 1, int(INT32_MAX))
   408  	//LogFlushQueueSize = props.GetInt(LogFlusherQueueSizeKey, LogFlushQueueSizeDef, 1, int(INT32_MAX))
   409  	//
   410  	//// stat
   411  	//StatEnable = props.GetBool(StatEnableKey, StatEnableDef)
   412  	//StatDir = util.StringUtil.FormatDir(props.GetTrimString(StatDirKey, StatDirDef))
   413  	//StatFlushFreq = props.GetInt(StatFlushFreqKey, StatFlushFreqDef, 1, int(INT32_MAX))
   414  	//StatHighFreqSqlCount = props.GetInt(StatHighFreqSqlCountKey, StatHighFreqSqlCountDef, 0, 1000)
   415  	//StatSlowSqlCount = props.GetInt(StatSlowSqlCountKey, StatSlowSqlCountDef, 0, 1000)
   416  	//StatSqlMaxCount = props.GetInt(StatSqlMaxCountKey, StatSqlMaxCountDef, 0, 100000)
   417  	//parseStatSqlRemoveMode(props)
   418  }
   419  
   420  func parseLanguage(value string) {
   421  	if util.StringUtil.EqualsIgnoreCase("cn", value) {
   422  		Locale = 0
   423  	} else if util.StringUtil.EqualsIgnoreCase("en", value) {
   424  		Locale = 1
   425  	}
   426  }
   427  
   428  func IsSupportedCharset(charset string) bool {
   429  	if util.StringUtil.EqualsIgnoreCase(ENCODING_UTF8, charset) || util.StringUtil.EqualsIgnoreCase(ENCODING_GB18030, charset) || util.StringUtil.EqualsIgnoreCase(ENCODING_EUCKR, charset) {
   430  		return true
   431  	}
   432  	return false
   433  }
   434  
   435  func ParseLogLevel(props *Properties) int {
   436  	logLevel := LOG_OFF
   437  	value := props.GetString(LogLevelKey, "")
   438  	if value != "" && !util.StringUtil.IsDigit(value) {
   439  		if util.StringUtil.EqualsIgnoreCase("debug", value) {
   440  			logLevel = LOG_DEBUG
   441  		} else if util.StringUtil.EqualsIgnoreCase("info", value) {
   442  			logLevel = LOG_INFO
   443  		} else if util.StringUtil.EqualsIgnoreCase("sql", value) {
   444  			logLevel = LOG_SQL
   445  		} else if util.StringUtil.EqualsIgnoreCase("warn", value) {
   446  			logLevel = LOG_WARN
   447  		} else if util.StringUtil.EqualsIgnoreCase("error", value) {
   448  			logLevel = LOG_ERROR
   449  		} else if util.StringUtil.EqualsIgnoreCase("off", value) {
   450  			logLevel = LOG_OFF
   451  		} else if util.StringUtil.EqualsIgnoreCase("all", value) {
   452  			logLevel = LOG_ALL
   453  		}
   454  	} else {
   455  		logLevel = props.GetInt(LogLevelKey, logLevel, LOG_OFF, LOG_INFO)
   456  	}
   457  
   458  	return logLevel
   459  }