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  }