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 }