gitee.com/curryzheng/dm@v0.0.1/zg.go (about) 1 /* 2 * Copyright (c) 2000-2018, 达梦数据库有限公司. 3 * All rights reserved. 4 */ 5 6 package dm 7 8 import ( 9 "context" 10 "database/sql/driver" 11 "gitee.com/curryzheng/dm/util" 12 "io" 13 "reflect" 14 "time" 15 ) 16 17 const SQL_GET_DSC_EP_SITE = "SELECT " + 18 "dsc.ep_seqno, " + 19 "(CASE mal.MAL_INST_HOST WHEN '' THEN mal.MAL_HOST ELSE mal.MAL_INST_HOST END) as ep_host, " + 20 "dcr.EP_PORT, " + 21 "dsc.EP_STATUS " + 22 "FROM V$DSC_EP_INFO dsc " + 23 "LEFT join V$DM_MAL_INI mal " + 24 "on dsc.EP_NAME = mal.MAL_INST_NAME " + 25 "LEFT join (SELECT grp.GROUP_TYPE GROUP_TYPE, ep.* FROM SYS.\"V$DCR_GROUP\" grp, SYS.\"V$DCR_EP\" ep where grp.GROUP_NAME = ep.GROUP_NAME) dcr " + 26 "on dsc.EP_NAME = dcr.EP_NAME and GROUP_TYPE = 'DB' order by dsc.ep_seqno asc;" 27 28 type reconnectFilter struct { 29 } 30 31 // 一定抛错 32 func (rf *reconnectFilter) autoReconnect(connection *DmConnection, err error) error { 33 if dmErr, ok := err.(*DmError); ok { 34 if dmErr.ErrCode == ECGO_COMMUNITION_ERROR.ErrCode { 35 return rf.reconnect(connection, dmErr.Error()) 36 } 37 } 38 return err 39 } 40 41 // 一定抛错 42 func (rf *reconnectFilter) reconnect(connection *DmConnection, reason string) error { 43 // 读写分离,重连需要处理备机 44 var err error 45 if connection.dmConnector.rwSeparate { 46 err = RWUtil.reconnect(connection) 47 } else { 48 err = connection.reconnect() 49 } 50 51 if err != nil { 52 return ECGO_CONNECTION_SWITCH_FAILED.addDetailln(reason).throw() 53 } 54 55 // 重连成功 56 return ECGO_CONNECTION_SWITCHED.addDetailln(reason).throw() 57 } 58 59 func (rf *reconnectFilter) loadDscEpSites(conn *DmConnection) []*ep { 60 stmt, rs, err := conn.driverQuery(SQL_GET_DSC_EP_SITE) 61 if err != nil { 62 return nil 63 } 64 defer func() { 65 rs.close() 66 stmt.close() 67 }() 68 epList := make([]*ep, 0) 69 dest := make([]driver.Value, 4) 70 for err = rs.next(dest); err != io.EOF; err = rs.next(dest) { 71 ep := newEP(dest[1].(string), dest[2].(int32)) 72 ep.epSeqno = dest[0].(int32) 73 if util.StringUtil.EqualsIgnoreCase(dest[3].(string), "OK") { 74 ep.epStatus = EP_STATUS_OK 75 } else { 76 ep.epStatus = EP_STATUS_ERROR 77 } 78 epList = append(epList, ep) 79 } 80 return epList 81 } 82 83 func (rf *reconnectFilter) checkAndRecover(conn *DmConnection) error { 84 if conn.dmConnector.doSwitch != DO_SWITCH_WHEN_EP_RECOVER { 85 return nil 86 } 87 // check trx finish 88 if !conn.trxFinish { 89 return nil 90 } 91 var curIndex = conn.getIndexOnEPGroup() 92 if curIndex == 0 || (time.Now().UnixNano()/1000000-conn.recoverInfo.checkEpRecoverTs) < int64(conn.dmConnector.switchInterval) { 93 return nil 94 } 95 // check db recover 96 var dscEps []*ep 97 if conn.dmConnector.cluster == CLUSTER_TYPE_DSC { 98 dscEps = rf.loadDscEpSites(conn) 99 } 100 if dscEps == nil || len(dscEps) == 0 { 101 return nil 102 } 103 var recover = false 104 for _, okEp := range dscEps { 105 if okEp.epStatus != EP_STATUS_OK { 106 continue 107 } 108 for i := int32(0); i < curIndex; i++ { 109 ep := conn.dmConnector.group.epList[i] 110 if okEp.host == ep.host && okEp.port == ep.port { 111 recover = true 112 break 113 } 114 } 115 if recover { 116 break 117 } 118 } 119 120 conn.recoverInfo.checkEpRecoverTs = time.Now().UnixNano() / 1000000 121 if !recover { 122 return nil 123 } 124 // do reconnect 125 return conn.reconnect() 126 } 127 128 //DmDriver 129 func (rf *reconnectFilter) DmDriverOpen(filterChain *filterChain, d *DmDriver, dsn string) (*DmConnection, error) { 130 return filterChain.DmDriverOpen(d, dsn) 131 } 132 133 func (rf *reconnectFilter) DmDriverOpenConnector(filterChain *filterChain, d *DmDriver, dsn string) (*DmConnector, error) { 134 return filterChain.DmDriverOpenConnector(d, dsn) 135 } 136 137 //DmConnector 138 func (rf *reconnectFilter) DmConnectorConnect(filterChain *filterChain, c *DmConnector, ctx context.Context) (*DmConnection, error) { 139 return filterChain.DmConnectorConnect(c, ctx) 140 } 141 142 func (rf *reconnectFilter) DmConnectorDriver(filterChain *filterChain, c *DmConnector) *DmDriver { 143 return filterChain.DmConnectorDriver(c) 144 } 145 146 //DmConnection 147 func (rf *reconnectFilter) DmConnectionBegin(filterChain *filterChain, c *DmConnection) (*DmConnection, error) { 148 dc, err := filterChain.DmConnectionBegin(c) 149 if err != nil { 150 return nil, rf.autoReconnect(c, err) 151 } 152 return dc, err 153 } 154 155 func (rf *reconnectFilter) DmConnectionBeginTx(filterChain *filterChain, c *DmConnection, ctx context.Context, opts driver.TxOptions) (*DmConnection, error) { 156 dc, err := filterChain.DmConnectionBeginTx(c, ctx, opts) 157 if err != nil { 158 return nil, rf.autoReconnect(c, err) 159 } 160 return dc, err 161 } 162 163 func (rf *reconnectFilter) DmConnectionCommit(filterChain *filterChain, c *DmConnection) error { 164 if err := filterChain.DmConnectionCommit(c); err != nil { 165 return rf.autoReconnect(c, err) 166 } 167 if err := rf.checkAndRecover(c); err != nil { 168 return rf.autoReconnect(c, err) 169 } 170 return nil 171 } 172 173 func (rf *reconnectFilter) DmConnectionRollback(filterChain *filterChain, c *DmConnection) error { 174 err := filterChain.DmConnectionRollback(c) 175 if err != nil { 176 err = rf.autoReconnect(c, err) 177 } 178 179 return err 180 } 181 182 func (rf *reconnectFilter) DmConnectionClose(filterChain *filterChain, c *DmConnection) error { 183 err := filterChain.DmConnectionClose(c) 184 if err != nil { 185 err = rf.autoReconnect(c, err) 186 } 187 188 return err 189 } 190 191 func (rf *reconnectFilter) DmConnectionPing(filterChain *filterChain, c *DmConnection, ctx context.Context) error { 192 err := filterChain.DmConnectionPing(c, ctx) 193 if err != nil { 194 err = rf.autoReconnect(c, err) 195 } 196 197 return err 198 } 199 200 func (rf *reconnectFilter) DmConnectionExec(filterChain *filterChain, c *DmConnection, query string, args []driver.Value) (*DmResult, error) { 201 if err := rf.checkAndRecover(c); err != nil { 202 return nil, rf.autoReconnect(c, err) 203 } 204 dr, err := filterChain.DmConnectionExec(c, query, args) 205 if err != nil { 206 return nil, rf.autoReconnect(c, err) 207 } 208 209 return dr, err 210 } 211 212 func (rf *reconnectFilter) DmConnectionExecContext(filterChain *filterChain, c *DmConnection, ctx context.Context, query string, args []driver.NamedValue) (*DmResult, error) { 213 if err := rf.checkAndRecover(c); err != nil { 214 return nil, rf.autoReconnect(c, err) 215 } 216 dr, err := filterChain.DmConnectionExecContext(c, ctx, query, args) 217 if err != nil { 218 return nil, rf.autoReconnect(c, err) 219 } 220 221 return dr, err 222 } 223 224 func (rf *reconnectFilter) DmConnectionQuery(filterChain *filterChain, c *DmConnection, query string, args []driver.Value) (*DmRows, error) { 225 if err := rf.checkAndRecover(c); err != nil { 226 return nil, rf.autoReconnect(c, err) 227 } 228 dr, err := filterChain.DmConnectionQuery(c, query, args) 229 if err != nil { 230 return nil, rf.autoReconnect(c, err) 231 } 232 233 return dr, err 234 } 235 236 func (rf *reconnectFilter) DmConnectionQueryContext(filterChain *filterChain, c *DmConnection, ctx context.Context, query string, args []driver.NamedValue) (*DmRows, error) { 237 if err := rf.checkAndRecover(c); err != nil { 238 return nil, rf.autoReconnect(c, err) 239 } 240 dr, err := filterChain.DmConnectionQueryContext(c, ctx, query, args) 241 if err != nil { 242 return nil, rf.autoReconnect(c, err) 243 } 244 245 return dr, err 246 } 247 248 func (rf *reconnectFilter) DmConnectionPrepare(filterChain *filterChain, c *DmConnection, query string) (*DmStatement, error) { 249 ds, err := filterChain.DmConnectionPrepare(c, query) 250 if err != nil { 251 return nil, rf.autoReconnect(c, err) 252 } 253 254 return ds, err 255 } 256 257 func (rf *reconnectFilter) DmConnectionPrepareContext(filterChain *filterChain, c *DmConnection, ctx context.Context, query string) (*DmStatement, error) { 258 ds, err := filterChain.DmConnectionPrepareContext(c, ctx, query) 259 if err != nil { 260 return nil, rf.autoReconnect(c, err) 261 } 262 263 return ds, err 264 } 265 266 func (rf *reconnectFilter) DmConnectionResetSession(filterChain *filterChain, c *DmConnection, ctx context.Context) error { 267 err := filterChain.DmConnectionResetSession(c, ctx) 268 if err != nil { 269 err = rf.autoReconnect(c, err) 270 } 271 272 return err 273 } 274 275 func (rf *reconnectFilter) DmConnectionCheckNamedValue(filterChain *filterChain, c *DmConnection, nv *driver.NamedValue) error { 276 err := filterChain.DmConnectionCheckNamedValue(c, nv) 277 if err != nil { 278 err = rf.autoReconnect(c, err) 279 } 280 281 return err 282 } 283 284 //DmStatement 285 func (rf *reconnectFilter) DmStatementClose(filterChain *filterChain, s *DmStatement) error { 286 err := filterChain.DmStatementClose(s) 287 if err != nil { 288 err = rf.autoReconnect(s.dmConn, err) 289 } 290 291 return err 292 } 293 294 func (rf *reconnectFilter) DmStatementNumInput(filterChain *filterChain, s *DmStatement) int { 295 var ret int 296 defer func() { 297 err := recover() 298 if err != nil { 299 rf.autoReconnect(s.dmConn, err.(error)) 300 ret = 0 301 } 302 }() 303 ret = filterChain.DmStatementNumInput(s) 304 return ret 305 } 306 307 func (rf *reconnectFilter) DmStatementExec(filterChain *filterChain, s *DmStatement, args []driver.Value) (*DmResult, error) { 308 if err := rf.checkAndRecover(s.dmConn); err != nil { 309 return nil, rf.autoReconnect(s.dmConn, err) 310 } 311 dr, err := filterChain.DmStatementExec(s, args) 312 if err != nil { 313 return nil, rf.autoReconnect(s.dmConn, err) 314 } 315 316 return dr, err 317 } 318 319 func (rf *reconnectFilter) DmStatementExecContext(filterChain *filterChain, s *DmStatement, ctx context.Context, args []driver.NamedValue) (*DmResult, error) { 320 if err := rf.checkAndRecover(s.dmConn); err != nil { 321 return nil, rf.autoReconnect(s.dmConn, err) 322 } 323 dr, err := filterChain.DmStatementExecContext(s, ctx, args) 324 if err != nil { 325 return nil, rf.autoReconnect(s.dmConn, err) 326 } 327 328 return dr, err 329 } 330 331 func (rf *reconnectFilter) DmStatementQuery(filterChain *filterChain, s *DmStatement, args []driver.Value) (*DmRows, error) { 332 if err := rf.checkAndRecover(s.dmConn); err != nil { 333 return nil, rf.autoReconnect(s.dmConn, err) 334 } 335 dr, err := filterChain.DmStatementQuery(s, args) 336 if err != nil { 337 return nil, rf.autoReconnect(s.dmConn, err) 338 } 339 340 return dr, err 341 } 342 343 func (rf *reconnectFilter) DmStatementQueryContext(filterChain *filterChain, s *DmStatement, ctx context.Context, args []driver.NamedValue) (*DmRows, error) { 344 if err := rf.checkAndRecover(s.dmConn); err != nil { 345 return nil, rf.autoReconnect(s.dmConn, err) 346 } 347 dr, err := filterChain.DmStatementQueryContext(s, ctx, args) 348 if err != nil { 349 return nil, rf.autoReconnect(s.dmConn, err) 350 } 351 352 return dr, err 353 } 354 355 func (rf *reconnectFilter) DmStatementCheckNamedValue(filterChain *filterChain, s *DmStatement, nv *driver.NamedValue) error { 356 err := filterChain.DmStatementCheckNamedValue(s, nv) 357 if err != nil { 358 err = rf.autoReconnect(s.dmConn, err) 359 } 360 361 return err 362 } 363 364 //DmResult 365 func (rf *reconnectFilter) DmResultLastInsertId(filterChain *filterChain, r *DmResult) (int64, error) { 366 i, err := filterChain.DmResultLastInsertId(r) 367 if err != nil { 368 err = rf.autoReconnect(r.dmStmt.dmConn, err) 369 return 0, err 370 } 371 372 return i, err 373 } 374 375 func (rf *reconnectFilter) DmResultRowsAffected(filterChain *filterChain, r *DmResult) (int64, error) { 376 i, err := filterChain.DmResultRowsAffected(r) 377 if err != nil { 378 err = rf.autoReconnect(r.dmStmt.dmConn, err) 379 return 0, err 380 } 381 382 return i, err 383 } 384 385 //DmRows 386 func (rf *reconnectFilter) DmRowsColumns(filterChain *filterChain, r *DmRows) []string { 387 var ret []string 388 defer func() { 389 err := recover() 390 if err != nil { 391 rf.autoReconnect(r.CurrentRows.dmStmt.dmConn, err.(error)) 392 ret = nil 393 } 394 }() 395 ret = filterChain.DmRowsColumns(r) 396 return ret 397 } 398 399 func (rf *reconnectFilter) DmRowsClose(filterChain *filterChain, r *DmRows) error { 400 err := filterChain.DmRowsClose(r) 401 if err != nil { 402 err = rf.autoReconnect(r.CurrentRows.dmStmt.dmConn, err) 403 } 404 405 return err 406 } 407 408 func (rf *reconnectFilter) DmRowsNext(filterChain *filterChain, r *DmRows, dest []driver.Value) error { 409 err := filterChain.DmRowsNext(r, dest) 410 if err != nil { 411 err = rf.autoReconnect(r.CurrentRows.dmStmt.dmConn, err) 412 } 413 414 return err 415 } 416 417 func (rf *reconnectFilter) DmRowsHasNextResultSet(filterChain *filterChain, r *DmRows) bool { 418 var ret bool 419 defer func() { 420 err := recover() 421 if err != nil { 422 rf.autoReconnect(r.CurrentRows.dmStmt.dmConn, err.(error)) 423 ret = false 424 } 425 }() 426 ret = filterChain.DmRowsHasNextResultSet(r) 427 return ret 428 } 429 430 func (rf *reconnectFilter) DmRowsNextResultSet(filterChain *filterChain, r *DmRows) error { 431 err := filterChain.DmRowsNextResultSet(r) 432 if err != nil { 433 err = rf.autoReconnect(r.CurrentRows.dmStmt.dmConn, err) 434 } 435 436 return err 437 } 438 439 func (rf *reconnectFilter) DmRowsColumnTypeScanType(filterChain *filterChain, r *DmRows, index int) reflect.Type { 440 var ret reflect.Type 441 defer func() { 442 err := recover() 443 if err != nil { 444 rf.autoReconnect(r.CurrentRows.dmStmt.dmConn, err.(error)) 445 ret = scanTypeUnknown 446 } 447 }() 448 ret = filterChain.DmRowsColumnTypeScanType(r, index) 449 return ret 450 } 451 452 func (rf *reconnectFilter) DmRowsColumnTypeDatabaseTypeName(filterChain *filterChain, r *DmRows, index int) string { 453 var ret string 454 defer func() { 455 err := recover() 456 if err != nil { 457 rf.autoReconnect(r.CurrentRows.dmStmt.dmConn, err.(error)) 458 ret = "" 459 } 460 }() 461 ret = filterChain.DmRowsColumnTypeDatabaseTypeName(r, index) 462 return ret 463 } 464 465 func (rf *reconnectFilter) DmRowsColumnTypeLength(filterChain *filterChain, r *DmRows, index int) (length int64, ok bool) { 466 defer func() { 467 err := recover() 468 if err != nil { 469 rf.autoReconnect(r.CurrentRows.dmStmt.dmConn, err.(error)) 470 length, ok = 0, false 471 } 472 }() 473 return filterChain.DmRowsColumnTypeLength(r, index) 474 } 475 476 func (rf *reconnectFilter) DmRowsColumnTypeNullable(filterChain *filterChain, r *DmRows, index int) (nullable, ok bool) { 477 defer func() { 478 err := recover() 479 if err != nil { 480 rf.autoReconnect(r.CurrentRows.dmStmt.dmConn, err.(error)) 481 nullable, ok = false, false 482 } 483 }() 484 return filterChain.DmRowsColumnTypeNullable(r, index) 485 } 486 487 func (rf *reconnectFilter) DmRowsColumnTypePrecisionScale(filterChain *filterChain, r *DmRows, index int) (precision, scale int64, ok bool) { 488 defer func() { 489 err := recover() 490 if err != nil { 491 rf.autoReconnect(r.CurrentRows.dmStmt.dmConn, err.(error)) 492 precision, scale, ok = 0, 0, false 493 } 494 }() 495 return filterChain.DmRowsColumnTypePrecisionScale(r, index) 496 }