gitee.com/curryzheng/dm@v0.0.1/zzn.go (about)

     1  /*
     2   * Copyright (c) 2000-2018, 达梦数据库有限公司.
     3   * All rights reserved.
     4   */
     5  
     6  package dm
     7  
     8  import (
     9  	"bufio"
    10  	"gitee.com/curryzheng/dm/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 int32 = 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]*epGroup)
   112  
   113  	GlobalProperties = NewProperties()
   114  )
   115  
   116  // filePath: dm_svc.conf 文件路径
   117  func load(filePath string) {
   118  	if filePath == "" {
   119  		switch runtime.GOOS {
   120  		case "windows":
   121  			filePath = os.Getenv("SystemRoot") + "\\system32\\dm_svc.conf"
   122  		case "linux":
   123  			filePath = "/etc/dm_svc.conf"
   124  		default:
   125  			return
   126  		}
   127  	}
   128  	file, err := os.Open(filePath)
   129  	defer file.Close()
   130  	if err != nil {
   131  		return
   132  	}
   133  	fileReader := bufio.NewReader(file)
   134  
   135  	// GlobalProperties = NewProperties()
   136  	var groupProps *Properties
   137  	var line string //dm_svc.conf读取到的一行
   138  
   139  	for line, err = fileReader.ReadString('\n'); line != "" && (err == nil || err == io.EOF); line, err = fileReader.ReadString('\n') {
   140  		// 去除#标记的注释
   141  		if notesIndex := strings.IndexByte(line, '#'); notesIndex != -1 {
   142  			line = line[:notesIndex]
   143  		}
   144  		// 去除前后多余的空格
   145  		line = strings.TrimSpace(line)
   146  		if line == "" {
   147  			continue
   148  		}
   149  
   150  		if strings.HasPrefix(line, "[") && strings.HasSuffix(line, "]") {
   151  			groupName := strings.ToLower(line[1 : len(line)-1])
   152  			dbGroup, ok := ServerGroupMap[groupName]
   153  			if groupName == "" || !ok {
   154  				continue
   155  			}
   156  			groupProps = dbGroup.props
   157  			if groupProps.IsNil() {
   158  				groupProps = NewProperties()
   159  				groupProps.SetProperties(GlobalProperties)
   160  				dbGroup.props = groupProps
   161  			}
   162  
   163  		} else {
   164  			cfgInfo := strings.Split(line, "=")
   165  			if len(cfgInfo) < 2 {
   166  				continue
   167  			}
   168  			key := strings.TrimSpace(cfgInfo[0])
   169  			value := strings.TrimSpace(cfgInfo[1])
   170  			if strings.HasPrefix(value, "(") && strings.HasSuffix(value, ")") {
   171  				value = strings.TrimSpace(value[1 : len(value)-1])
   172  			}
   173  			if key == "" || value == "" {
   174  				continue
   175  			}
   176  			// 区分属性是全局的还是组的
   177  			var success bool
   178  			if groupProps.IsNil() {
   179  				success = SetServerGroupProperties(GlobalProperties, key, value)
   180  			} else {
   181  				success = SetServerGroupProperties(groupProps, key, value)
   182  			}
   183  			if !success {
   184  				var serverGroup = parseServerName(key, value)
   185  				if serverGroup != nil {
   186  					serverGroup.props = NewProperties()
   187  					serverGroup.props.SetProperties(GlobalProperties)
   188  					ServerGroupMap[strings.ToLower(key)] = serverGroup
   189  				}
   190  			}
   191  		}
   192  	}
   193  }
   194  
   195  func SetServerGroupProperties(props *Properties, key string, value string) bool {
   196  	if util.StringUtil.EqualsIgnoreCase(key, "ADDRESS_REMAP") {
   197  		tmp := props.GetString(AddressRemapKey, "")
   198  		props.Set(AddressRemapKey, tmp+"("+value+")")
   199  	} else if util.StringUtil.EqualsIgnoreCase(key, "ALWAYS_ALLOW_COMMIT") {
   200  		props.Set(AlwayseAllowCommitKey, value)
   201  	} else if util.StringUtil.EqualsIgnoreCase(key, "APP_NAME") {
   202  		props.Set(AppNameKey, value)
   203  	} else if util.StringUtil.EqualsIgnoreCase(key, "AUTO_COMMIT") {
   204  		props.Set(AutoCommitKey, value)
   205  	} else if util.StringUtil.EqualsIgnoreCase(key, "BATCH_ALLOW_MAX_ERRORS") {
   206  		props.Set(BatchAllowMaxErrorsKey, value)
   207  	} else if util.StringUtil.EqualsIgnoreCase(key, "BATCH_CONTINUE_ON_ERROR") ||
   208  		util.StringUtil.EqualsIgnoreCase(key, "CONTINUE_BATCH_ON_ERROR") {
   209  		props.Set(ContinueBatchOnErrorKey, value)
   210  	} else if util.StringUtil.EqualsIgnoreCase(key, "BATCH_NOT_ON_CALL") {
   211  		props.Set(BatchNotOnCallKey, value)
   212  	} else if util.StringUtil.EqualsIgnoreCase(key, "BATCH_TYPE") {
   213  		props.Set(BatchTypeKey, value)
   214  	} else if util.StringUtil.EqualsIgnoreCase(key, "BUF_PREFETCH") {
   215  		props.Set(BufPrefetchKey, value)
   216  	} else if util.StringUtil.EqualsIgnoreCase(key, "CIPHER_PATH") {
   217  		props.Set(CipherPathKey, value)
   218  	} else if util.StringUtil.EqualsIgnoreCase(key, "CLUSTER") {
   219  		props.Set(ClusterKey, value)
   220  	} else if util.StringUtil.EqualsIgnoreCase(key, "COLUMN_NAME_UPPER_CASE") {
   221  		props.Set(ColumnNameUpperCaseKey, value)
   222  	} else if util.StringUtil.EqualsIgnoreCase(key, "COLUMN_NAME_CASE") {
   223  		props.Set(ColumnNameCaseKey, value)
   224  	} else if util.StringUtil.EqualsIgnoreCase(key, "COMPATIBLE_MODE") {
   225  		props.Set(CompatibleModeKey, value)
   226  	} else if util.StringUtil.EqualsIgnoreCase(key, "COMPRESS") ||
   227  		util.StringUtil.EqualsIgnoreCase(key, "COMPRESS_MSG") {
   228  		props.Set(CompressKey, value)
   229  	} else if util.StringUtil.EqualsIgnoreCase(key, "COMPRESS_ID") {
   230  		props.Set(CompressIdKey, value)
   231  	} else if util.StringUtil.EqualsIgnoreCase(key, "CONNECT_TIMEOUT") {
   232  		props.Set(ConnectTimeoutKey, value)
   233  	} else if util.StringUtil.EqualsIgnoreCase(key, "DO_SWITCH") ||
   234  		util.StringUtil.EqualsIgnoreCase(key, "AUTO_RECONNECT") {
   235  		props.Set(DoSwitchKey, value)
   236  	} else if util.StringUtil.EqualsIgnoreCase(key, "ENABLE_RS_CACHE") {
   237  		props.Set(EnRsCacheKey, value)
   238  	} else if util.StringUtil.EqualsIgnoreCase(key, "EP_SELECTION") {
   239  		props.Set(EpSelectorKey, value)
   240  	} else if util.StringUtil.EqualsIgnoreCase(key, "ESCAPE_PROCESS") {
   241  		props.Set(EscapeProcessKey, value)
   242  	} else if util.StringUtil.EqualsIgnoreCase(key, "IS_BDTA_RS") {
   243  		props.Set(IsBdtaRSKey, value)
   244  	} else if util.StringUtil.EqualsIgnoreCase(key, "KEY_WORDS") ||
   245  		util.StringUtil.EqualsIgnoreCase(key, "KEYWORDS") {
   246  		props.Set(KeywordsKey, value)
   247  	} else if util.StringUtil.EqualsIgnoreCase(key, "LANGUAGE") {
   248  		props.Set(LanguageKey, value)
   249  	} else if util.StringUtil.EqualsIgnoreCase(key, "LOB_MODE") {
   250  		props.Set(LobModeKey, value)
   251  	} else if util.StringUtil.EqualsIgnoreCase(key, "LOG_DIR") {
   252  		props.Set(LogDirKey, value)
   253  	} else if util.StringUtil.EqualsIgnoreCase(key, "LOG_FLUSH_FREQ") {
   254  		props.Set(LogFlushFreqKey, value)
   255  	} else if util.StringUtil.EqualsIgnoreCase(key, "LOG_LEVEL") {
   256  		props.Set(LogLevelKey, value)
   257  	} else if util.StringUtil.EqualsIgnoreCase(key, "LOGIN_DSC_CTRL") {
   258  		props.Set(LoginDscCtrlKey, value)
   259  	} else if util.StringUtil.EqualsIgnoreCase(key, "LOGIN_ENCRYPT") {
   260  		props.Set(LoginEncryptKey, value)
   261  	} else if util.StringUtil.EqualsIgnoreCase(key, "LOGIN_MODE") {
   262  		props.Set(LoginModeKey, value)
   263  	} else if util.StringUtil.EqualsIgnoreCase(key, "LOGIN_STATUS") {
   264  		props.Set(LoginStatusKey, value)
   265  	} else if util.StringUtil.EqualsIgnoreCase(key, "MAX_ROWS") {
   266  		props.Set(MaxRowsKey, value)
   267  	} else if util.StringUtil.EqualsIgnoreCase(key, "MPP_LOCAL") {
   268  		props.Set(MppLocalKey, value)
   269  	} else if util.StringUtil.EqualsIgnoreCase(key, "OS_NAME") {
   270  		props.Set(OsNameKey, value)
   271  	} else if util.StringUtil.EqualsIgnoreCase(key, "RS_CACHE_SIZE") {
   272  		props.Set(RsCacheSizeKey, value)
   273  	} else if util.StringUtil.EqualsIgnoreCase(key, "RS_REFRESH_FREQ") {
   274  		props.Set(RsRefreshFreqKey, value)
   275  	} else if util.StringUtil.EqualsIgnoreCase(key, "RW_HA") {
   276  		props.Set(RwHAKey, value)
   277  	} else if util.StringUtil.EqualsIgnoreCase(key, "RW_IGNORE_SQL") {
   278  		props.Set(RwIgnoreSqlKey, value)
   279  	} else if util.StringUtil.EqualsIgnoreCase(key, "RW_PERCENT") {
   280  		props.Set(RwPercentKey, value)
   281  	} else if util.StringUtil.EqualsIgnoreCase(key, "RW_SEPARATE") {
   282  		props.Set(RwSeparateKey, value)
   283  	} else if util.StringUtil.EqualsIgnoreCase(key, "RW_STANDBY_RECOVER_TIME") {
   284  		props.Set(RwStandbyRecoverTimeKey, value)
   285  	} else if util.StringUtil.EqualsIgnoreCase(key, "SCHEMA") {
   286  		props.Set(SchemaKey, value)
   287  	} else if util.StringUtil.EqualsIgnoreCase(key, "SESS_ENCODE") {
   288  		if IsSupportedCharset(value) {
   289  			props.Set("sessEncode", value)
   290  		}
   291  	} else if util.StringUtil.EqualsIgnoreCase(key, "SESSION_TIMEOUT") {
   292  		props.Set(SessionTimeoutKey, value)
   293  	} else if util.StringUtil.EqualsIgnoreCase(key, "SOCKET_TIMEOUT") {
   294  		props.Set(SocketTimeoutKey, value)
   295  	} else if util.StringUtil.EqualsIgnoreCase(key, "SSL_FILES_PATH") {
   296  		props.Set(SslFilesPathKey, value)
   297  	} else if util.StringUtil.EqualsIgnoreCase(key, "STAT_DIR") {
   298  		props.Set(StatDirKey, value)
   299  	} else if util.StringUtil.EqualsIgnoreCase(key, "STAT_ENABLE") {
   300  		props.Set(StatEnableKey, value)
   301  	} else if util.StringUtil.EqualsIgnoreCase(key, "STAT_FLUSH_FREQ") {
   302  		props.Set(StatFlushFreqKey, value)
   303  	} else if util.StringUtil.EqualsIgnoreCase(key, "STAT_HIGH_FREQ_SQL_COUNT") {
   304  		props.Set(StatHighFreqSqlCountKey, value)
   305  	} else if util.StringUtil.EqualsIgnoreCase(key, "STAT_SLOW_SQL_COUNT") {
   306  		props.Set(StatSlowSqlCountKey, value)
   307  	} else if util.StringUtil.EqualsIgnoreCase(key, "STAT_SQL_MAX_COUNT") {
   308  		props.Set(StatSqlMaxCountKey, value)
   309  	} else if util.StringUtil.EqualsIgnoreCase(key, "STAT_SQL_REMOVE_MODE") {
   310  		props.Set(StatSqlRemoveModeKey, value)
   311  	} else if util.StringUtil.EqualsIgnoreCase(key, "SWITCH_INTERVAL") {
   312  		props.Set(SwitchIntervalKey, value)
   313  	} else if util.StringUtil.EqualsIgnoreCase(key, "SWITCH_TIME") ||
   314  		util.StringUtil.EqualsIgnoreCase(key, "SWITCH_TIMES") {
   315  		props.Set(SwitchTimesKey, value)
   316  	} else if util.StringUtil.EqualsIgnoreCase(key, "TIME_ZONE") {
   317  		props.Set(TimeZoneKey, value)
   318  		props.Set("localTimezone", value)
   319  	} else if util.StringUtil.EqualsIgnoreCase(key, "USER_REMAP") {
   320  		tmp := props.GetString(UserRemapKey, "")
   321  		props.Set(UserRemapKey, tmp+"("+value+")")
   322  	} else {
   323  		return false
   324  	}
   325  	return true
   326  }
   327  
   328  func parseServerName(name string, value string) *epGroup {
   329  	values := strings.Split(value, ",")
   330  
   331  	var tmpVals []string
   332  	var tmpName string
   333  	var tmpPort int
   334  	var svrList = make([]*ep, 0, len(values))
   335  
   336  	for _, v := range values {
   337  
   338  		var tmp *ep
   339  		// 先查找IPV6,以[]包括
   340  		begin := strings.IndexByte(v, '[')
   341  		end := -1
   342  		if begin != -1 {
   343  			end = strings.IndexByte(v[begin:], ']')
   344  		}
   345  		if end != -1 {
   346  			tmpName = v[begin+1 : end]
   347  
   348  			// port
   349  			if portIndex := strings.IndexByte(v[end:], ':'); portIndex != -1 {
   350  				tmpPort, _ = strconv.Atoi(strings.TrimSpace(v[portIndex+1:]))
   351  			} else {
   352  				tmpPort = int(DEFAULT_PORT)
   353  			}
   354  			tmp = newEP(tmpName, int32(tmpPort))
   355  			svrList = append(svrList, tmp)
   356  			continue
   357  		}
   358  		// IPV4
   359  		tmpVals = strings.Split(v, ":")
   360  		tmpName = strings.TrimSpace(tmpVals[0])
   361  		if len(tmpVals) >= 2 {
   362  			tmpPort, _ = strconv.Atoi(tmpVals[1])
   363  		} else {
   364  			tmpPort = int(DEFAULT_PORT)
   365  		}
   366  		tmp = newEP(tmpName, int32(tmpPort))
   367  		svrList = append(svrList, tmp)
   368  	}
   369  
   370  	if len(svrList) == 0 {
   371  		return nil
   372  	}
   373  	return newEPGroup(name, svrList)
   374  }
   375  
   376  func setDriverAttributes(props *Properties) {
   377  	if props == nil || props.Len() == 0 {
   378  		return
   379  	}
   380  
   381  	parseLanguage(props.GetString(LanguageKey, "cn"))
   382  	DbAliveCheckFreq = props.GetInt(DbAliveCheckFreqKey, DbAliveCheckFreqDef, 1, int(INT32_MAX))
   383  
   384  	//// log
   385  	//LogLevel = ParseLogLevel(props)
   386  	//LogDir = util.StringUtil.FormatDir(props.GetTrimString(LogDirKey, LogDirDef))
   387  	//LogBufferSize = props.GetInt(LogBufferSizeKey, LogBufferSizeDef, 1, int(INT32_MAX))
   388  	//LogFlushFreq = props.GetInt(LogFlushFreqKey, LogFlushFreqDef, 1, int(INT32_MAX))
   389  	//LogFlushQueueSize = props.GetInt(LogFlusherQueueSizeKey, LogFlushQueueSizeDef, 1, int(INT32_MAX))
   390  	//
   391  	//// stat
   392  	//StatEnable = props.GetBool(StatEnableKey, StatEnableDef)
   393  	//StatDir = util.StringUtil.FormatDir(props.GetTrimString(StatDirKey, StatDirDef))
   394  	//StatFlushFreq = props.GetInt(StatFlushFreqKey, StatFlushFreqDef, 1, int(INT32_MAX))
   395  	//StatHighFreqSqlCount = props.GetInt(StatHighFreqSqlCountKey, StatHighFreqSqlCountDef, 0, 1000)
   396  	//StatSlowSqlCount = props.GetInt(StatSlowSqlCountKey, StatSlowSqlCountDef, 0, 1000)
   397  	//StatSqlMaxCount = props.GetInt(StatSqlMaxCountKey, StatSqlMaxCountDef, 0, 100000)
   398  	//parseStatSqlRemoveMode(props)
   399  }
   400  
   401  func parseLanguage(value string) {
   402  	if util.StringUtil.EqualsIgnoreCase("cn", value) {
   403  		Locale = 0
   404  	} else if util.StringUtil.EqualsIgnoreCase("en", value) {
   405  		Locale = 1
   406  	}
   407  }
   408  
   409  func IsSupportedCharset(charset string) bool {
   410  	if util.StringUtil.EqualsIgnoreCase(ENCODING_UTF8, charset) || util.StringUtil.EqualsIgnoreCase(ENCODING_GB18030, charset) || util.StringUtil.EqualsIgnoreCase(ENCODING_EUCKR, charset) {
   411  		return true
   412  	}
   413  	return false
   414  }
   415  
   416  func ParseLogLevel(props *Properties) int {
   417  	logLevel := LOG_OFF
   418  	value := props.GetString(LogLevelKey, "")
   419  	if value != "" && !util.StringUtil.IsDigit(value) {
   420  		if util.StringUtil.EqualsIgnoreCase("debug", value) {
   421  			logLevel = LOG_DEBUG
   422  		} else if util.StringUtil.EqualsIgnoreCase("info", value) {
   423  			logLevel = LOG_INFO
   424  		} else if util.StringUtil.EqualsIgnoreCase("sql", value) {
   425  			logLevel = LOG_SQL
   426  		} else if util.StringUtil.EqualsIgnoreCase("warn", value) {
   427  			logLevel = LOG_WARN
   428  		} else if util.StringUtil.EqualsIgnoreCase("error", value) {
   429  			logLevel = LOG_ERROR
   430  		} else if util.StringUtil.EqualsIgnoreCase("off", value) {
   431  			logLevel = LOG_OFF
   432  		} else if util.StringUtil.EqualsIgnoreCase("all", value) {
   433  			logLevel = LOG_ALL
   434  		}
   435  	} else {
   436  		logLevel = props.GetInt(LogLevelKey, logLevel, LOG_OFF, LOG_INFO)
   437  	}
   438  
   439  	return logLevel
   440  }