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