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  }