github.com/xiyichan/dm8@v0.0.0-20211213021639-be727be3e136/o.go (about)

     1  /*
     2   * Copyright (c) 2000-2018, 达梦数据库有限公司.
     3   * All rights reserved.
     4   */
     5  package dm
     6  
     7  import (
     8  	"bytes"
     9  	"context"
    10  	"database/sql"
    11  	"database/sql/driver"
    12  	"fmt"
    13  	"github.com/xiyichan/dm8/parser"
    14  	"golang.org/x/text/encoding"
    15  	"sync/atomic"
    16  )
    17  
    18  type DmConnection struct {
    19  	filterable
    20  
    21  	dmConnector        *DmConnector
    22  	Access             *dm_build_1285
    23  	stmtMap            map[int32]*DmStatement
    24  	stmtPool           []stmtPoolInfo
    25  	lastExecInfo       *execInfo
    26  	lexer              *parser.Lexer
    27  	encode             encoding.Encoding
    28  	encodeBuffer       *bytes.Buffer
    29  	transformReaderDst []byte
    30  	transformReaderSrc []byte
    31  
    32  	serverEncoding          string
    33  	GlobalServerSeries      int
    34  	ServerVersion           string
    35  	Malini2                 bool
    36  	Execute2                bool
    37  	LobEmptyCompOrcl        bool
    38  	IsoLevel                int32
    39  	ReadOnly                bool
    40  	NewLobFlag              bool
    41  	sslEncrypt              int
    42  	MaxRowSize              int32
    43  	DDLAutoCommit           bool
    44  	BackslashEscape         bool
    45  	SvrStat                 int16
    46  	SvrMode                 int16
    47  	ConstParaOpt            bool
    48  	DbTimezone              int16
    49  	LifeTimeRemainder       int16
    50  	InstanceName            string
    51  	Schema                  string
    52  	LastLoginIP             string
    53  	LastLoginTime           string
    54  	FailedAttempts          int32
    55  	LoginWarningID          int32
    56  	GraceTimeRemainder      int32
    57  	Guid                    string
    58  	DbName                  string
    59  	StandbyHost             string
    60  	StandbyPort             int32
    61  	StandbyCount            uint16
    62  	SessionID               int64
    63  	OracleDateFormat        string
    64  	OracleTimestampFormat   string
    65  	OracleTimestampTZFormat string
    66  	OracleTimeFormat        string
    67  	OracleTimeTZFormat      string
    68  	OracleDateLanguage      byte
    69  	Local                   bool
    70  	TrxStatus               int32
    71  	trxFinish               bool
    72  	sessionID               int64
    73  	autoCommit              bool
    74  	isBatch                 bool
    75  
    76  	watching bool
    77  	watcher  chan<- context.Context
    78  	closech  chan struct{}
    79  	finished chan<- struct{}
    80  	canceled atomicError
    81  	closed   atomicBool
    82  }
    83  
    84  func (conn *DmConnection) setTrxFinish(status int32) {
    85  	switch status & Dm_build_122 {
    86  	case Dm_build_119, Dm_build_120, Dm_build_121:
    87  		conn.trxFinish = true
    88  	default:
    89  		conn.trxFinish = false
    90  	}
    91  }
    92  
    93  func (dmConn *DmConnection) init() {
    94  	if dmConn.dmConnector.stmtPoolMaxSize > 0 {
    95  		dmConn.stmtPool = make([]stmtPoolInfo, 0, dmConn.dmConnector.stmtPoolMaxSize)
    96  	}
    97  
    98  	dmConn.stmtMap = make(map[int32]*DmStatement)
    99  	dmConn.DbTimezone = 0
   100  	dmConn.GlobalServerSeries = 0
   101  	dmConn.MaxRowSize = 0
   102  	dmConn.LobEmptyCompOrcl = false
   103  	dmConn.ReadOnly = false
   104  	dmConn.DDLAutoCommit = false
   105  	dmConn.ConstParaOpt = false
   106  	dmConn.IsoLevel = -1
   107  	dmConn.sessionID = -1
   108  	dmConn.Malini2 = true
   109  	dmConn.NewLobFlag = true
   110  	dmConn.Execute2 = true
   111  	dmConn.serverEncoding = ENCODING_GB18030
   112  	dmConn.TrxStatus = Dm_build_70
   113  
   114  	dmConn.idGenerator = dmConnIDGenerator
   115  }
   116  
   117  func (dmConn *DmConnection) reset() {
   118  	dmConn.DbTimezone = 0
   119  	dmConn.GlobalServerSeries = 0
   120  	dmConn.MaxRowSize = 0
   121  	dmConn.LobEmptyCompOrcl = false
   122  	dmConn.ReadOnly = false
   123  	dmConn.DDLAutoCommit = false
   124  	dmConn.ConstParaOpt = false
   125  	dmConn.IsoLevel = -1
   126  	dmConn.sessionID = -1
   127  	dmConn.Malini2 = true
   128  	dmConn.NewLobFlag = true
   129  	dmConn.Execute2 = true
   130  	dmConn.serverEncoding = ENCODING_GB18030
   131  	dmConn.TrxStatus = Dm_build_70
   132  }
   133  
   134  func (dc *DmConnection) checkClosed() error {
   135  	if dc.closed.IsSet() {
   136  		return driver.ErrBadConn
   137  	}
   138  
   139  	return nil
   140  }
   141  
   142  func (dc *DmConnection) executeInner(query string, execType int16) (interface{}, error) {
   143  
   144  	stmt, err := NewDmStmt(dc, query)
   145  
   146  	if err != nil {
   147  		return nil, err
   148  	}
   149  
   150  	if execType == Dm_build_87 {
   151  		defer stmt.close()
   152  	}
   153  
   154  	stmt.innerUsed = true
   155  	if stmt.dmConn.dmConnector.escapeProcess {
   156  		stmt.nativeSql, err = stmt.dmConn.escape(stmt.nativeSql, stmt.dmConn.dmConnector.keyWords)
   157  		if err != nil {
   158  			stmt.close()
   159  			return nil, err
   160  		}
   161  	}
   162  
   163  	var optParamList []OptParameter
   164  
   165  	if stmt.dmConn.ConstParaOpt {
   166  		optParamList = make([]OptParameter, 0)
   167  		stmt.nativeSql, optParamList, err = stmt.dmConn.execOpt(stmt.nativeSql, optParamList, stmt.dmConn.getServerEncoding())
   168  		if err != nil {
   169  			stmt.close()
   170  			optParamList = nil
   171  		}
   172  	}
   173  
   174  	if execType == Dm_build_86 && dc.dmConnector.enRsCache {
   175  		rpv, err := rp.get(stmt, query)
   176  		if err != nil {
   177  			return nil, err
   178  		}
   179  
   180  		if rpv != nil {
   181  			stmt.execInfo = rpv.execInfo
   182  			dc.lastExecInfo = rpv.execInfo
   183  			return newDmRows(rpv.getResultSet(stmt)), nil
   184  		}
   185  	}
   186  
   187  	var info *execInfo
   188  
   189  	if optParamList != nil && len(optParamList) > 0 {
   190  		info, err = dc.Access.Dm_build_1363(stmt, optParamList)
   191  		if err != nil {
   192  			stmt.nativeSql = query
   193  			info, err = dc.Access.Dm_build_1369(stmt, execType)
   194  		}
   195  	} else {
   196  		info, err = dc.Access.Dm_build_1369(stmt, execType)
   197  	}
   198  
   199  	dc.lastExecInfo = info
   200  	if err != nil {
   201  		stmt.close()
   202  		return nil, err
   203  	}
   204  
   205  	if info.hasResultSet {
   206  		return newDmRows(newInnerRows(0, stmt, info)), nil
   207  	} else {
   208  		return newDmResult(stmt, info), nil
   209  	}
   210  }
   211  
   212  func g2dbIsoLevel(isoLevel int32) int32 {
   213  	switch isoLevel {
   214  	case 1:
   215  		return Dm_build_74
   216  	case 2:
   217  		return Dm_build_75
   218  	case 4:
   219  		return Dm_build_76
   220  	case 6:
   221  		return Dm_build_77
   222  	default:
   223  		return -1
   224  	}
   225  }
   226  
   227  func (dc *DmConnection) Begin() (driver.Tx, error) {
   228  	if len(dc.filterChain.filters) == 0 {
   229  		return dc.begin()
   230  	} else {
   231  		return dc.filterChain.reset().DmConnectionBegin(dc)
   232  	}
   233  }
   234  
   235  func (dc *DmConnection) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx, error) {
   236  	if len(dc.filterChain.filters) == 0 {
   237  		return dc.beginTx(ctx, opts)
   238  	}
   239  	return dc.filterChain.reset().DmConnectionBeginTx(dc, ctx, opts)
   240  }
   241  
   242  func (dc *DmConnection) Commit() error {
   243  	if len(dc.filterChain.filters) == 0 {
   244  		return dc.commit()
   245  	} else {
   246  		return dc.filterChain.reset().DmConnectionCommit(dc)
   247  	}
   248  }
   249  
   250  func (dc *DmConnection) Rollback() error {
   251  	if len(dc.filterChain.filters) == 0 {
   252  		return dc.rollback()
   253  	} else {
   254  		return dc.filterChain.reset().DmConnectionRollback(dc)
   255  	}
   256  }
   257  
   258  func (dc *DmConnection) Close() error {
   259  	if len(dc.filterChain.filters) == 0 {
   260  		return dc.close()
   261  	} else {
   262  		return dc.filterChain.reset().DmConnectionClose(dc)
   263  	}
   264  }
   265  
   266  func (dc *DmConnection) Ping(ctx context.Context) error {
   267  	if len(dc.filterChain.filters) == 0 {
   268  		return dc.ping(ctx)
   269  	} else {
   270  		return dc.filterChain.reset().DmConnectionPing(dc, ctx)
   271  	}
   272  }
   273  
   274  func (dc *DmConnection) Exec(query string, args []driver.Value) (driver.Result, error) {
   275  	if len(dc.filterChain.filters) == 0 {
   276  		return dc.exec(query, args)
   277  	}
   278  	return dc.filterChain.reset().DmConnectionExec(dc, query, args)
   279  }
   280  
   281  func (dc *DmConnection) ExecContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Result, error) {
   282  	if len(dc.filterChain.filters) == 0 {
   283  		return dc.execContext(ctx, query, args)
   284  	}
   285  	return dc.filterChain.reset().DmConnectionExecContext(dc, ctx, query, args)
   286  }
   287  
   288  func (dc *DmConnection) Query(query string, args []driver.Value) (driver.Rows, error) {
   289  	if len(dc.filterChain.filters) == 0 {
   290  		return dc.query(query, args)
   291  	}
   292  	return dc.filterChain.reset().DmConnectionQuery(dc, query, args)
   293  }
   294  
   295  func (dc *DmConnection) QueryContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Rows, error) {
   296  	if len(dc.filterChain.filters) == 0 {
   297  		return dc.queryContext(ctx, query, args)
   298  	}
   299  	return dc.filterChain.reset().DmConnectionQueryContext(dc, ctx, query, args)
   300  }
   301  
   302  func (dc *DmConnection) Prepare(query string) (driver.Stmt, error) {
   303  	if len(dc.filterChain.filters) == 0 {
   304  		return dc.prepare(query)
   305  	}
   306  	return dc.filterChain.reset().DmConnectionPrepare(dc, query)
   307  }
   308  
   309  func (dc *DmConnection) PrepareContext(ctx context.Context, query string) (driver.Stmt, error) {
   310  	if len(dc.filterChain.filters) == 0 {
   311  		return dc.prepareContext(ctx, query)
   312  	}
   313  	return dc.filterChain.reset().DmConnectionPrepareContext(dc, ctx, query)
   314  }
   315  
   316  func (dc *DmConnection) ResetSession(ctx context.Context) error {
   317  	if len(dc.filterChain.filters) == 0 {
   318  		return dc.resetSession(ctx)
   319  	}
   320  	return dc.filterChain.reset().DmConnectionResetSession(dc, ctx)
   321  }
   322  
   323  func (dc *DmConnection) CheckNamedValue(nv *driver.NamedValue) error {
   324  	if len(dc.filterChain.filters) == 0 {
   325  		return dc.checkNamedValue(nv)
   326  	}
   327  	return dc.filterChain.reset().DmConnectionCheckNamedValue(dc, nv)
   328  }
   329  
   330  func (dc *DmConnection) begin() (*DmConnection, error) {
   331  	return dc.beginTx(context.Background(), driver.TxOptions{driver.IsolationLevel(sql.LevelDefault), false})
   332  }
   333  
   334  func (dc *DmConnection) beginTx(ctx context.Context, opts driver.TxOptions) (*DmConnection, error) {
   335  	err := dc.checkClosed()
   336  	if err != nil {
   337  		return nil, err
   338  	}
   339  
   340  	if err := dc.watchCancel(ctx); err != nil {
   341  		return nil, err
   342  	}
   343  	defer dc.finish()
   344  
   345  	dc.autoCommit = false
   346  
   347  	if sql.IsolationLevel(opts.Isolation) == sql.LevelDefault {
   348  		opts.Isolation = driver.IsolationLevel(sql.LevelReadCommitted)
   349  	}
   350  
   351  	dc.ReadOnly = opts.ReadOnly
   352  
   353  	if dc.IsoLevel == int32(opts.Isolation) {
   354  		return dc, nil
   355  	}
   356  
   357  	switch sql.IsolationLevel(opts.Isolation) {
   358  	case sql.LevelDefault:
   359  		return dc, nil
   360  	case sql.LevelReadUncommitted, sql.LevelReadCommitted, sql.LevelSerializable:
   361  		dc.IsoLevel = int32(opts.Isolation)
   362  	case sql.LevelRepeatableRead:
   363  		if dc.CompatibleMysql() {
   364  			dc.IsoLevel = int32(sql.LevelReadCommitted)
   365  		} else {
   366  			return nil, ECGO_INVALID_TRAN_ISOLATION.throw()
   367  		}
   368  	default:
   369  		return nil, ECGO_INVALID_TRAN_ISOLATION.throw()
   370  	}
   371  
   372  	err = dc.Access.Dm_build_1423(dc)
   373  	if err != nil {
   374  		return nil, err
   375  	}
   376  	return dc, nil
   377  }
   378  
   379  func (dc *DmConnection) commit() error {
   380  	err := dc.checkClosed()
   381  	if err != nil {
   382  		return err
   383  	}
   384  
   385  	defer func() {
   386  		dc.autoCommit = dc.dmConnector.autoCommit
   387  	}()
   388  
   389  	if !dc.autoCommit {
   390  		err = dc.Access.Commit()
   391  		if err != nil {
   392  			return err
   393  		}
   394  		dc.trxFinish = true
   395  		return nil
   396  	} else if !dc.dmConnector.alwayseAllowCommit {
   397  		return ECGO_COMMIT_IN_AUTOCOMMIT_MODE.throw()
   398  	}
   399  
   400  	return nil
   401  }
   402  
   403  func (dc *DmConnection) rollback() error {
   404  	err := dc.checkClosed()
   405  	if err != nil {
   406  		return err
   407  	}
   408  
   409  	defer func() {
   410  		dc.autoCommit = dc.dmConnector.autoCommit
   411  	}()
   412  
   413  	if !dc.autoCommit {
   414  		err = dc.Access.Rollback()
   415  		if err != nil {
   416  			return err
   417  		}
   418  		dc.trxFinish = true
   419  		return nil
   420  	} else if !dc.dmConnector.alwayseAllowCommit {
   421  		return ECGO_ROLLBACK_IN_AUTOCOMMIT_MODE.throw()
   422  	}
   423  
   424  	return nil
   425  }
   426  
   427  func (dc *DmConnection) reconnect() error {
   428  	err := dc.Access.Close()
   429  	if err != nil {
   430  		return err
   431  	}
   432  
   433  	for _, stmt := range dc.stmtMap {
   434  		stmt.closed = true
   435  		for id, _ := range stmt.rsMap {
   436  			delete(stmt.rsMap, id)
   437  		}
   438  	}
   439  
   440  	if dc.stmtPool != nil {
   441  		dc.stmtPool = dc.stmtPool[:0]
   442  	}
   443  
   444  	dc.dmConnector.reConnection = dc
   445  
   446  	if dc.dmConnector.group != nil {
   447  		_, err = dc.dmConnector.group.connect(dc.dmConnector)
   448  		if err != nil {
   449  			return err
   450  		}
   451  	} else {
   452  		_, err = dc.dmConnector.connect(context.Background())
   453  	}
   454  
   455  	for _, stmt := range dc.stmtMap {
   456  		err = dc.Access.Dm_build_1341(stmt)
   457  		if err != nil {
   458  			return err
   459  		}
   460  
   461  		if stmt.paramCount > 0 {
   462  			err = stmt.prepare()
   463  			if err != nil {
   464  				return err
   465  			}
   466  		}
   467  	}
   468  
   469  	return nil
   470  }
   471  
   472  func (dc *DmConnection) close() error {
   473  	if dc.closed.IsSet() {
   474  		return nil
   475  	}
   476  
   477  	close(dc.closech)
   478  	if dc.Access == nil {
   479  		return nil
   480  	}
   481  
   482  	err := dc.rollback()
   483  	if err != nil {
   484  		return err
   485  	}
   486  
   487  	for _, stmt := range dc.stmtMap {
   488  		err = stmt.free()
   489  		if err != nil {
   490  			return err
   491  		}
   492  	}
   493  
   494  	if dc.stmtPool != nil {
   495  		for _, spi := range dc.stmtPool {
   496  			err = dc.Access.Dm_build_1346(spi.id)
   497  			if err != nil {
   498  				return err
   499  			}
   500  		}
   501  		dc.stmtPool = nil
   502  	}
   503  
   504  	err = dc.Access.Close()
   505  	if err != nil {
   506  		return err
   507  	}
   508  
   509  	dc.closed.Set(true)
   510  	return nil
   511  }
   512  
   513  func (dc *DmConnection) ping(ctx context.Context) error {
   514  	rows, err := dc.query("select 1", nil)
   515  	if err != nil {
   516  		return err
   517  	}
   518  	return rows.close()
   519  }
   520  
   521  func (dc *DmConnection) exec(query string, args []driver.Value) (*DmResult, error) {
   522  	err := dc.checkClosed()
   523  	if err != nil {
   524  		return nil, err
   525  	}
   526  
   527  	if args != nil && len(args) > 0 {
   528  		stmt, err := dc.prepare(query)
   529  		dc.lastExecInfo = stmt.execInfo
   530  		defer stmt.close()
   531  		if err != nil {
   532  			return nil, err
   533  		}
   534  
   535  		return stmt.exec(args)
   536  	} else {
   537  		r1, err := dc.executeInner(query, Dm_build_87)
   538  		if err != nil {
   539  			return nil, err
   540  		}
   541  
   542  		if r2, ok := r1.(*DmResult); ok {
   543  			return r2, nil
   544  		} else {
   545  			return nil, ECGO_NOT_EXEC_SQL.throw()
   546  		}
   547  	}
   548  }
   549  
   550  func (dc *DmConnection) execContext(ctx context.Context, query string, args []driver.NamedValue) (*DmResult, error) {
   551  
   552  	err := dc.checkClosed()
   553  	if err != nil {
   554  		return nil, err
   555  	}
   556  
   557  	if err := dc.watchCancel(ctx); err != nil {
   558  		return nil, err
   559  	}
   560  	defer dc.finish()
   561  
   562  	if args != nil && len(args) > 0 {
   563  		stmt, err := dc.prepare(query)
   564  		dc.lastExecInfo = stmt.execInfo
   565  		defer stmt.close()
   566  		if err != nil {
   567  			return nil, err
   568  		}
   569  
   570  		return stmt.execContext(ctx, args)
   571  	} else {
   572  		r1, err := dc.executeInner(query, Dm_build_87)
   573  		if err != nil {
   574  			return nil, err
   575  		}
   576  
   577  		if r2, ok := r1.(*DmResult); ok {
   578  			return r2, nil
   579  		} else {
   580  			return nil, ECGO_NOT_EXEC_SQL.throw()
   581  		}
   582  	}
   583  }
   584  
   585  func (dc *DmConnection) query(query string, args []driver.Value) (*DmRows, error) {
   586  
   587  	err := dc.checkClosed()
   588  	if err != nil {
   589  		return nil, err
   590  	}
   591  
   592  	if args != nil && len(args) > 0 {
   593  		stmt, err := dc.prepare(query)
   594  		dc.lastExecInfo = stmt.execInfo
   595  		if err != nil {
   596  			stmt.close()
   597  			return nil, err
   598  		}
   599  
   600  		stmt.innerUsed = true
   601  		return stmt.query(args)
   602  
   603  	} else {
   604  		r1, err := dc.executeInner(query, Dm_build_86)
   605  		if err != nil {
   606  			return nil, err
   607  		}
   608  
   609  		if r2, ok := r1.(*DmRows); ok {
   610  			return r2, nil
   611  		} else {
   612  			return nil, ECGO_NOT_QUERY_SQL.throw()
   613  		}
   614  	}
   615  }
   616  
   617  func (dc *DmConnection) queryContext(ctx context.Context, query string, args []driver.NamedValue) (*DmRows, error) {
   618  
   619  	err := dc.checkClosed()
   620  	if err != nil {
   621  		return nil, err
   622  	}
   623  
   624  	if err := dc.watchCancel(ctx); err != nil {
   625  		return nil, err
   626  	}
   627  	defer dc.finish()
   628  
   629  	if args != nil && len(args) > 0 {
   630  		stmt, err := dc.prepare(query)
   631  		dc.lastExecInfo = stmt.execInfo
   632  		if err != nil {
   633  			stmt.close()
   634  			return nil, err
   635  		}
   636  
   637  		stmt.innerUsed = true
   638  		return stmt.queryContext(ctx, args)
   639  
   640  	} else {
   641  		r1, err := dc.executeInner(query, Dm_build_86)
   642  		if err != nil {
   643  			return nil, err
   644  		}
   645  
   646  		if r2, ok := r1.(*DmRows); ok {
   647  			return r2, nil
   648  		} else {
   649  			return nil, ECGO_NOT_QUERY_SQL.throw()
   650  		}
   651  	}
   652  
   653  }
   654  
   655  func (dc *DmConnection) prepare(query string) (*DmStatement, error) {
   656  	err := dc.checkClosed()
   657  	if err != nil {
   658  		return nil, err
   659  	}
   660  
   661  	stmt, err := NewDmStmt(dc, query)
   662  	if err != nil {
   663  		return nil, err
   664  	}
   665  
   666  	err = stmt.prepare()
   667  	return stmt, err
   668  }
   669  
   670  func (dc *DmConnection) prepareContext(ctx context.Context, query string) (*DmStatement, error) {
   671  	err := dc.checkClosed()
   672  	if err != nil {
   673  		return nil, err
   674  	}
   675  
   676  	if err := dc.watchCancel(ctx); err != nil {
   677  		return nil, err
   678  	}
   679  	defer dc.finish()
   680  
   681  	stmt, err := dc.prepare(query)
   682  	if err != nil {
   683  		return nil, err
   684  	}
   685  
   686  	return stmt, nil
   687  }
   688  
   689  func (dc *DmConnection) resetSession(ctx context.Context) error {
   690  	err := dc.checkClosed()
   691  	if err != nil {
   692  		return err
   693  	}
   694  
   695  	for _, stmt := range dc.stmtMap {
   696  		stmt.inUse = false
   697  	}
   698  
   699  	return nil
   700  }
   701  
   702  func (dc *DmConnection) checkNamedValue(nv *driver.NamedValue) error {
   703  	var err error
   704  	var cvt = converter{dc, false}
   705  	nv.Value, err = cvt.ConvertValue(nv.Value)
   706  	dc.isBatch = cvt.isBatch
   707  	return err
   708  }
   709  
   710  func (dc *DmConnection) getServerEncoding() string {
   711  	if dc.dmConnector.charCode != "" {
   712  		return dc.dmConnector.charCode
   713  	}
   714  	return dc.serverEncoding
   715  }
   716  
   717  func (dc *DmConnection) lobFetchAll() bool {
   718  	return dc.dmConnector.lobMode == 2
   719  }
   720  
   721  func (conn *DmConnection) CompatibleOracle() bool {
   722  	return conn.dmConnector.compatibleMode == COMPATIBLE_MODE_ORACLE
   723  }
   724  
   725  func (conn *DmConnection) CompatibleMysql() bool {
   726  	return conn.dmConnector.compatibleMode == COMPATIBLE_MODE_MYSQL
   727  }
   728  
   729  func (conn *DmConnection) cancel(err error) {
   730  	conn.canceled.Set(err)
   731  	fmt.Println(conn.close())
   732  }
   733  
   734  func (conn *DmConnection) finish() {
   735  	if !conn.watching || conn.finished == nil {
   736  		return
   737  	}
   738  	select {
   739  	case conn.finished <- struct{}{}:
   740  		conn.watching = false
   741  	case <-conn.closech:
   742  	}
   743  }
   744  
   745  func (conn *DmConnection) startWatcher() {
   746  	watcher := make(chan context.Context, 1)
   747  	conn.watcher = watcher
   748  	finished := make(chan struct{})
   749  	conn.finished = finished
   750  	go func() {
   751  		for {
   752  			var ctx context.Context
   753  			select {
   754  			case ctx = <-watcher:
   755  			case <-conn.closech:
   756  				return
   757  			}
   758  
   759  			select {
   760  			case <-ctx.Done():
   761  				conn.cancel(ctx.Err())
   762  			case <-finished:
   763  			case <-conn.closech:
   764  				return
   765  			}
   766  		}
   767  	}()
   768  }
   769  
   770  func (conn *DmConnection) watchCancel(ctx context.Context) error {
   771  	if conn.watching {
   772  
   773  		return conn.close()
   774  	}
   775  
   776  	if err := ctx.Err(); err != nil {
   777  		return err
   778  	}
   779  
   780  	if ctx.Done() == nil {
   781  		return nil
   782  	}
   783  
   784  	if conn.watcher == nil {
   785  		return nil
   786  	}
   787  
   788  	conn.watching = true
   789  	conn.watcher <- ctx
   790  	return nil
   791  }
   792  
   793  type noCopy struct{}
   794  
   795  func (*noCopy) Lock() {}
   796  
   797  type atomicBool struct {
   798  	_noCopy noCopy
   799  	value   uint32
   800  }
   801  
   802  func (ab *atomicBool) IsSet() bool {
   803  	return atomic.LoadUint32(&ab.value) > 0
   804  }
   805  
   806  func (ab *atomicBool) Set(value bool) {
   807  	if value {
   808  		atomic.StoreUint32(&ab.value, 1)
   809  	} else {
   810  		atomic.StoreUint32(&ab.value, 0)
   811  	}
   812  }
   813  
   814  func (ab *atomicBool) TrySet(value bool) bool {
   815  	if value {
   816  		return atomic.SwapUint32(&ab.value, 1) == 0
   817  	}
   818  	return atomic.SwapUint32(&ab.value, 0) > 0
   819  }
   820  
   821  type atomicError struct {
   822  	_noCopy noCopy
   823  	value   atomic.Value
   824  }
   825  
   826  func (ae *atomicError) Set(value error) {
   827  	ae.value.Store(value)
   828  }
   829  
   830  func (ae *atomicError) Value() error {
   831  	if v := ae.value.Load(); v != nil {
   832  
   833  		return v.(error)
   834  	}
   835  	return nil
   836  }