github.com/wanlay/gorm-dm8@v1.0.5/dmr/zzm.go (about)

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