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