github.com/whtcorpsinc/MilevaDB-Prod@v0.0.0-20211104133533-f57f4be3b597/causetstore/stochastik/session.go (about)

     1  // Copyright 2020 The ql Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSES/QL-LICENSE file.
     4  
     5  // Copyright 2020 WHTCORPS INC, Inc.
     6  //
     7  // Licensed under the Apache License, Version 2.0 (the "License");
     8  // you may not use this file except in compliance with the License.
     9  // You may obtain a copy of the License at
    10  //
    11  //     http://www.apache.org/licenses/LICENSE-2.0
    12  //
    13  // Unless required by applicable law or agreed to in writing, software
    14  // distributed under the License is distributed on an "AS IS" BASIS,
    15  // See the License for the specific language governing permissions and
    16  // limitations under the License.
    17  
    18  package stochastik
    19  
    20  import (
    21  	"context"
    22  	"crypto/tls"
    23  	"encoding/json"
    24  	"fmt"
    25  	"net"
    26  	"runtime/trace"
    27  	"strconv"
    28  	"strings"
    29  	"sync"
    30  	"sync/atomic"
    31  	"time"
    32  
    33  	"github.com/ngaut/pools"
    34  	"github.com/opentracing/opentracing-go"
    35  	"github.com/whtcorpsinc/BerolinaSQL"
    36  	"github.com/whtcorpsinc/BerolinaSQL/allegrosql"
    37  	"github.com/whtcorpsinc/BerolinaSQL/ast"
    38  	"github.com/whtcorpsinc/BerolinaSQL/auth"
    39  	"github.com/whtcorpsinc/BerolinaSQL/charset"
    40  	"github.com/whtcorpsinc/BerolinaSQL/perceptron"
    41  	"github.com/whtcorpsinc/BerolinaSQL/terror"
    42  	"github.com/whtcorpsinc/errors"
    43  	"github.com/whtcorpsinc/failpoint"
    44  	"github.com/whtcorpsinc/fidelpb/go-binlog"
    45  	"github.com/whtcorpsinc/milevadb/bindinfo"
    46  	"github.com/whtcorpsinc/milevadb/causet"
    47  	causetembedded "github.com/whtcorpsinc/milevadb/causet/embedded"
    48  	"github.com/whtcorpsinc/milevadb/causetstore/einsteindb"
    49  	"github.com/whtcorpsinc/milevadb/config"
    50  	"github.com/whtcorpsinc/milevadb/ekv"
    51  	"github.com/whtcorpsinc/milevadb/interlock"
    52  	"github.com/whtcorpsinc/milevadb/metrics"
    53  	"github.com/whtcorpsinc/milevadb/petri"
    54  	"github.com/whtcorpsinc/milevadb/plugin"
    55  	"github.com/whtcorpsinc/milevadb/privilege"
    56  	"github.com/whtcorpsinc/milevadb/privilege/privileges"
    57  	"github.com/whtcorpsinc/milevadb/schemareplicant"
    58  	"github.com/whtcorpsinc/milevadb/soliton"
    59  	"github.com/whtcorpsinc/milevadb/soliton/chunk"
    60  	"github.com/whtcorpsinc/milevadb/soliton/collate"
    61  	"github.com/whtcorpsinc/milevadb/soliton/ekvcache"
    62  	"github.com/whtcorpsinc/milevadb/soliton/execdetails"
    63  	"github.com/whtcorpsinc/milevadb/soliton/logutil"
    64  	"github.com/whtcorpsinc/milevadb/soliton/sqlexec"
    65  	"github.com/whtcorpsinc/milevadb/soliton/timeutil"
    66  	"github.com/whtcorpsinc/milevadb/spacetime"
    67  	"github.com/whtcorpsinc/milevadb/statistics/handle"
    68  	"github.com/whtcorpsinc/milevadb/stochastikctx"
    69  	"github.com/whtcorpsinc/milevadb/stochastikctx/binloginfo"
    70  	"github.com/whtcorpsinc/milevadb/stochastikctx/stmtctx"
    71  	"github.com/whtcorpsinc/milevadb/stochastikctx/variable"
    72  	"github.com/whtcorpsinc/milevadb/tenant"
    73  	"github.com/whtcorpsinc/milevadb/types"
    74  	"go.uber.org/zap"
    75  )
    76  
    77  var (
    78  	memexPerTransactionPessimisticOK     = metrics.StatementPerTransaction.WithLabelValues(metrics.LblPessimistic, metrics.LblOK)
    79  	memexPerTransactionPessimisticError  = metrics.StatementPerTransaction.WithLabelValues(metrics.LblPessimistic, metrics.LblError)
    80  	memexPerTransactionOptimisticOK      = metrics.StatementPerTransaction.WithLabelValues(metrics.LblOptimistic, metrics.LblOK)
    81  	memexPerTransactionOptimisticError   = metrics.StatementPerTransaction.WithLabelValues(metrics.LblOptimistic, metrics.LblError)
    82  	transactionDurationPessimisticCommit = metrics.TransactionDuration.WithLabelValues(metrics.LblPessimistic, metrics.LblCommit)
    83  	transactionDurationPessimisticAbort  = metrics.TransactionDuration.WithLabelValues(metrics.LblPessimistic, metrics.LblAbort)
    84  	transactionDurationOptimisticCommit  = metrics.TransactionDuration.WithLabelValues(metrics.LblOptimistic, metrics.LblCommit)
    85  	transactionDurationOptimisticAbort   = metrics.TransactionDuration.WithLabelValues(metrics.LblOptimistic, metrics.LblAbort)
    86  
    87  	stochastikInterDircuteCompileDurationInternal = metrics.StochastikInterDircuteCompileDuration.WithLabelValues(metrics.LblInternal)
    88  	stochastikInterDircuteCompileDurationGeneral  = metrics.StochastikInterDircuteCompileDuration.WithLabelValues(metrics.LblGeneral)
    89  	stochastikInterDircuteParseDurationInternal   = metrics.StochastikInterDircuteParseDuration.WithLabelValues(metrics.LblInternal)
    90  	stochastikInterDircuteParseDurationGeneral    = metrics.StochastikInterDircuteParseDuration.WithLabelValues(metrics.LblGeneral)
    91  )
    92  
    93  // Stochastik context, it is consistent with the lifecycle of a client connection.
    94  type Stochastik interface {
    95  	stochastikctx.Context
    96  	Status() uint16       // Flag of current status, such as autocommit.
    97  	LastInsertID() uint64 // LastInsertID is the last inserted auto_increment ID.
    98  	LastMessage() string  // LastMessage is the info message that may be generated by last command
    99  	AffectedRows() uint64 // Affected rows by latest executed stmt.
   100  	// InterDircute is deprecated, use InterDircuteStmt() instead.
   101  	InterDircute(context.Context, string) ([]sqlexec.RecordSet, error)         // InterDircute a allegrosql memex.
   102  	InterDircuteInternal(context.Context, string) ([]sqlexec.RecordSet, error) // InterDircute a internal allegrosql memex.
   103  	InterDircuteStmt(context.Context, ast.StmtNode) (sqlexec.RecordSet, error)
   104  	Parse(ctx context.Context, allegrosql string) ([]ast.StmtNode, error)
   105  	String() string // String is used to debug.
   106  	CommitTxn(context.Context) error
   107  	RollbackTxn(context.Context)
   108  	// PrepareStmt executes prepare memex in binary protocol.
   109  	PrepareStmt(allegrosql string) (stmtID uint32, paramCount int, fields []*ast.ResultField, err error)
   110  	// InterDircutePreparedStmt executes a prepared memex.
   111  	InterDircutePreparedStmt(ctx context.Context, stmtID uint32, param []types.Causet) (sqlexec.RecordSet, error)
   112  	DropPreparedStmt(stmtID uint32) error
   113  	SetClientCapability(uint32) // Set client capability flags.
   114  	SetConnectionID(uint64)
   115  	SetCommandValue(byte)
   116  	SetProcessInfo(string, time.Time, byte, uint64)
   117  	SetTLSState(*tls.ConnectionState)
   118  	SetDefCauslation(coID int) error
   119  	SetStochastikManager(soliton.StochastikManager)
   120  	Close()
   121  	Auth(user *auth.UserIdentity, auth []byte, salt []byte) bool
   122  	AuthWithoutVerification(user *auth.UserIdentity) bool
   123  	ShowProcess() *soliton.ProcessInfo
   124  	// PrepareTxnCtx is exported for test.
   125  	PrepareTxnCtx(context.Context)
   126  	// FieldList returns fields list of a causet.
   127  	FieldList(blockName string) (fields []*ast.ResultField, err error)
   128  }
   129  
   130  var (
   131  	_ Stochastik = (*stochastik)(nil)
   132  )
   133  
   134  type stmtRecord struct {
   135  	st      sqlexec.Statement
   136  	stmtCtx *stmtctx.StatementContext
   137  }
   138  
   139  // StmtHistory holds all histories of memexs in a txn.
   140  type StmtHistory struct {
   141  	history []*stmtRecord
   142  }
   143  
   144  // Add appends a stmt to history list.
   145  func (h *StmtHistory) Add(st sqlexec.Statement, stmtCtx *stmtctx.StatementContext) {
   146  	s := &stmtRecord{
   147  		st:      st,
   148  		stmtCtx: stmtCtx,
   149  	}
   150  	h.history = append(h.history, s)
   151  }
   152  
   153  // Count returns the count of the history.
   154  func (h *StmtHistory) Count() int {
   155  	return len(h.history)
   156  }
   157  
   158  type stochastik struct {
   159  	// processInfo is used by ShowProcess(), and should be modified atomically.
   160  	processInfo atomic.Value
   161  	txn         TxnState
   162  
   163  	mu struct {
   164  		sync.RWMutex
   165  		values map[fmt.Stringer]interface{}
   166  	}
   167  
   168  	currentCtx    context.Context // only use for runtime.trace, Please NEVER use it.
   169  	currentCauset causetembedded.Causet
   170  
   171  	causetstore ekv.CausetStorage
   172  
   173  	BerolinaSQL *BerolinaSQL.BerolinaSQL
   174  
   175  	preparedCausetCache *ekvcache.SimpleLRUCache
   176  
   177  	stochastikVars    *variable.StochastikVars
   178  	stochastikManager soliton.StochastikManager
   179  
   180  	statsDefCauslector *handle.StochastikStatsDefCauslector
   181  	// dbsTenantChecker is used in `select milevadb_is_dbs_tenant()` memex;
   182  	dbsTenantChecker tenant.DBSTenantChecker
   183  	// lockedTables use to record the causet locks hold by the stochastik.
   184  	lockedTables map[int64]perceptron.TableLockTpInfo
   185  
   186  	// client shared interlock client per stochastik
   187  	client ekv.Client
   188  }
   189  
   190  // AddTableLock adds causet dagger to the stochastik dagger map.
   191  func (s *stochastik) AddTableLock(locks []perceptron.TableLockTpInfo) {
   192  	for _, l := range locks {
   193  		s.lockedTables[l.TableID] = l
   194  	}
   195  }
   196  
   197  // ReleaseTableLocks releases causet dagger in the stochastik dagger map.
   198  func (s *stochastik) ReleaseTableLocks(locks []perceptron.TableLockTpInfo) {
   199  	for _, l := range locks {
   200  		delete(s.lockedTables, l.TableID)
   201  	}
   202  }
   203  
   204  // ReleaseTableLockByTableIDs releases causet dagger in the stochastik dagger map by causet ID.
   205  func (s *stochastik) ReleaseTableLockByTableIDs(blockIDs []int64) {
   206  	for _, tblID := range blockIDs {
   207  		delete(s.lockedTables, tblID)
   208  	}
   209  }
   210  
   211  // CheckTableLocked checks the causet dagger.
   212  func (s *stochastik) CheckTableLocked(tblID int64) (bool, perceptron.TableLockType) {
   213  	lt, ok := s.lockedTables[tblID]
   214  	if !ok {
   215  		return false, perceptron.TableLockNone
   216  	}
   217  	return true, lt.Tp
   218  }
   219  
   220  // GetAllTableLocks gets all causet locks causet id and EDB id hold by the stochastik.
   221  func (s *stochastik) GetAllTableLocks() []perceptron.TableLockTpInfo {
   222  	lockTpInfo := make([]perceptron.TableLockTpInfo, 0, len(s.lockedTables))
   223  	for _, tl := range s.lockedTables {
   224  		lockTpInfo = append(lockTpInfo, tl)
   225  	}
   226  	return lockTpInfo
   227  }
   228  
   229  // HasLockedTables uses to check whether this stochastik locked any blocks.
   230  // If so, the stochastik can only visit the causet which locked by self.
   231  func (s *stochastik) HasLockedTables() bool {
   232  	b := len(s.lockedTables) > 0
   233  	return b
   234  }
   235  
   236  // ReleaseAllTableLocks releases all causet locks hold by the stochastik.
   237  func (s *stochastik) ReleaseAllTableLocks() {
   238  	s.lockedTables = make(map[int64]perceptron.TableLockTpInfo)
   239  }
   240  
   241  // DBSTenantChecker returns s.dbsTenantChecker.
   242  func (s *stochastik) DBSTenantChecker() tenant.DBSTenantChecker {
   243  	return s.dbsTenantChecker
   244  }
   245  
   246  func (s *stochastik) cleanRetryInfo() {
   247  	if s.stochastikVars.RetryInfo.Retrying {
   248  		return
   249  	}
   250  
   251  	retryInfo := s.stochastikVars.RetryInfo
   252  	defer retryInfo.Clean()
   253  	if len(retryInfo.DroppedPreparedStmtIDs) == 0 {
   254  		return
   255  	}
   256  
   257  	planCacheEnabled := causetembedded.PreparedCausetCacheEnabled()
   258  	var cacheKey ekvcache.Key
   259  	var preparedAst *ast.Prepared
   260  	if planCacheEnabled {
   261  		firstStmtID := retryInfo.DroppedPreparedStmtIDs[0]
   262  		if preparedPointer, ok := s.stochastikVars.PreparedStmts[firstStmtID]; ok {
   263  			preparedObj, ok := preparedPointer.(*causetembedded.CachedPrepareStmt)
   264  			if ok {
   265  				preparedAst = preparedObj.PreparedAst
   266  				cacheKey = causetembedded.NewPSTMTCausetCacheKey(s.stochastikVars, firstStmtID, preparedAst.SchemaVersion)
   267  			}
   268  		}
   269  	}
   270  	for i, stmtID := range retryInfo.DroppedPreparedStmtIDs {
   271  		if planCacheEnabled {
   272  			if i > 0 && preparedAst != nil {
   273  				causetembedded.SetPstmtIDSchemaVersion(cacheKey, stmtID, preparedAst.SchemaVersion, s.stochastikVars.IsolationReadEngines)
   274  			}
   275  			s.PreparedCausetCache().Delete(cacheKey)
   276  		}
   277  		s.stochastikVars.RemovePreparedStmt(stmtID)
   278  	}
   279  }
   280  
   281  func (s *stochastik) Status() uint16 {
   282  	return s.stochastikVars.Status
   283  }
   284  
   285  func (s *stochastik) LastInsertID() uint64 {
   286  	if s.stochastikVars.StmtCtx.LastInsertID > 0 {
   287  		return s.stochastikVars.StmtCtx.LastInsertID
   288  	}
   289  	return s.stochastikVars.StmtCtx.InsertID
   290  }
   291  
   292  func (s *stochastik) LastMessage() string {
   293  	return s.stochastikVars.StmtCtx.GetMessage()
   294  }
   295  
   296  func (s *stochastik) AffectedRows() uint64 {
   297  	return s.stochastikVars.StmtCtx.AffectedRows()
   298  }
   299  
   300  func (s *stochastik) SetClientCapability(capability uint32) {
   301  	s.stochastikVars.ClientCapability = capability
   302  }
   303  
   304  func (s *stochastik) SetConnectionID(connectionID uint64) {
   305  	s.stochastikVars.ConnectionID = connectionID
   306  }
   307  
   308  func (s *stochastik) SetTLSState(tlsState *tls.ConnectionState) {
   309  	// If user is not connected via TLS, then tlsState == nil.
   310  	if tlsState != nil {
   311  		s.stochastikVars.TLSConnectionState = tlsState
   312  	}
   313  }
   314  
   315  func (s *stochastik) SetCommandValue(command byte) {
   316  	atomic.StoreUint32(&s.stochastikVars.CommandValue, uint32(command))
   317  }
   318  
   319  func (s *stochastik) SetDefCauslation(coID int) error {
   320  	cs, co, err := charset.GetCharsetInfoByID(coID)
   321  	if err != nil {
   322  		return err
   323  	}
   324  	for _, v := range variable.SetNamesVariables {
   325  		terror.Log(s.stochastikVars.SetSystemVar(v, cs))
   326  	}
   327  	return s.stochastikVars.SetSystemVar(variable.DefCauslationConnection, co)
   328  }
   329  
   330  func (s *stochastik) PreparedCausetCache() *ekvcache.SimpleLRUCache {
   331  	return s.preparedCausetCache
   332  }
   333  
   334  func (s *stochastik) SetStochastikManager(sm soliton.StochastikManager) {
   335  	s.stochastikManager = sm
   336  }
   337  
   338  func (s *stochastik) GetStochastikManager() soliton.StochastikManager {
   339  	return s.stochastikManager
   340  }
   341  
   342  func (s *stochastik) StoreQueryFeedback(feedback interface{}) {
   343  	if s.statsDefCauslector != nil {
   344  		do, err := GetPetri(s.causetstore)
   345  		if err != nil {
   346  			logutil.BgLogger().Debug("petri not found", zap.Error(err))
   347  			metrics.StoreQueryFeedbackCounter.WithLabelValues(metrics.LblError).Inc()
   348  			return
   349  		}
   350  		err = s.statsDefCauslector.StoreQueryFeedback(feedback, do.StatsHandle())
   351  		if err != nil {
   352  			logutil.BgLogger().Debug("causetstore query feedback", zap.Error(err))
   353  			metrics.StoreQueryFeedbackCounter.WithLabelValues(metrics.LblError).Inc()
   354  			return
   355  		}
   356  		metrics.StoreQueryFeedbackCounter.WithLabelValues(metrics.LblOK).Inc()
   357  	}
   358  }
   359  
   360  // FieldList returns fields list of a causet.
   361  func (s *stochastik) FieldList(blockName string) ([]*ast.ResultField, error) {
   362  	is := schemareplicant.GetSchemaReplicant(s)
   363  	dbName := perceptron.NewCIStr(s.GetStochastikVars().CurrentDB)
   364  	tName := perceptron.NewCIStr(blockName)
   365  	pm := privilege.GetPrivilegeManager(s)
   366  	if pm != nil && s.stochastikVars.User != nil {
   367  		if !pm.RequestVerification(s.stochastikVars.ActiveRoles, dbName.O, tName.O, "", allegrosql.AllPrivMask) {
   368  			user := s.stochastikVars.User
   369  			u := user.Username
   370  			h := user.Hostname
   371  			if len(user.AuthUsername) > 0 && len(user.AuthHostname) > 0 {
   372  				u = user.AuthUsername
   373  				h = user.AuthHostname
   374  			}
   375  			return nil, causetembedded.ErrTableaccessDenied.GenWithStackByArgs("SELECT", u, h, blockName)
   376  		}
   377  	}
   378  	causet, err := is.TableByName(dbName, tName)
   379  	if err != nil {
   380  		return nil, err
   381  	}
   382  
   383  	defcaus := causet.DefCauss()
   384  	fields := make([]*ast.ResultField, 0, len(defcaus))
   385  	for _, col := range causet.DefCauss() {
   386  		rf := &ast.ResultField{
   387  			DeferredCausetAsName: col.Name,
   388  			TableAsName:          tName,
   389  			DBName:               dbName,
   390  			Block:                causet.Meta(),
   391  			DeferredCauset:       col.DeferredCausetInfo,
   392  		}
   393  		fields = append(fields, rf)
   394  	}
   395  	return fields, nil
   396  }
   397  
   398  func (s *stochastik) doCommit(ctx context.Context) error {
   399  	if !s.txn.Valid() {
   400  		return nil
   401  	}
   402  	defer func() {
   403  		s.txn.changeToInvalid()
   404  		s.stochastikVars.SetStatusFlag(allegrosql.ServerStatusInTrans, false)
   405  	}()
   406  	if s.txn.IsReadOnly() {
   407  		return nil
   408  	}
   409  
   410  	// mockCommitError and mockGetTSErrorInRetry use to test PR #8743.
   411  	failpoint.Inject("mockCommitError", func(val failpoint.Value) {
   412  		if val.(bool) && ekv.IsMockCommitErrorEnable() {
   413  			ekv.MockCommitErrorDisable()
   414  			failpoint.Return(ekv.ErrTxnRetryable)
   415  		}
   416  	})
   417  
   418  	if s.stochastikVars.BinlogClient != nil {
   419  		prewriteValue := binloginfo.GetPrewriteValue(s, false)
   420  		if prewriteValue != nil {
   421  			prewriteData, err := prewriteValue.Marshal()
   422  			if err != nil {
   423  				return errors.Trace(err)
   424  			}
   425  			info := &binloginfo.BinlogInfo{
   426  				Data: &binlog.Binlog{
   427  					Tp:            binlog.BinlogType_Prewrite,
   428  					PrewriteValue: prewriteData,
   429  				},
   430  				Client: s.stochastikVars.BinlogClient,
   431  			}
   432  			s.txn.SetOption(ekv.BinlogInfo, info)
   433  		}
   434  	}
   435  
   436  	// Get the related causet or partition IDs.
   437  	relatedPhysicalTables := s.GetStochastikVars().TxnCtx.TableDeltaMap
   438  	physicalTableIDs := make([]int64, 0, len(relatedPhysicalTables))
   439  	for id := range relatedPhysicalTables {
   440  		physicalTableIDs = append(physicalTableIDs, id)
   441  	}
   442  	// Set this option for 2 phase commit to validate schemaReplicant lease.
   443  	s.txn.SetOption(ekv.SchemaChecker, petri.NewSchemaChecker(petri.GetPetri(s), s.stochastikVars.TxnCtx.SchemaVersion, physicalTableIDs))
   444  	s.txn.SetOption(ekv.SchemaReplicant, s.stochastikVars.TxnCtx.SchemaReplicant)
   445  	s.txn.SetOption(ekv.CommitHook, func(info ekv.TxnInfo, _ error) { s.stochastikVars.LastTxnInfo = info })
   446  	if s.GetStochastikVars().EnableAmendPessimisticTxn {
   447  		s.txn.SetOption(ekv.SchemaAmender, NewSchemaAmenderForEinsteinDBTxn(s))
   448  	}
   449  
   450  	return s.txn.Commit(stochastikctx.SetCommitCtx(ctx, s))
   451  }
   452  
   453  func (s *stochastik) doCommitWithRetry(ctx context.Context) error {
   454  	defer func() {
   455  		s.GetStochastikVars().SetTxnIsolationLevelOneShotStateForNextTxn()
   456  		s.txn.changeToInvalid()
   457  		s.cleanRetryInfo()
   458  	}()
   459  	if !s.txn.Valid() {
   460  		// If the transaction is invalid, maybe it has already been rolled back by the client.
   461  		return nil
   462  	}
   463  	txnSize := s.txn.Size()
   464  	isPessimistic := s.txn.IsPessimistic()
   465  	if span := opentracing.SpanFromContext(ctx); span != nil && span.Tracer() != nil {
   466  		span1 := span.Tracer().StartSpan("stochastik.doCommitWitRetry", opentracing.ChildOf(span.Context()))
   467  		defer span1.Finish()
   468  		ctx = opentracing.ContextWithSpan(ctx, span1)
   469  	}
   470  	err := s.doCommit(ctx)
   471  	if err != nil {
   472  		commitRetryLimit := s.stochastikVars.RetryLimit
   473  		if !s.stochastikVars.TxnCtx.CouldRetry {
   474  			commitRetryLimit = 0
   475  		}
   476  		// Don't retry in BatchInsert mode. As a counter-example, insert into t1 select * from t2,
   477  		// BatchInsert already commit the first batch 1000 rows, then it commit 1000-2000 and retry the memex,
   478  		// Finally t1 will have more data than t2, with no errors return to user!
   479  		if s.isTxnRetryableError(err) && !s.stochastikVars.BatchInsert && commitRetryLimit > 0 && !isPessimistic {
   480  			logutil.Logger(ctx).Warn("allegrosql",
   481  				zap.String("label", s.getALLEGROSQLLabel()),
   482  				zap.Error(err),
   483  				zap.String("txn", s.txn.GoString()))
   484  			// Transactions will retry 2 ~ commitRetryLimit times.
   485  			// We make larger transactions retry less times to prevent cluster resource outage.
   486  			txnSizeRate := float64(txnSize) / float64(ekv.TxnTotalSizeLimit)
   487  			maxRetryCount := commitRetryLimit - int64(float64(commitRetryLimit-1)*txnSizeRate)
   488  			err = s.retry(ctx, uint(maxRetryCount))
   489  		} else {
   490  			logutil.Logger(ctx).Warn("can not retry txn",
   491  				zap.String("label", s.getALLEGROSQLLabel()),
   492  				zap.Error(err),
   493  				zap.Bool("IsBatchInsert", s.stochastikVars.BatchInsert),
   494  				zap.Bool("IsPessimistic", isPessimistic),
   495  				zap.Bool("InRestrictedALLEGROSQL", s.stochastikVars.InRestrictedALLEGROSQL),
   496  				zap.Int64("milevadb_retry_limit", s.stochastikVars.RetryLimit),
   497  				zap.Bool("milevadb_disable_txn_auto_retry", s.stochastikVars.DisableTxnAutoRetry))
   498  		}
   499  	}
   500  	counter := s.stochastikVars.TxnCtx.StatementCount
   501  	duration := time.Since(s.GetStochastikVars().TxnCtx.CreateTime).Seconds()
   502  	s.recordOnTransactionInterDircution(err, counter, duration)
   503  
   504  	if err != nil {
   505  		logutil.Logger(ctx).Warn("commit failed",
   506  			zap.String("finished txn", s.txn.GoString()),
   507  			zap.Error(err))
   508  		return err
   509  	}
   510  	mapper := s.GetStochastikVars().TxnCtx.TableDeltaMap
   511  	if s.statsDefCauslector != nil && mapper != nil {
   512  		for id, item := range mapper {
   513  			s.statsDefCauslector.UFIDelate(id, item.Delta, item.Count, &item.DefCausSize)
   514  		}
   515  	}
   516  	return nil
   517  }
   518  
   519  func (s *stochastik) CommitTxn(ctx context.Context) error {
   520  	if span := opentracing.SpanFromContext(ctx); span != nil && span.Tracer() != nil {
   521  		span1 := span.Tracer().StartSpan("stochastik.CommitTxn", opentracing.ChildOf(span.Context()))
   522  		defer span1.Finish()
   523  		ctx = opentracing.ContextWithSpan(ctx, span1)
   524  	}
   525  
   526  	var commitDetail *execdetails.CommitDetails
   527  	ctx = context.WithValue(ctx, execdetails.CommitDetailCtxKey, &commitDetail)
   528  	err := s.doCommitWithRetry(ctx)
   529  	if commitDetail != nil {
   530  		s.stochastikVars.StmtCtx.MergeInterDircDetails(nil, commitDetail)
   531  	}
   532  
   533  	failpoint.Inject("keepHistory", func(val failpoint.Value) {
   534  		if val.(bool) {
   535  			failpoint.Return(err)
   536  		}
   537  	})
   538  
   539  	s.stochastikVars.TxnCtx.Cleanup()
   540  	return err
   541  }
   542  
   543  func (s *stochastik) RollbackTxn(ctx context.Context) {
   544  	if span := opentracing.SpanFromContext(ctx); span != nil && span.Tracer() != nil {
   545  		span1 := span.Tracer().StartSpan("stochastik.RollbackTxn", opentracing.ChildOf(span.Context()))
   546  		defer span1.Finish()
   547  	}
   548  
   549  	if s.txn.Valid() {
   550  		terror.Log(s.txn.Rollback())
   551  	}
   552  	if ctx.Value(inCloseStochastik{}) == nil {
   553  		s.cleanRetryInfo()
   554  	}
   555  	s.txn.changeToInvalid()
   556  	s.stochastikVars.TxnCtx.Cleanup()
   557  	s.stochastikVars.SetStatusFlag(allegrosql.ServerStatusInTrans, false)
   558  }
   559  
   560  func (s *stochastik) GetClient() ekv.Client {
   561  	return s.client
   562  }
   563  
   564  func (s *stochastik) String() string {
   565  	// TODO: how to print binded context in values appropriately?
   566  	sessVars := s.stochastikVars
   567  	data := map[string]interface{}{
   568  		"id":         sessVars.ConnectionID,
   569  		"user":       sessVars.User,
   570  		"currDBName": sessVars.CurrentDB,
   571  		"status":     sessVars.Status,
   572  		"strictMode": sessVars.StrictALLEGROSQLMode,
   573  	}
   574  	if s.txn.Valid() {
   575  		// if txn is committed or rolled back, txn is nil.
   576  		data["txn"] = s.txn.String()
   577  	}
   578  	if sessVars.SnapshotTS != 0 {
   579  		data["snapshotTS"] = sessVars.SnapshotTS
   580  	}
   581  	if sessVars.StmtCtx.LastInsertID > 0 {
   582  		data["lastInsertID"] = sessVars.StmtCtx.LastInsertID
   583  	}
   584  	if len(sessVars.PreparedStmts) > 0 {
   585  		data["preparedStmtCount"] = len(sessVars.PreparedStmts)
   586  	}
   587  	b, err := json.MarshalIndent(data, "", "  ")
   588  	terror.Log(errors.Trace(err))
   589  	return string(b)
   590  }
   591  
   592  const sqlLogMaxLen = 1024
   593  
   594  // SchemaChangedWithoutRetry is used for testing.
   595  var SchemaChangedWithoutRetry uint32
   596  
   597  func (s *stochastik) getALLEGROSQLLabel() string {
   598  	if s.stochastikVars.InRestrictedALLEGROSQL {
   599  		return metrics.LblInternal
   600  	}
   601  	return metrics.LblGeneral
   602  }
   603  
   604  func (s *stochastik) isInternal() bool {
   605  	return s.stochastikVars.InRestrictedALLEGROSQL
   606  }
   607  
   608  func (s *stochastik) isTxnRetryableError(err error) bool {
   609  	if atomic.LoadUint32(&SchemaChangedWithoutRetry) == 1 {
   610  		return ekv.IsTxnRetryableError(err)
   611  	}
   612  	return ekv.IsTxnRetryableError(err) || petri.ErrSchemaReplicantChanged.Equal(err)
   613  }
   614  
   615  func (s *stochastik) checkTxnAborted(stmt sqlexec.Statement) error {
   616  	var err error
   617  	if atomic.LoadUint32(&s.GetStochastikVars().TxnCtx.LockExpire) > 0 {
   618  		err = einsteindb.ErrLockExpire
   619  	} else {
   620  		return nil
   621  	}
   622  	// If the transaction is aborted, the following memexs do not need to execute, except `commit` and `rollback`,
   623  	// because they are used to finish the aborted transaction.
   624  	if _, ok := stmt.(*interlock.InterDircStmt).StmtNode.(*ast.CommitStmt); ok {
   625  		return nil
   626  	}
   627  	if _, ok := stmt.(*interlock.InterDircStmt).StmtNode.(*ast.RollbackStmt); ok {
   628  		return nil
   629  	}
   630  	return err
   631  }
   632  
   633  func (s *stochastik) retry(ctx context.Context, maxCnt uint) (err error) {
   634  	var retryCnt uint
   635  	defer func() {
   636  		s.stochastikVars.RetryInfo.Retrying = false
   637  		// retryCnt only increments on retryable error, so +1 here.
   638  		metrics.StochastikRetry.Observe(float64(retryCnt + 1))
   639  		s.stochastikVars.SetStatusFlag(allegrosql.ServerStatusInTrans, false)
   640  		if err != nil {
   641  			s.RollbackTxn(ctx)
   642  		}
   643  		s.txn.changeToInvalid()
   644  	}()
   645  
   646  	connID := s.stochastikVars.ConnectionID
   647  	s.stochastikVars.RetryInfo.Retrying = true
   648  	if atomic.LoadUint32(&s.stochastikVars.TxnCtx.ForUFIDelate) == 1 {
   649  		err = ErrForUFIDelateCantRetry.GenWithStackByArgs(connID)
   650  		return err
   651  	}
   652  
   653  	nh := GetHistory(s)
   654  	var schemaVersion int64
   655  	sessVars := s.GetStochastikVars()
   656  	orgStartTS := sessVars.TxnCtx.StartTS
   657  	label := s.getALLEGROSQLLabel()
   658  	for {
   659  		s.PrepareTxnCtx(ctx)
   660  		s.stochastikVars.RetryInfo.ResetOffset()
   661  		for i, sr := range nh.history {
   662  			st := sr.st
   663  			s.stochastikVars.StmtCtx = sr.stmtCtx
   664  			s.stochastikVars.StmtCtx.ResetForRetry()
   665  			s.stochastikVars.PreparedParams = s.stochastikVars.PreparedParams[:0]
   666  			schemaVersion, err = st.RebuildCauset(ctx)
   667  			if err != nil {
   668  				return err
   669  			}
   670  
   671  			if retryCnt == 0 {
   672  				// We do not have to log the query every time.
   673  				// We print the queries at the first try only.
   674  				allegrosql := sqlForLog(st.GetTextToLog())
   675  				if !config.RedactLogEnabled() {
   676  					allegrosql += sessVars.PreparedParams.String()
   677  				}
   678  				logutil.Logger(ctx).Warn("retrying",
   679  					zap.Int64("schemaVersion", schemaVersion),
   680  					zap.Uint("retryCnt", retryCnt),
   681  					zap.Int("queryNum", i),
   682  					zap.String("allegrosql", allegrosql))
   683  			} else {
   684  				logutil.Logger(ctx).Warn("retrying",
   685  					zap.Int64("schemaVersion", schemaVersion),
   686  					zap.Uint("retryCnt", retryCnt),
   687  					zap.Int("queryNum", i))
   688  			}
   689  			_, err = st.InterDirc(ctx)
   690  			if err != nil {
   691  				s.StmtRollback()
   692  				break
   693  			}
   694  			s.StmtCommit()
   695  		}
   696  		logutil.Logger(ctx).Warn("transaction association",
   697  			zap.Uint64("retrying txnStartTS", s.GetStochastikVars().TxnCtx.StartTS),
   698  			zap.Uint64("original txnStartTS", orgStartTS))
   699  		failpoint.Inject("preCommitHook", func() {
   700  			hook, ok := ctx.Value("__preCommitHook").(func())
   701  			if ok {
   702  				hook()
   703  			}
   704  		})
   705  		if err == nil {
   706  			err = s.doCommit(ctx)
   707  			if err == nil {
   708  				break
   709  			}
   710  		}
   711  		if !s.isTxnRetryableError(err) {
   712  			logutil.Logger(ctx).Warn("allegrosql",
   713  				zap.String("label", label),
   714  				zap.Stringer("stochastik", s),
   715  				zap.Error(err))
   716  			metrics.StochastikRetryErrorCounter.WithLabelValues(label, metrics.LblUnretryable).Inc()
   717  			return err
   718  		}
   719  		retryCnt++
   720  		if retryCnt >= maxCnt {
   721  			logutil.Logger(ctx).Warn("allegrosql",
   722  				zap.String("label", label),
   723  				zap.Uint("retry reached max count", retryCnt))
   724  			metrics.StochastikRetryErrorCounter.WithLabelValues(label, metrics.LblReachMax).Inc()
   725  			return err
   726  		}
   727  		logutil.Logger(ctx).Warn("allegrosql",
   728  			zap.String("label", label),
   729  			zap.Error(err),
   730  			zap.String("txn", s.txn.GoString()))
   731  		ekv.BackOff(retryCnt)
   732  		s.txn.changeToInvalid()
   733  		s.stochastikVars.SetStatusFlag(allegrosql.ServerStatusInTrans, false)
   734  	}
   735  	return err
   736  }
   737  
   738  func sqlForLog(allegrosql string) string {
   739  	if len(allegrosql) > sqlLogMaxLen {
   740  		allegrosql = allegrosql[:sqlLogMaxLen] + fmt.Sprintf("(len:%d)", len(allegrosql))
   741  	}
   742  	return interlock.QueryReplacer.Replace(allegrosql)
   743  }
   744  
   745  type stochastikPool interface {
   746  	Get() (pools.Resource, error)
   747  	Put(pools.Resource)
   748  }
   749  
   750  func (s *stochastik) sysStochastikPool() stochastikPool {
   751  	return petri.GetPetri(s).SysStochastikPool()
   752  }
   753  
   754  // InterDircRestrictedALLEGROSQL implements RestrictedALLEGROSQLInterlockingDirectorate interface.
   755  // This is used for executing some restricted allegrosql memexs, usually executed during a normal memex execution.
   756  // Unlike normal InterDirc, it doesn't reset memex status, doesn't commit or rollback the current transaction
   757  // and doesn't write binlog.
   758  func (s *stochastik) InterDircRestrictedALLEGROSQL(allegrosql string) ([]chunk.Row, []*ast.ResultField, error) {
   759  	return s.InterDircRestrictedALLEGROSQLWithContext(context.TODO(), allegrosql)
   760  }
   761  
   762  // InterDircRestrictedALLEGROSQLWithContext implements RestrictedALLEGROSQLInterlockingDirectorate interface.
   763  func (s *stochastik) InterDircRestrictedALLEGROSQLWithContext(ctx context.Context, allegrosql string) ([]chunk.Row, []*ast.ResultField, error) {
   764  	// Use special stochastik to execute the allegrosql.
   765  	tmp, err := s.sysStochastikPool().Get()
   766  	if err != nil {
   767  		return nil, nil, err
   768  	}
   769  	se := tmp.(*stochastik)
   770  	// The special stochastik will share the `InspectionTableCache` with current stochastik
   771  	// if the current stochastik in inspection mode.
   772  	if cache := s.stochastikVars.InspectionTableCache; cache != nil {
   773  		se.stochastikVars.InspectionTableCache = cache
   774  		defer func() { se.stochastikVars.InspectionTableCache = nil }()
   775  	}
   776  	if ok := s.stochastikVars.OptimizerUseInvisibleIndexes; ok {
   777  		se.stochastikVars.OptimizerUseInvisibleIndexes = true
   778  		defer func() { se.stochastikVars.OptimizerUseInvisibleIndexes = false }()
   779  	}
   780  	defer func() {
   781  		if se != nil && se.GetStochastikVars().StmtCtx.WarningCount() > 0 {
   782  			warnings := se.GetStochastikVars().StmtCtx.GetWarnings()
   783  			s.GetStochastikVars().StmtCtx.AppendWarnings(warnings)
   784  		}
   785  		s.sysStochastikPool().Put(tmp)
   786  	}()
   787  	metrics.StochastikRestrictedALLEGROSQLCounter.Inc()
   788  
   789  	return execRestrictedALLEGROSQL(ctx, se, allegrosql)
   790  }
   791  
   792  // InterDircRestrictedALLEGROSQLWithSnapshot implements RestrictedALLEGROSQLInterlockingDirectorate interface.
   793  // This is used for executing some restricted allegrosql memexs with snapshot.
   794  // If current stochastik sets the snapshot timestamp, then execute with this snapshot timestamp.
   795  // Otherwise, execute with the current transaction start timestamp if the transaction is valid.
   796  func (s *stochastik) InterDircRestrictedALLEGROSQLWithSnapshot(allegrosql string) ([]chunk.Row, []*ast.ResultField, error) {
   797  	ctx := context.TODO()
   798  
   799  	// Use special stochastik to execute the allegrosql.
   800  	tmp, err := s.sysStochastikPool().Get()
   801  	if err != nil {
   802  		return nil, nil, err
   803  	}
   804  	se := tmp.(*stochastik)
   805  	// The special stochastik will share the `InspectionTableCache` with current stochastik
   806  	// if the current stochastik in inspection mode.
   807  	if cache := s.stochastikVars.InspectionTableCache; cache != nil {
   808  		se.stochastikVars.InspectionTableCache = cache
   809  		defer func() { se.stochastikVars.InspectionTableCache = nil }()
   810  	}
   811  	defer s.sysStochastikPool().Put(tmp)
   812  	metrics.StochastikRestrictedALLEGROSQLCounter.Inc()
   813  	var snapshot uint64
   814  	txn, err := s.Txn(false)
   815  	if err != nil {
   816  		return nil, nil, err
   817  	}
   818  	if txn.Valid() {
   819  		snapshot = s.txn.StartTS()
   820  	}
   821  	if s.stochastikVars.SnapshotTS != 0 {
   822  		snapshot = s.stochastikVars.SnapshotTS
   823  	}
   824  	// Set snapshot.
   825  	if snapshot != 0 {
   826  		se.stochastikVars.SnapshotschemaReplicant, err = petri.GetPetri(s).GetSnapshotSchemaReplicant(snapshot)
   827  		if err != nil {
   828  			return nil, nil, err
   829  		}
   830  		if err := se.stochastikVars.SetSystemVar(variable.MilevaDBSnapshot, strconv.FormatUint(snapshot, 10)); err != nil {
   831  			return nil, nil, err
   832  		}
   833  		defer func() {
   834  			if err := se.stochastikVars.SetSystemVar(variable.MilevaDBSnapshot, ""); err != nil {
   835  				logutil.BgLogger().Error("set milevadbSnapshot error", zap.Error(err))
   836  			}
   837  			se.stochastikVars.SnapshotschemaReplicant = nil
   838  		}()
   839  	}
   840  	if ok := s.stochastikVars.OptimizerUseInvisibleIndexes; ok {
   841  		se.stochastikVars.OptimizerUseInvisibleIndexes = true
   842  		defer func() { se.stochastikVars.OptimizerUseInvisibleIndexes = false }()
   843  	}
   844  	return execRestrictedALLEGROSQL(ctx, se, allegrosql)
   845  }
   846  
   847  func execRestrictedALLEGROSQL(ctx context.Context, se *stochastik, allegrosql string) ([]chunk.Row, []*ast.ResultField, error) {
   848  	ctx = context.WithValue(ctx, execdetails.StmtInterDircDetailKey, &execdetails.StmtInterDircDetails{})
   849  	startTime := time.Now()
   850  	recordSets, err := se.InterDircute(ctx, allegrosql)
   851  	if err != nil {
   852  		return nil, nil, err
   853  	}
   854  
   855  	var (
   856  		rows   []chunk.Row
   857  		fields []*ast.ResultField
   858  	)
   859  	// InterDircute all recordset, take out the first one as result.
   860  	for i, rs := range recordSets {
   861  		tmp, err := drainRecordSet(ctx, se, rs)
   862  		if err != nil {
   863  			return nil, nil, err
   864  		}
   865  		if err = rs.Close(); err != nil {
   866  			return nil, nil, err
   867  		}
   868  
   869  		if i == 0 {
   870  			rows = tmp
   871  			fields = rs.Fields()
   872  		}
   873  	}
   874  	metrics.QueryDurationHistogram.WithLabelValues(metrics.LblInternal).Observe(time.Since(startTime).Seconds())
   875  	return rows, fields, nil
   876  }
   877  
   878  func createStochastikFunc(causetstore ekv.CausetStorage) pools.Factory {
   879  	return func() (pools.Resource, error) {
   880  		se, err := createStochastik(causetstore)
   881  		if err != nil {
   882  			return nil, err
   883  		}
   884  		err = variable.SetStochastikSystemVar(se.stochastikVars, variable.AutoCommit, types.NewStringCauset("1"))
   885  		if err != nil {
   886  			return nil, err
   887  		}
   888  		err = variable.SetStochastikSystemVar(se.stochastikVars, variable.MaxInterDircutionTime, types.NewUintCauset(0))
   889  		if err != nil {
   890  			return nil, errors.Trace(err)
   891  		}
   892  		err = variable.SetStochastikSystemVar(se.stochastikVars, variable.MaxAllowedPacket, types.NewStringCauset("67108864"))
   893  		if err != nil {
   894  			return nil, errors.Trace(err)
   895  		}
   896  		se.stochastikVars.CommonGlobalLoaded = true
   897  		se.stochastikVars.InRestrictedALLEGROSQL = true
   898  		return se, nil
   899  	}
   900  }
   901  
   902  func createStochastikWithPetriFunc(causetstore ekv.CausetStorage) func(*petri.Petri) (pools.Resource, error) {
   903  	return func(dom *petri.Petri) (pools.Resource, error) {
   904  		se, err := CreateStochastikWithPetri(causetstore, dom)
   905  		if err != nil {
   906  			return nil, err
   907  		}
   908  		err = variable.SetStochastikSystemVar(se.stochastikVars, variable.AutoCommit, types.NewStringCauset("1"))
   909  		if err != nil {
   910  			return nil, err
   911  		}
   912  		err = variable.SetStochastikSystemVar(se.stochastikVars, variable.MaxInterDircutionTime, types.NewUintCauset(0))
   913  		if err != nil {
   914  			return nil, errors.Trace(err)
   915  		}
   916  		se.stochastikVars.CommonGlobalLoaded = true
   917  		se.stochastikVars.InRestrictedALLEGROSQL = true
   918  		return se, nil
   919  	}
   920  }
   921  
   922  func drainRecordSet(ctx context.Context, se *stochastik, rs sqlexec.RecordSet) ([]chunk.Row, error) {
   923  	var rows []chunk.Row
   924  	req := rs.NewChunk()
   925  	for {
   926  		err := rs.Next(ctx, req)
   927  		if err != nil || req.NumRows() == 0 {
   928  			return rows, err
   929  		}
   930  		iter := chunk.NewIterator4Chunk(req)
   931  		for r := iter.Begin(); r != iter.End(); r = iter.Next() {
   932  			rows = append(rows, r)
   933  		}
   934  		req = chunk.Renew(req, se.stochastikVars.MaxChunkSize)
   935  	}
   936  }
   937  
   938  // getInterDircRet executes restricted allegrosql and the result is one column.
   939  // It returns a string value.
   940  func (s *stochastik) getInterDircRet(ctx stochastikctx.Context, allegrosql string) (string, error) {
   941  	rows, fields, err := s.InterDircRestrictedALLEGROSQL(allegrosql)
   942  	if err != nil {
   943  		return "", err
   944  	}
   945  	if len(rows) == 0 {
   946  		return "", interlock.ErrResultIsEmpty
   947  	}
   948  	d := rows[0].GetCauset(0, &fields[0].DeferredCauset.FieldType)
   949  	value, err := d.ToString()
   950  	if err != nil {
   951  		return "", err
   952  	}
   953  	return value, nil
   954  }
   955  
   956  // GetAllSysVars implements GlobalVarAccessor.GetAllSysVars interface.
   957  func (s *stochastik) GetAllSysVars() (map[string]string, error) {
   958  	if s.Value(stochastikctx.Initing) != nil {
   959  		return nil, nil
   960  	}
   961  	allegrosql := `SELECT VARIABLE_NAME, VARIABLE_VALUE FROM %s.%s;`
   962  	allegrosql = fmt.Sprintf(allegrosql, allegrosql.SystemDB, allegrosql.GlobalVariablesTable)
   963  	rows, _, err := s.InterDircRestrictedALLEGROSQL(allegrosql)
   964  	if err != nil {
   965  		return nil, err
   966  	}
   967  	ret := make(map[string]string, len(rows))
   968  	for _, r := range rows {
   969  		k, v := r.GetString(0), r.GetString(1)
   970  		ret[k] = v
   971  	}
   972  	return ret, nil
   973  }
   974  
   975  // GetGlobalSysVar implements GlobalVarAccessor.GetGlobalSysVar interface.
   976  func (s *stochastik) GetGlobalSysVar(name string) (string, error) {
   977  	if s.Value(stochastikctx.Initing) != nil {
   978  		// When running bootstrap or upgrade, we should not access global storage.
   979  		return "", nil
   980  	}
   981  	allegrosql := fmt.Sprintf(`SELECT VARIABLE_VALUE FROM %s.%s WHERE VARIABLE_NAME="%s";`,
   982  		allegrosql.SystemDB, allegrosql.GlobalVariablesTable, name)
   983  	sysVar, err := s.getInterDircRet(s, allegrosql)
   984  	if err != nil {
   985  		if interlock.ErrResultIsEmpty.Equal(err) {
   986  			if sv, ok := variable.SysVars[name]; ok {
   987  				return sv.Value, nil
   988  			}
   989  			return "", variable.ErrUnknownSystemVar.GenWithStackByArgs(name)
   990  		}
   991  		return "", err
   992  	}
   993  	return sysVar, nil
   994  }
   995  
   996  // SetGlobalSysVar implements GlobalVarAccessor.SetGlobalSysVar interface.
   997  func (s *stochastik) SetGlobalSysVar(name, value string) error {
   998  	if name == variable.ALLEGROSQLModeVar {
   999  		value = allegrosql.FormatALLEGROSQLModeStr(value)
  1000  		if _, err := allegrosql.GetALLEGROSQLMode(value); err != nil {
  1001  			return err
  1002  		}
  1003  	}
  1004  	var sVal string
  1005  	var err error
  1006  	sVal, err = variable.ValidateSetSystemVar(s.stochastikVars, name, value, variable.ScopeGlobal)
  1007  	if err != nil {
  1008  		return err
  1009  	}
  1010  	name = strings.ToLower(name)
  1011  	variable.CheckDeprecationSetSystemVar(s.stochastikVars, name)
  1012  	allegrosql := fmt.Sprintf(`REPLACE %s.%s VALUES ('%s', '%s');`,
  1013  		allegrosql.SystemDB, allegrosql.GlobalVariablesTable, name, sVal)
  1014  	_, _, err = s.InterDircRestrictedALLEGROSQL(allegrosql)
  1015  	return err
  1016  }
  1017  
  1018  func (s *stochastik) ParseALLEGROSQL(ctx context.Context, allegrosql, charset, collation string) ([]ast.StmtNode, []error, error) {
  1019  	if span := opentracing.SpanFromContext(ctx); span != nil && span.Tracer() != nil {
  1020  		span1 := span.Tracer().StartSpan("stochastik.ParseALLEGROSQL", opentracing.ChildOf(span.Context()))
  1021  		defer span1.Finish()
  1022  	}
  1023  	defer trace.StartRegion(ctx, "ParseALLEGROSQL").End()
  1024  	s.BerolinaSQL.SetALLEGROSQLMode(s.stochastikVars.ALLEGROSQLMode)
  1025  	s.BerolinaSQL.EnableWindowFunc(s.stochastikVars.EnableWindowFunction)
  1026  	return s.BerolinaSQL.Parse(allegrosql, charset, collation)
  1027  }
  1028  
  1029  func (s *stochastik) SetProcessInfo(allegrosql string, t time.Time, command byte, maxInterDircutionTime uint64) {
  1030  	// If command == allegrosql.ComSleep, it means the ALLEGROALLEGROSQL execution is finished. The processinfo is reset to SLEEP.
  1031  	// If the ALLEGROALLEGROSQL finished and the stochastik is not in transaction, the current start timestamp need to reset to 0.
  1032  	// Otherwise, it should be set to the transaction start timestamp.
  1033  	// Why not reset the transaction start timestamp to 0 when transaction committed?
  1034  	// Because the select memex and other memexs need this timestamp to read data,
  1035  	// after the transaction is committed. e.g. SHOW MASTER STATUS;
  1036  	var curTxnStartTS uint64
  1037  	if command != allegrosql.ComSleep || s.GetStochastikVars().InTxn() {
  1038  		curTxnStartTS = s.stochastikVars.TxnCtx.StartTS
  1039  	}
  1040  	pi := soliton.ProcessInfo{
  1041  		ID:                    s.stochastikVars.ConnectionID,
  1042  		EDB:                   s.stochastikVars.CurrentDB,
  1043  		Command:               command,
  1044  		Causet:                s.currentCauset,
  1045  		CausetExplainRows:     causetembedded.GetExplainRowsForCauset(s.currentCauset),
  1046  		Time:                  t,
  1047  		State:                 s.Status(),
  1048  		Info:                  allegrosql,
  1049  		CurTxnStartTS:         curTxnStartTS,
  1050  		StmtCtx:               s.stochastikVars.StmtCtx,
  1051  		StatsInfo:             causetembedded.GetStatsInfo,
  1052  		MaxInterDircutionTime: maxInterDircutionTime,
  1053  	}
  1054  	_, pi.Digest = s.stochastikVars.StmtCtx.ALLEGROSQLDigest()
  1055  	if s.stochastikVars.User != nil {
  1056  		pi.User = s.stochastikVars.User.Username
  1057  		pi.Host = s.stochastikVars.User.Hostname
  1058  	}
  1059  	s.processInfo.CausetStore(&pi)
  1060  }
  1061  
  1062  func (s *stochastik) InterDircuteInternal(ctx context.Context, allegrosql string) (recordSets []sqlexec.RecordSet, err error) {
  1063  	origin := s.stochastikVars.InRestrictedALLEGROSQL
  1064  	s.stochastikVars.InRestrictedALLEGROSQL = true
  1065  	defer func() {
  1066  		s.stochastikVars.InRestrictedALLEGROSQL = origin
  1067  	}()
  1068  	return s.InterDircute(ctx, allegrosql)
  1069  }
  1070  
  1071  func (s *stochastik) InterDircute(ctx context.Context, allegrosql string) (recordSets []sqlexec.RecordSet, err error) {
  1072  	if span := opentracing.SpanFromContext(ctx); span != nil && span.Tracer() != nil {
  1073  		span1 := span.Tracer().StartSpan("stochastik.InterDircute", opentracing.ChildOf(span.Context()))
  1074  		defer span1.Finish()
  1075  		ctx = opentracing.ContextWithSpan(ctx, span1)
  1076  		logutil.Eventf(ctx, "execute: %s", allegrosql)
  1077  	}
  1078  
  1079  	stmtNodes, err := s.Parse(ctx, allegrosql)
  1080  	if err != nil {
  1081  		return nil, err
  1082  	}
  1083  	if len(stmtNodes) != 1 {
  1084  		return nil, errors.New("InterDircute() API doesn't support multiple memexs any more")
  1085  	}
  1086  
  1087  	rs, err := s.InterDircuteStmt(ctx, stmtNodes[0])
  1088  	if err != nil {
  1089  		s.stochastikVars.StmtCtx.AppendError(err)
  1090  	}
  1091  	if rs == nil {
  1092  		return nil, err
  1093  	}
  1094  	return []sqlexec.RecordSet{rs}, err
  1095  }
  1096  
  1097  // Parse parses a query string to raw ast.StmtNode.
  1098  func (s *stochastik) Parse(ctx context.Context, allegrosql string) ([]ast.StmtNode, error) {
  1099  	charsetInfo, collation := s.stochastikVars.GetCharsetInfo()
  1100  	parseStartTime := time.Now()
  1101  	stmts, warns, err := s.ParseALLEGROSQL(ctx, allegrosql, charsetInfo, collation)
  1102  	if err != nil {
  1103  		s.rollbackOnError(ctx)
  1104  
  1105  		// Only print log message when this ALLEGROALLEGROSQL is from the user.
  1106  		// Mute the warning for internal ALLEGROSQLs.
  1107  		if !s.stochastikVars.InRestrictedALLEGROSQL {
  1108  			logutil.Logger(ctx).Warn("parse ALLEGROALLEGROSQL failed", zap.Error(err), zap.String("ALLEGROALLEGROSQL", allegrosql))
  1109  		}
  1110  		return nil, soliton.SyntaxError(err)
  1111  	}
  1112  
  1113  	durParse := time.Since(parseStartTime)
  1114  	s.GetStochastikVars().DurationParse = durParse
  1115  	isInternal := s.isInternal()
  1116  	if isInternal {
  1117  		stochastikInterDircuteParseDurationInternal.Observe(durParse.Seconds())
  1118  	} else {
  1119  		stochastikInterDircuteParseDurationGeneral.Observe(durParse.Seconds())
  1120  	}
  1121  	for _, warn := range warns {
  1122  		s.stochastikVars.StmtCtx.AppendWarning(soliton.SyntaxWarn(warn))
  1123  	}
  1124  	return stmts, nil
  1125  }
  1126  
  1127  func (s *stochastik) InterDircuteStmt(ctx context.Context, stmtNode ast.StmtNode) (sqlexec.RecordSet, error) {
  1128  	if span := opentracing.SpanFromContext(ctx); span != nil && span.Tracer() != nil {
  1129  		span1 := span.Tracer().StartSpan("stochastik.InterDircuteStmt", opentracing.ChildOf(span.Context()))
  1130  		defer span1.Finish()
  1131  		ctx = opentracing.ContextWithSpan(ctx, span1)
  1132  	}
  1133  
  1134  	s.PrepareTxnCtx(ctx)
  1135  	err := s.loadCommonGlobalVariablesIfNeeded()
  1136  	if err != nil {
  1137  		return nil, err
  1138  	}
  1139  
  1140  	s.stochastikVars.StartTime = time.Now()
  1141  
  1142  	// Some executions are done in compile stage, so we reset them before compile.
  1143  	if err := interlock.ResetContextOfStmt(s, stmtNode); err != nil {
  1144  		return nil, err
  1145  	}
  1146  
  1147  	// Transform abstract syntax tree to a physical plan(stored in interlock.InterDircStmt).
  1148  	compiler := interlock.Compiler{Ctx: s}
  1149  	stmt, err := compiler.Compile(ctx, stmtNode)
  1150  	if err != nil {
  1151  		s.rollbackOnError(ctx)
  1152  
  1153  		// Only print log message when this ALLEGROALLEGROSQL is from the user.
  1154  		// Mute the warning for internal ALLEGROSQLs.
  1155  		if !s.stochastikVars.InRestrictedALLEGROSQL {
  1156  			logutil.Logger(ctx).Warn("compile ALLEGROALLEGROSQL failed", zap.Error(err), zap.String("ALLEGROALLEGROSQL", stmtNode.Text()))
  1157  		}
  1158  		return nil, err
  1159  	}
  1160  	durCompile := time.Since(s.stochastikVars.StartTime)
  1161  	s.GetStochastikVars().DurationCompile = durCompile
  1162  	if s.isInternal() {
  1163  		stochastikInterDircuteCompileDurationInternal.Observe(durCompile.Seconds())
  1164  	} else {
  1165  		stochastikInterDircuteCompileDurationGeneral.Observe(durCompile.Seconds())
  1166  	}
  1167  	s.currentCauset = stmt.Causet
  1168  
  1169  	// InterDircute the physical plan.
  1170  	logStmt(stmt, s.stochastikVars)
  1171  	recordSet, err := runStmt(ctx, s, stmt)
  1172  	if err != nil {
  1173  		if !ekv.ErrKeyExists.Equal(err) {
  1174  			logutil.Logger(ctx).Warn("run memex failed",
  1175  				zap.Int64("schemaVersion", s.stochastikVars.TxnCtx.SchemaVersion),
  1176  				zap.Error(err),
  1177  				zap.String("stochastik", s.String()))
  1178  		}
  1179  		return nil, err
  1180  	}
  1181  	return recordSet, nil
  1182  }
  1183  
  1184  // runStmt executes the sqlexec.Statement and commit or rollback the current transaction.
  1185  func runStmt(ctx context.Context, se *stochastik, s sqlexec.Statement) (rs sqlexec.RecordSet, err error) {
  1186  	if span := opentracing.SpanFromContext(ctx); span != nil && span.Tracer() != nil {
  1187  		span1 := span.Tracer().StartSpan("stochastik.runStmt", opentracing.ChildOf(span.Context()))
  1188  		span1.LogKV("allegrosql", s.OriginText())
  1189  		defer span1.Finish()
  1190  		ctx = opentracing.ContextWithSpan(ctx, span1)
  1191  	}
  1192  	se.SetValue(stochastikctx.QueryString, s.OriginText())
  1193  	if _, ok := s.(*interlock.InterDircStmt).StmtNode.(ast.DBSNode); ok {
  1194  		se.SetValue(stochastikctx.LastInterDircuteDBS, true)
  1195  	} else {
  1196  		se.ClearValue(stochastikctx.LastInterDircuteDBS)
  1197  	}
  1198  
  1199  	sessVars := se.stochastikVars
  1200  	// Save origTxnCtx here to avoid it reset in the transaction retry.
  1201  	origTxnCtx := sessVars.TxnCtx
  1202  	err = se.checkTxnAborted(s)
  1203  	if err != nil {
  1204  		return nil, err
  1205  	}
  1206  	rs, err = s.InterDirc(ctx)
  1207  	sessVars.TxnCtx.StatementCount++
  1208  	if !s.IsReadOnly(sessVars) {
  1209  		// All the history should be added here.
  1210  		if err == nil && sessVars.TxnCtx.CouldRetry {
  1211  			GetHistory(se).Add(s, sessVars.StmtCtx)
  1212  		}
  1213  
  1214  		// Handle the stmt commit/rollback.
  1215  		if se.txn.Valid() {
  1216  			if err != nil {
  1217  				se.StmtRollback()
  1218  			} else {
  1219  				se.StmtCommit()
  1220  			}
  1221  		}
  1222  	}
  1223  	if rs != nil {
  1224  		return &execStmtResult{
  1225  			RecordSet:  rs,
  1226  			allegrosql: s,
  1227  			se:         se,
  1228  		}, err
  1229  	}
  1230  
  1231  	err = finishStmt(ctx, se, err, s)
  1232  
  1233  	// If it is not a select memex, we record its slow log here,
  1234  	// then it could include the transaction commit time.
  1235  	s.(*interlock.InterDircStmt).FinishInterDircuteStmt(origTxnCtx.StartTS, err == nil, false)
  1236  	return nil, err
  1237  }
  1238  
  1239  // execStmtResult is the return value of InterDircuteStmt and it implements the sqlexec.RecordSet interface.
  1240  // Why we need a struct to wrap a RecordSet and provide another RecordSet?
  1241  // This is because there are so many stochastik state related things that definitely not belongs to the original
  1242  // RecordSet, so this struct exists and RecordSet.Close() is overrided handle that.
  1243  type execStmtResult struct {
  1244  	sqlexec.RecordSet
  1245  	se         *stochastik
  1246  	allegrosql sqlexec.Statement
  1247  }
  1248  
  1249  func (rs *execStmtResult) Close() error {
  1250  	se := rs.se
  1251  	err := rs.RecordSet.Close()
  1252  	return finishStmt(context.Background(), se, err, rs.allegrosql)
  1253  }
  1254  
  1255  // rollbackOnError makes sure the next memex starts a new transaction with the latest SchemaReplicant.
  1256  func (s *stochastik) rollbackOnError(ctx context.Context) {
  1257  	if !s.stochastikVars.InTxn() {
  1258  		s.RollbackTxn(ctx)
  1259  	}
  1260  }
  1261  
  1262  // PrepareStmt is used for executing prepare memex in binary protocol
  1263  func (s *stochastik) PrepareStmt(allegrosql string) (stmtID uint32, paramCount int, fields []*ast.ResultField, err error) {
  1264  	if s.stochastikVars.TxnCtx.SchemaReplicant == nil {
  1265  		// We don't need to create a transaction for prepare memex, just get information schemaReplicant will do.
  1266  		s.stochastikVars.TxnCtx.SchemaReplicant = petri.GetPetri(s).SchemaReplicant()
  1267  	}
  1268  	err = s.loadCommonGlobalVariablesIfNeeded()
  1269  	if err != nil {
  1270  		return
  1271  	}
  1272  
  1273  	ctx := context.Background()
  1274  	inTxn := s.GetStochastikVars().InTxn()
  1275  	// NewPrepareInterDirc may need startTS to build the interlock, for example prepare memex has subquery in int.
  1276  	// So we have to call PrepareTxnCtx here.
  1277  	s.PrepareTxnCtx(ctx)
  1278  	s.PrepareTSFuture(ctx)
  1279  	prepareInterDirc := interlock.NewPrepareInterDirc(s, schemareplicant.GetSchemaReplicant(s), allegrosql)
  1280  	err = prepareInterDirc.Next(ctx, nil)
  1281  	if err != nil {
  1282  		return
  1283  	}
  1284  	if !inTxn {
  1285  		// We could start a transaction to build the prepare interlock before, we should rollback it here.
  1286  		s.RollbackTxn(ctx)
  1287  	}
  1288  	return prepareInterDirc.ID, prepareInterDirc.ParamCount, prepareInterDirc.Fields, nil
  1289  }
  1290  
  1291  func (s *stochastik) preparedStmtInterDirc(ctx context.Context,
  1292  	stmtID uint32, prepareStmt *causetembedded.CachedPrepareStmt, args []types.Causet) (sqlexec.RecordSet, error) {
  1293  	st, err := interlock.CompileInterDircutePreparedStmt(ctx, s, stmtID, args)
  1294  	if err != nil {
  1295  		return nil, err
  1296  	}
  1297  	stochastikInterDircuteCompileDurationGeneral.Observe(time.Since(s.stochastikVars.StartTime).Seconds())
  1298  	logQuery(st.OriginText(), s.stochastikVars)
  1299  	return runStmt(ctx, s, st)
  1300  }
  1301  
  1302  // cachedCausetInterDirc short path currently ONLY for cached "point select plan" execution
  1303  func (s *stochastik) cachedCausetInterDirc(ctx context.Context,
  1304  	stmtID uint32, prepareStmt *causetembedded.CachedPrepareStmt, args []types.Causet) (sqlexec.RecordSet, error) {
  1305  	prepared := prepareStmt.PreparedAst
  1306  	// compile InterDircStmt
  1307  	is := schemareplicant.GetSchemaReplicant(s)
  1308  	execAst := &ast.InterDircuteStmt{InterDircID: stmtID}
  1309  	if err := interlock.ResetContextOfStmt(s, execAst); err != nil {
  1310  		return nil, err
  1311  	}
  1312  	execAst.BinaryArgs = args
  1313  	execCauset, err := causet.OptimizeInterDircStmt(ctx, s, execAst, is)
  1314  	if err != nil {
  1315  		return nil, err
  1316  	}
  1317  
  1318  	stmtCtx := s.GetStochastikVars().StmtCtx
  1319  	stmt := &interlock.InterDircStmt{
  1320  		GoCtx:           ctx,
  1321  		SchemaReplicant: is,
  1322  		Causet:          execCauset,
  1323  		StmtNode:        execAst,
  1324  		Ctx:             s,
  1325  		OutputNames:     execCauset.OutputNames(),
  1326  		PsStmt:          prepareStmt,
  1327  	}
  1328  	compileDuration := time.Since(s.stochastikVars.StartTime)
  1329  	stochastikInterDircuteCompileDurationGeneral.Observe(compileDuration.Seconds())
  1330  	s.GetStochastikVars().DurationCompile = compileDuration
  1331  
  1332  	stmt.Text = prepared.Stmt.Text()
  1333  	stmtCtx.OriginalALLEGROSQL = stmt.Text
  1334  	stmtCtx.InitALLEGROSQLDigest(prepareStmt.NormalizedALLEGROSQL, prepareStmt.ALLEGROSQLDigest)
  1335  	stmtCtx.SetCausetDigest(prepareStmt.NormalizedCauset, prepareStmt.CausetDigest)
  1336  	logQuery(stmt.GetTextToLog(), s.stochastikVars)
  1337  
  1338  	// run InterDircStmt
  1339  	var resultSet sqlexec.RecordSet
  1340  	switch prepared.CachedCauset.(type) {
  1341  	case *causetembedded.PointGetCauset:
  1342  		resultSet, err = stmt.PointGet(ctx, is)
  1343  		s.txn.changeToInvalid()
  1344  	case *causetembedded.UFIDelate:
  1345  		s.PrepareTSFuture(ctx)
  1346  		stmtCtx.Priority = ekv.PriorityHigh
  1347  		resultSet, err = runStmt(ctx, s, stmt)
  1348  	default:
  1349  		prepared.CachedCauset = nil
  1350  		return nil, errors.Errorf("invalid cached plan type")
  1351  	}
  1352  	return resultSet, err
  1353  }
  1354  
  1355  // IsCachedInterDircOk check if we can execute using plan cached in prepared structure
  1356  // Be careful for the short path, current precondition is ths cached plan satisfying
  1357  // IsPointGetWithPKOrUniqueKeyByAutoCommit
  1358  func (s *stochastik) IsCachedInterDircOk(ctx context.Context, preparedStmt *causetembedded.CachedPrepareStmt) (bool, error) {
  1359  	prepared := preparedStmt.PreparedAst
  1360  	if prepared.CachedCauset == nil {
  1361  		return false, nil
  1362  	}
  1363  	// check auto commit
  1364  	if !s.GetStochastikVars().IsAutocommit() {
  1365  		return false, nil
  1366  	}
  1367  	// check schemaReplicant version
  1368  	is := schemareplicant.GetSchemaReplicant(s)
  1369  	if prepared.SchemaVersion != is.SchemaMetaVersion() {
  1370  		prepared.CachedCauset = nil
  1371  		return false, nil
  1372  	}
  1373  	// maybe we'd better check cached plan type here, current
  1374  	// only point select/uFIDelate will be cached, see "getPhysicalCauset" func
  1375  	var ok bool
  1376  	var err error
  1377  	switch prepared.CachedCauset.(type) {
  1378  	case *causetembedded.PointGetCauset:
  1379  		ok = true
  1380  	case *causetembedded.UFIDelate:
  1381  		pointUFIDelate := prepared.CachedCauset.(*causetembedded.UFIDelate)
  1382  		_, ok = pointUFIDelate.SelectCauset.(*causetembedded.PointGetCauset)
  1383  		if !ok {
  1384  			err = errors.Errorf("cached uFIDelate plan not point uFIDelate")
  1385  			prepared.CachedCauset = nil
  1386  			return false, err
  1387  		}
  1388  	default:
  1389  		ok = false
  1390  	}
  1391  	return ok, err
  1392  }
  1393  
  1394  // InterDircutePreparedStmt executes a prepared memex.
  1395  func (s *stochastik) InterDircutePreparedStmt(ctx context.Context, stmtID uint32, args []types.Causet) (sqlexec.RecordSet, error) {
  1396  	s.PrepareTxnCtx(ctx)
  1397  	var err error
  1398  	s.stochastikVars.StartTime = time.Now()
  1399  	preparedPointer, ok := s.stochastikVars.PreparedStmts[stmtID]
  1400  	if !ok {
  1401  		err = causetembedded.ErrStmtNotFound
  1402  		logutil.Logger(ctx).Error("prepared memex not found", zap.Uint32("stmtID", stmtID))
  1403  		return nil, err
  1404  	}
  1405  	preparedStmt, ok := preparedPointer.(*causetembedded.CachedPrepareStmt)
  1406  	if !ok {
  1407  		return nil, errors.Errorf("invalid CachedPrepareStmt type")
  1408  	}
  1409  	interlock.CountStmtNode(preparedStmt.PreparedAst.Stmt, s.stochastikVars.InRestrictedALLEGROSQL)
  1410  	ok, err = s.IsCachedInterDircOk(ctx, preparedStmt)
  1411  	if err != nil {
  1412  		return nil, err
  1413  	}
  1414  	if ok {
  1415  		return s.cachedCausetInterDirc(ctx, stmtID, preparedStmt, args)
  1416  	}
  1417  	return s.preparedStmtInterDirc(ctx, stmtID, preparedStmt, args)
  1418  }
  1419  
  1420  func (s *stochastik) DropPreparedStmt(stmtID uint32) error {
  1421  	vars := s.stochastikVars
  1422  	if _, ok := vars.PreparedStmts[stmtID]; !ok {
  1423  		return causetembedded.ErrStmtNotFound
  1424  	}
  1425  	vars.RetryInfo.DroppedPreparedStmtIDs = append(vars.RetryInfo.DroppedPreparedStmtIDs, stmtID)
  1426  	return nil
  1427  }
  1428  
  1429  func (s *stochastik) Txn(active bool) (ekv.Transaction, error) {
  1430  	if !active {
  1431  		return &s.txn, nil
  1432  	}
  1433  	if !s.txn.validOrPending() {
  1434  		return &s.txn, errors.AddStack(ekv.ErrInvalidTxn)
  1435  	}
  1436  	if s.txn.pending() {
  1437  		defer func(begin time.Time) {
  1438  			s.stochastikVars.DurationWaitTS = time.Since(begin)
  1439  		}(time.Now())
  1440  		// Transaction is lazy initialized.
  1441  		// PrepareTxnCtx is called to get a tso future, makes s.txn a pending txn,
  1442  		// If Txn() is called later, wait for the future to get a valid txn.
  1443  		if err := s.txn.changePendingToValid(s.currentCtx); err != nil {
  1444  			logutil.BgLogger().Error("active transaction fail",
  1445  				zap.Error(err))
  1446  			s.txn.cleanup()
  1447  			s.stochastikVars.TxnCtx.StartTS = 0
  1448  			return &s.txn, err
  1449  		}
  1450  		s.stochastikVars.TxnCtx.StartTS = s.txn.StartTS()
  1451  		if s.stochastikVars.TxnCtx.IsPessimistic {
  1452  			s.txn.SetOption(ekv.Pessimistic, true)
  1453  		}
  1454  		if !s.stochastikVars.IsAutocommit() {
  1455  			s.stochastikVars.SetStatusFlag(allegrosql.ServerStatusInTrans, true)
  1456  		}
  1457  		s.stochastikVars.TxnCtx.CouldRetry = s.isTxnRetryable()
  1458  		s.txn.SetVars(s.stochastikVars.KVVars)
  1459  		if s.stochastikVars.GetReplicaRead().IsFollowerRead() {
  1460  			s.txn.SetOption(ekv.ReplicaRead, ekv.ReplicaReadFollower)
  1461  		}
  1462  	}
  1463  	return &s.txn, nil
  1464  }
  1465  
  1466  // isTxnRetryable (if returns true) means the transaction could retry.
  1467  // If the transaction is in pessimistic mode, do not retry.
  1468  // If the stochastik is already in transaction, enable retry or internal ALLEGROALLEGROSQL could retry.
  1469  // If not, the transaction could always retry, because it should be auto committed transaction.
  1470  // Anyway the retry limit is 0, the transaction could not retry.
  1471  func (s *stochastik) isTxnRetryable() bool {
  1472  	sessVars := s.stochastikVars
  1473  
  1474  	// The pessimistic transaction no need to retry.
  1475  	if sessVars.TxnCtx.IsPessimistic {
  1476  		return false
  1477  	}
  1478  
  1479  	// If retry limit is 0, the transaction could not retry.
  1480  	if sessVars.RetryLimit == 0 {
  1481  		return false
  1482  	}
  1483  
  1484  	// If the stochastik is not InTxn, it is an auto-committed transaction.
  1485  	// The auto-committed transaction could always retry.
  1486  	if !sessVars.InTxn() {
  1487  		return true
  1488  	}
  1489  
  1490  	// The internal transaction could always retry.
  1491  	if sessVars.InRestrictedALLEGROSQL {
  1492  		return true
  1493  	}
  1494  
  1495  	// If the retry is enabled, the transaction could retry.
  1496  	if !sessVars.DisableTxnAutoRetry {
  1497  		return true
  1498  	}
  1499  
  1500  	return false
  1501  }
  1502  
  1503  func (s *stochastik) NewTxn(ctx context.Context) error {
  1504  	if s.txn.Valid() {
  1505  		txnID := s.txn.StartTS()
  1506  		err := s.CommitTxn(ctx)
  1507  		if err != nil {
  1508  			return err
  1509  		}
  1510  		vars := s.GetStochastikVars()
  1511  		logutil.Logger(ctx).Info("NewTxn() inside a transaction auto commit",
  1512  			zap.Int64("schemaVersion", vars.TxnCtx.SchemaVersion),
  1513  			zap.Uint64("txnStartTS", txnID))
  1514  	}
  1515  
  1516  	txn, err := s.causetstore.Begin()
  1517  	if err != nil {
  1518  		return err
  1519  	}
  1520  	txn.SetVars(s.stochastikVars.KVVars)
  1521  	if s.GetStochastikVars().GetReplicaRead().IsFollowerRead() {
  1522  		txn.SetOption(ekv.ReplicaRead, ekv.ReplicaReadFollower)
  1523  	}
  1524  	s.txn.changeInvalidToValid(txn)
  1525  	is := petri.GetPetri(s).SchemaReplicant()
  1526  	s.stochastikVars.TxnCtx = &variable.TransactionContext{
  1527  		SchemaReplicant: is,
  1528  		SchemaVersion:   is.SchemaMetaVersion(),
  1529  		CreateTime:      time.Now(),
  1530  		StartTS:         txn.StartTS(),
  1531  		ShardStep:       int(s.stochastikVars.ShardAllocateStep),
  1532  	}
  1533  	return nil
  1534  }
  1535  
  1536  func (s *stochastik) SetValue(key fmt.Stringer, value interface{}) {
  1537  	s.mu.Lock()
  1538  	s.mu.values[key] = value
  1539  	s.mu.Unlock()
  1540  }
  1541  
  1542  func (s *stochastik) Value(key fmt.Stringer) interface{} {
  1543  	s.mu.RLock()
  1544  	value := s.mu.values[key]
  1545  	s.mu.RUnlock()
  1546  	return value
  1547  }
  1548  
  1549  func (s *stochastik) ClearValue(key fmt.Stringer) {
  1550  	s.mu.Lock()
  1551  	delete(s.mu.values, key)
  1552  	s.mu.Unlock()
  1553  }
  1554  
  1555  type inCloseStochastik struct{}
  1556  
  1557  // Close function does some clean work when stochastik end.
  1558  // Close should release the causet locks which hold by the stochastik.
  1559  func (s *stochastik) Close() {
  1560  	// TODO: do clean causet locks when stochastik exited without execute Close.
  1561  	// TODO: do clean causet locks when milevadb-server was `kill -9`.
  1562  	if s.HasLockedTables() && config.TableLockEnabled() {
  1563  		if ds := config.TableLockDelayClean(); ds > 0 {
  1564  			time.Sleep(time.Duration(ds) * time.Millisecond)
  1565  		}
  1566  		lockedTables := s.GetAllTableLocks()
  1567  		err := petri.GetPetri(s).DBS().UnlockTables(s, lockedTables)
  1568  		if err != nil {
  1569  			logutil.BgLogger().Error("release causet dagger failed", zap.Uint64("conn", s.stochastikVars.ConnectionID))
  1570  		}
  1571  	}
  1572  	if s.statsDefCauslector != nil {
  1573  		s.statsDefCauslector.Delete()
  1574  	}
  1575  	bindValue := s.Value(bindinfo.StochastikBindInfoKeyType)
  1576  	if bindValue != nil {
  1577  		bindValue.(*bindinfo.StochastikHandle).Close()
  1578  	}
  1579  	ctx := context.WithValue(context.TODO(), inCloseStochastik{}, struct{}{})
  1580  	s.RollbackTxn(ctx)
  1581  	if s.stochastikVars != nil {
  1582  		s.stochastikVars.WithdrawAllPreparedStmt()
  1583  	}
  1584  }
  1585  
  1586  // GetStochastikVars implements the context.Context interface.
  1587  func (s *stochastik) GetStochastikVars() *variable.StochastikVars {
  1588  	return s.stochastikVars
  1589  }
  1590  
  1591  func (s *stochastik) Auth(user *auth.UserIdentity, authentication []byte, salt []byte) bool {
  1592  	pm := privilege.GetPrivilegeManager(s)
  1593  
  1594  	// Check IP or localhost.
  1595  	var success bool
  1596  	user.AuthUsername, user.AuthHostname, success = pm.ConnectionVerification(user.Username, user.Hostname, authentication, salt, s.stochastikVars.TLSConnectionState)
  1597  	if success {
  1598  		s.stochastikVars.User = user
  1599  		s.stochastikVars.ActiveRoles = pm.GetDefaultRoles(user.AuthUsername, user.AuthHostname)
  1600  		return true
  1601  	} else if user.Hostname == variable.DefHostname {
  1602  		return false
  1603  	}
  1604  
  1605  	// Check Hostname.
  1606  	for _, addr := range getHostByIP(user.Hostname) {
  1607  		u, h, success := pm.ConnectionVerification(user.Username, addr, authentication, salt, s.stochastikVars.TLSConnectionState)
  1608  		if success {
  1609  			s.stochastikVars.User = &auth.UserIdentity{
  1610  				Username:     user.Username,
  1611  				Hostname:     addr,
  1612  				AuthUsername: u,
  1613  				AuthHostname: h,
  1614  			}
  1615  			s.stochastikVars.ActiveRoles = pm.GetDefaultRoles(u, h)
  1616  			return true
  1617  		}
  1618  	}
  1619  	return false
  1620  }
  1621  
  1622  // AuthWithoutVerification is required by the ResetConnection RPC
  1623  func (s *stochastik) AuthWithoutVerification(user *auth.UserIdentity) bool {
  1624  	pm := privilege.GetPrivilegeManager(s)
  1625  
  1626  	// Check IP or localhost.
  1627  	var success bool
  1628  	user.AuthUsername, user.AuthHostname, success = pm.GetAuthWithoutVerification(user.Username, user.Hostname)
  1629  	if success {
  1630  		s.stochastikVars.User = user
  1631  		s.stochastikVars.ActiveRoles = pm.GetDefaultRoles(user.AuthUsername, user.AuthHostname)
  1632  		return true
  1633  	} else if user.Hostname == variable.DefHostname {
  1634  		return false
  1635  	}
  1636  
  1637  	// Check Hostname.
  1638  	for _, addr := range getHostByIP(user.Hostname) {
  1639  		u, h, success := pm.GetAuthWithoutVerification(user.Username, addr)
  1640  		if success {
  1641  			s.stochastikVars.User = &auth.UserIdentity{
  1642  				Username:     user.Username,
  1643  				Hostname:     addr,
  1644  				AuthUsername: u,
  1645  				AuthHostname: h,
  1646  			}
  1647  			s.stochastikVars.ActiveRoles = pm.GetDefaultRoles(u, h)
  1648  			return true
  1649  		}
  1650  	}
  1651  	return false
  1652  }
  1653  
  1654  func getHostByIP(ip string) []string {
  1655  	if ip == "127.0.0.1" {
  1656  		return []string{variable.DefHostname}
  1657  	}
  1658  	addrs, err := net.LookupAddr(ip)
  1659  	if err != nil {
  1660  		// The error is ignorable.
  1661  		// The empty line here makes the golint tool (which complains err is not checked) happy.
  1662  	}
  1663  	return addrs
  1664  }
  1665  
  1666  // CreateStochastik4Test creates a new stochastik environment for test.
  1667  func CreateStochastik4Test(causetstore ekv.CausetStorage) (Stochastik, error) {
  1668  	return CreateStochastik4TestWithOpt(causetstore, nil)
  1669  }
  1670  
  1671  // Opt describes the option for creating stochastik
  1672  type Opt struct {
  1673  	PreparedCausetCache *ekvcache.SimpleLRUCache
  1674  }
  1675  
  1676  // CreateStochastik4TestWithOpt creates a new stochastik environment for test.
  1677  func CreateStochastik4TestWithOpt(causetstore ekv.CausetStorage, opt *Opt) (Stochastik, error) {
  1678  	s, err := CreateStochastikWithOpt(causetstore, opt)
  1679  	if err == nil {
  1680  		// initialize stochastik variables for test.
  1681  		s.GetStochastikVars().InitChunkSize = 2
  1682  		s.GetStochastikVars().MaxChunkSize = 32
  1683  	}
  1684  	return s, err
  1685  }
  1686  
  1687  // CreateStochastik creates a new stochastik environment.
  1688  func CreateStochastik(causetstore ekv.CausetStorage) (Stochastik, error) {
  1689  	return CreateStochastikWithOpt(causetstore, nil)
  1690  }
  1691  
  1692  // CreateStochastikWithOpt creates a new stochastik environment with option.
  1693  // Use default option if opt is nil.
  1694  func CreateStochastikWithOpt(causetstore ekv.CausetStorage, opt *Opt) (Stochastik, error) {
  1695  	s, err := createStochastikWithOpt(causetstore, opt)
  1696  	if err != nil {
  1697  		return nil, err
  1698  	}
  1699  
  1700  	// Add auth here.
  1701  	do, err := domap.Get(causetstore)
  1702  	if err != nil {
  1703  		return nil, err
  1704  	}
  1705  	pm := &privileges.UserPrivileges{
  1706  		Handle: do.PrivilegeHandle(),
  1707  	}
  1708  	privilege.BindPrivilegeManager(s, pm)
  1709  
  1710  	stochastikBindHandle := bindinfo.NewStochastikBindHandle(s.BerolinaSQL)
  1711  	s.SetValue(bindinfo.StochastikBindInfoKeyType, stochastikBindHandle)
  1712  	// Add stats collector, and it will be freed by background stats worker
  1713  	// which periodically uFIDelates stats using the collected data.
  1714  	if do.StatsHandle() != nil && do.StatsUFIDelating() {
  1715  		s.statsDefCauslector = do.StatsHandle().NewStochastikStatsDefCauslector()
  1716  	}
  1717  
  1718  	return s, nil
  1719  }
  1720  
  1721  // loadSystemTZ loads systemTZ from allegrosql.milevadb
  1722  func loadSystemTZ(se *stochastik) (string, error) {
  1723  	return loadParameter(se, "system_tz")
  1724  }
  1725  
  1726  // loadDefCauslationParameter loads collation parameter from allegrosql.milevadb
  1727  func loadDefCauslationParameter(se *stochastik) (bool, error) {
  1728  	para, err := loadParameter(se, milevadbNewDefCauslationEnabled)
  1729  	if err != nil {
  1730  		return false, err
  1731  	}
  1732  	if para == varTrue {
  1733  		return true, nil
  1734  	} else if para == varFalse {
  1735  		return false, nil
  1736  	}
  1737  	logutil.BgLogger().Warn(
  1738  		"Unexpected value of 'new_collation_enabled' in 'allegrosql.milevadb', use 'False' instead",
  1739  		zap.String("value", para))
  1740  	return false, nil
  1741  }
  1742  
  1743  // loadParameter loads read-only parameter from allegrosql.milevadb
  1744  func loadParameter(se *stochastik, name string) (string, error) {
  1745  	allegrosql := "select variable_value from allegrosql.milevadb where variable_name = '" + name + "'"
  1746  	rss, errLoad := se.InterDircute(context.Background(), allegrosql)
  1747  	if errLoad != nil {
  1748  		return "", errLoad
  1749  	}
  1750  	// the record of allegrosql.milevadb under where condition: variable_name = $name should shall only be one.
  1751  	defer func() {
  1752  		if err := rss[0].Close(); err != nil {
  1753  			logutil.BgLogger().Error("close result set error", zap.Error(err))
  1754  		}
  1755  	}()
  1756  	req := rss[0].NewChunk()
  1757  	if err := rss[0].Next(context.Background(), req); err != nil {
  1758  		return "", err
  1759  	}
  1760  	return req.GetRow(0).GetString(0), nil
  1761  }
  1762  
  1763  // BootstrapStochastik runs the first time when the MilevaDB server start.
  1764  func BootstrapStochastik(causetstore ekv.CausetStorage) (*petri.Petri, error) {
  1765  	cfg := config.GetGlobalConfig()
  1766  	if len(cfg.Plugin.Load) > 0 {
  1767  		err := plugin.Load(context.Background(), plugin.Config{
  1768  			Plugins:        strings.Split(cfg.Plugin.Load, ","),
  1769  			PluginDir:      cfg.Plugin.Dir,
  1770  			GlobalSysVar:   &variable.SysVars,
  1771  			PluginVarNames: &variable.PluginVarNames,
  1772  		})
  1773  		if err != nil {
  1774  			return nil, err
  1775  		}
  1776  	}
  1777  
  1778  	initLoadCommonGlobalVarsALLEGROSQL()
  1779  
  1780  	ver := getStoreBootstrapVersion(causetstore)
  1781  	if ver == notBootstrapped {
  1782  		runInBootstrapStochastik(causetstore, bootstrap)
  1783  	} else if ver < currentBootstrapVersion {
  1784  		runInBootstrapStochastik(causetstore, upgrade)
  1785  	}
  1786  
  1787  	se, err := createStochastik(causetstore)
  1788  	if err != nil {
  1789  		return nil, err
  1790  	}
  1791  	// get system tz from allegrosql.milevadb
  1792  	tz, err := loadSystemTZ(se)
  1793  	if err != nil {
  1794  		return nil, err
  1795  	}
  1796  	timeutil.SetSystemTZ(tz)
  1797  
  1798  	// get the flag from `allegrosql`.`milevadb` which indicating if new collations are enabled.
  1799  	newDefCauslationEnabled, err := loadDefCauslationParameter(se)
  1800  	if err != nil {
  1801  		return nil, err
  1802  	}
  1803  
  1804  	if newDefCauslationEnabled {
  1805  		collate.EnableNewDefCauslations()
  1806  	}
  1807  
  1808  	dom := petri.GetPetri(se)
  1809  	dom.InitExpensiveQueryHandle()
  1810  
  1811  	se2, err := createStochastik(causetstore)
  1812  	if err != nil {
  1813  		return nil, err
  1814  	}
  1815  	se3, err := createStochastik(causetstore)
  1816  	if err != nil {
  1817  		return nil, err
  1818  	}
  1819  	// We should make the load bind-info loop before other loops which has internal ALLEGROALLEGROSQL.
  1820  	// Because the internal ALLEGROALLEGROSQL may access the global bind-info handler. As the result, the data race occurs here as the
  1821  	// LoadBindInfoLoop inits global bind-info handler.
  1822  	err = dom.LoadBindInfoLoop(se2, se3)
  1823  	if err != nil {
  1824  		return nil, err
  1825  	}
  1826  
  1827  	if !config.GetGlobalConfig().Security.SkipGrantTable {
  1828  		err = dom.LoadPrivilegeLoop(se)
  1829  		if err != nil {
  1830  			return nil, err
  1831  		}
  1832  	}
  1833  
  1834  	if len(cfg.Plugin.Load) > 0 {
  1835  		err := plugin.Init(context.Background(), plugin.Config{EtcdClient: dom.GetEtcdClient()})
  1836  		if err != nil {
  1837  			return nil, err
  1838  		}
  1839  	}
  1840  
  1841  	err = interlock.LoadExprPushdownBlacklist(se)
  1842  	if err != nil {
  1843  		return nil, err
  1844  	}
  1845  
  1846  	err = interlock.LoadOptMemruleBlacklist(se)
  1847  	if err != nil {
  1848  		return nil, err
  1849  	}
  1850  
  1851  	dom.TelemetryLoop(se)
  1852  
  1853  	se1, err := createStochastik(causetstore)
  1854  	if err != nil {
  1855  		return nil, err
  1856  	}
  1857  	err = dom.UFIDelateTableStatsLoop(se1)
  1858  	if err != nil {
  1859  		return nil, err
  1860  	}
  1861  	if raw, ok := causetstore.(einsteindb.EtcdBackend); ok {
  1862  		err = raw.StartGCWorker()
  1863  		if err != nil {
  1864  			return nil, err
  1865  		}
  1866  	}
  1867  
  1868  	return dom, err
  1869  }
  1870  
  1871  // GetPetri gets the associated petri for causetstore.
  1872  func GetPetri(causetstore ekv.CausetStorage) (*petri.Petri, error) {
  1873  	return domap.Get(causetstore)
  1874  }
  1875  
  1876  // runInBootstrapStochastik create a special stochastik for bootstrap to run.
  1877  // If no bootstrap and storage is remote, we must use a little lease time to
  1878  // bootstrap quickly, after bootstrapped, we will reset the lease time.
  1879  // TODO: Using a bootstrap tool for doing this may be better later.
  1880  func runInBootstrapStochastik(causetstore ekv.CausetStorage, bootstrap func(Stochastik)) {
  1881  	s, err := createStochastik(causetstore)
  1882  	if err != nil {
  1883  		// Bootstrap fail will cause program exit.
  1884  		logutil.BgLogger().Fatal("createStochastik error", zap.Error(err))
  1885  	}
  1886  
  1887  	s.SetValue(stochastikctx.Initing, true)
  1888  	bootstrap(s)
  1889  	finishBootstrap(causetstore)
  1890  	s.ClearValue(stochastikctx.Initing)
  1891  
  1892  	dom := petri.GetPetri(s)
  1893  	dom.Close()
  1894  	domap.Delete(causetstore)
  1895  }
  1896  
  1897  func createStochastik(causetstore ekv.CausetStorage) (*stochastik, error) {
  1898  	return createStochastikWithOpt(causetstore, nil)
  1899  }
  1900  
  1901  func createStochastikWithOpt(causetstore ekv.CausetStorage, opt *Opt) (*stochastik, error) {
  1902  	dom, err := domap.Get(causetstore)
  1903  	if err != nil {
  1904  		return nil, err
  1905  	}
  1906  	s := &stochastik{
  1907  		causetstore:      causetstore,
  1908  		BerolinaSQL:      BerolinaSQL.New(),
  1909  		stochastikVars:   variable.NewStochastikVars(),
  1910  		dbsTenantChecker: dom.DBS().TenantManager(),
  1911  		client:           causetstore.GetClient(),
  1912  	}
  1913  	if causetembedded.PreparedCausetCacheEnabled() {
  1914  		if opt != nil && opt.PreparedCausetCache != nil {
  1915  			s.preparedCausetCache = opt.PreparedCausetCache
  1916  		} else {
  1917  			s.preparedCausetCache = ekvcache.NewSimpleLRUCache(causetembedded.PreparedCausetCacheCapacity,
  1918  				causetembedded.PreparedCausetCacheMemoryGuardRatio, causetembedded.PreparedCausetCacheMaxMemory.Load())
  1919  		}
  1920  	}
  1921  	s.mu.values = make(map[fmt.Stringer]interface{})
  1922  	s.lockedTables = make(map[int64]perceptron.TableLockTpInfo)
  1923  	petri.BindPetri(s, dom)
  1924  	// stochastik implements variable.GlobalVarAccessor. Bind it to ctx.
  1925  	s.stochastikVars.GlobalVarsAccessor = s
  1926  	s.stochastikVars.BinlogClient = binloginfo.GetPumpsClient()
  1927  	s.txn.init()
  1928  
  1929  	stochastikBindHandle := bindinfo.NewStochastikBindHandle(s.BerolinaSQL)
  1930  	s.SetValue(bindinfo.StochastikBindInfoKeyType, stochastikBindHandle)
  1931  	return s, nil
  1932  }
  1933  
  1934  // CreateStochastikWithPetri creates a new Stochastik and binds it with a Petri.
  1935  // We need this because when we start DBS in Petri, the DBS need a stochastik
  1936  // to change some system blocks. But at that time, we have been already in
  1937  // a dagger context, which cause we can't call createSesion directly.
  1938  func CreateStochastikWithPetri(causetstore ekv.CausetStorage, dom *petri.Petri) (*stochastik, error) {
  1939  	s := &stochastik{
  1940  		causetstore:    causetstore,
  1941  		BerolinaSQL:    BerolinaSQL.New(),
  1942  		stochastikVars: variable.NewStochastikVars(),
  1943  		client:         causetstore.GetClient(),
  1944  	}
  1945  	if causetembedded.PreparedCausetCacheEnabled() {
  1946  		s.preparedCausetCache = ekvcache.NewSimpleLRUCache(causetembedded.PreparedCausetCacheCapacity,
  1947  			causetembedded.PreparedCausetCacheMemoryGuardRatio, causetembedded.PreparedCausetCacheMaxMemory.Load())
  1948  	}
  1949  	s.mu.values = make(map[fmt.Stringer]interface{})
  1950  	s.lockedTables = make(map[int64]perceptron.TableLockTpInfo)
  1951  	petri.BindPetri(s, dom)
  1952  	// stochastik implements variable.GlobalVarAccessor. Bind it to ctx.
  1953  	s.stochastikVars.GlobalVarsAccessor = s
  1954  	s.txn.init()
  1955  	return s, nil
  1956  }
  1957  
  1958  const (
  1959  	notBootstrapped         = 0
  1960  	currentBootstrapVersion = version51
  1961  )
  1962  
  1963  func getStoreBootstrapVersion(causetstore ekv.CausetStorage) int64 {
  1964  	storeBootstrappedLock.Lock()
  1965  	defer storeBootstrappedLock.Unlock()
  1966  	// check in memory
  1967  	_, ok := storeBootstrapped[causetstore.UUID()]
  1968  	if ok {
  1969  		return currentBootstrapVersion
  1970  	}
  1971  
  1972  	var ver int64
  1973  	// check in ekv causetstore
  1974  	err := ekv.RunInNewTxn(causetstore, false, func(txn ekv.Transaction) error {
  1975  		var err error
  1976  		t := spacetime.NewMeta(txn)
  1977  		ver, err = t.GetBootstrapVersion()
  1978  		return err
  1979  	})
  1980  
  1981  	if err != nil {
  1982  		logutil.BgLogger().Fatal("check bootstrapped failed",
  1983  			zap.Error(err))
  1984  	}
  1985  
  1986  	if ver > notBootstrapped {
  1987  		// here mean memory is not ok, but other server has already finished it
  1988  		storeBootstrapped[causetstore.UUID()] = true
  1989  	}
  1990  
  1991  	return ver
  1992  }
  1993  
  1994  func finishBootstrap(causetstore ekv.CausetStorage) {
  1995  	setStoreBootstrapped(causetstore.UUID())
  1996  
  1997  	err := ekv.RunInNewTxn(causetstore, true, func(txn ekv.Transaction) error {
  1998  		t := spacetime.NewMeta(txn)
  1999  		err := t.FinishBootstrap(currentBootstrapVersion)
  2000  		return err
  2001  	})
  2002  	if err != nil {
  2003  		logutil.BgLogger().Fatal("finish bootstrap failed",
  2004  			zap.Error(err))
  2005  	}
  2006  }
  2007  
  2008  const quoteCommaQuote = "', '"
  2009  
  2010  var builtinGlobalVariable = []string{
  2011  	variable.AutoCommit,
  2012  	variable.ALLEGROSQLModeVar,
  2013  	variable.MaxAllowedPacket,
  2014  	variable.TimeZone,
  2015  	variable.BlockEncryptionMode,
  2016  	variable.WaitTimeout,
  2017  	variable.InteractiveTimeout,
  2018  	variable.MaxPreparedStmtCount,
  2019  	variable.InitConnect,
  2020  	variable.TxnIsolation,
  2021  	variable.TxReadOnly,
  2022  	variable.TransactionIsolation,
  2023  	variable.TransactionReadOnly,
  2024  	variable.NetBufferLength,
  2025  	variable.QueryCacheType,
  2026  	variable.QueryCacheSize,
  2027  	variable.CharacterSetServer,
  2028  	variable.AutoIncrementIncrement,
  2029  	variable.AutoIncrementOffset,
  2030  	variable.DefCauslationServer,
  2031  	variable.NetWriteTimeout,
  2032  	variable.MaxInterDircutionTime,
  2033  	variable.InnodbLockWaitTimeout,
  2034  	variable.WindowingUseHighPrecision,
  2035  	variable.ALLEGROSQLSelectLimit,
  2036  
  2037  	/* MilevaDB specific global variables: */
  2038  	variable.MilevaDBSkipASCIICheck,
  2039  	variable.MilevaDBSkipUTF8Check,
  2040  	variable.MilevaDBIndexJoinBatchSize,
  2041  	variable.MilevaDBIndexLookupSize,
  2042  	variable.MilevaDBIndexLookupConcurrency,
  2043  	variable.MilevaDBIndexLookupJoinConcurrency,
  2044  	variable.MilevaDBIndexSerialScanConcurrency,
  2045  	variable.MilevaDBHashJoinConcurrency,
  2046  	variable.MilevaDBProjectionConcurrency,
  2047  	variable.MilevaDBHashAggPartialConcurrency,
  2048  	variable.MilevaDBHashAggFinalConcurrency,
  2049  	variable.MilevaDBWindowConcurrency,
  2050  	variable.MilevaDBInterlockingDirectorateConcurrency,
  2051  	variable.MilevaDBBackoffLockFast,
  2052  	variable.MilevaDBBackOffWeight,
  2053  	variable.MilevaDBConstraintCheckInPlace,
  2054  	variable.MilevaDBDBSReorgWorkerCount,
  2055  	variable.MilevaDBDBSReorgBatchSize,
  2056  	variable.MilevaDBDBSErrorCountLimit,
  2057  	variable.MilevaDBOptInSubqToJoinAnPosetDagg,
  2058  	variable.MilevaDBOptCorrelationThreshold,
  2059  	variable.MilevaDBOptCorrelationExpFactor,
  2060  	variable.MilevaDBOptCPUFactor,
  2061  	variable.MilevaDBOptCopCPUFactor,
  2062  	variable.MilevaDBOptNetworkFactor,
  2063  	variable.MilevaDBOptScanFactor,
  2064  	variable.MilevaDBOptDescScanFactor,
  2065  	variable.MilevaDBOptMemoryFactor,
  2066  	variable.MilevaDBOptDiskFactor,
  2067  	variable.MilevaDBOptConcurrencyFactor,
  2068  	variable.MilevaDBDistALLEGROSQLScanConcurrency,
  2069  	variable.MilevaDBInitChunkSize,
  2070  	variable.MilevaDBMaxChunkSize,
  2071  	variable.MilevaDBEnableCascadesCausetAppend,
  2072  	variable.MilevaDBRetryLimit,
  2073  	variable.MilevaDBDisableTxnAutoRetry,
  2074  	variable.MilevaDBEnableWindowFunction,
  2075  	variable.MilevaDBEnableTablePartition,
  2076  	variable.MilevaDBEnableVectorizedExpression,
  2077  	variable.MilevaDBEnableFastAnalyze,
  2078  	variable.MilevaDBExpensiveQueryTimeThreshold,
  2079  	variable.MilevaDBEnableNoopFuncs,
  2080  	variable.MilevaDBEnableIndexMerge,
  2081  	variable.MilevaDBTxnMode,
  2082  	variable.MilevaDBAllowBatchCop,
  2083  	variable.MilevaDBOptBCJ,
  2084  	variable.MilevaDBRowFormatVersion,
  2085  	variable.MilevaDBEnableStmtSummary,
  2086  	variable.MilevaDBStmtSummaryInternalQuery,
  2087  	variable.MilevaDBStmtSummaryRefreshInterval,
  2088  	variable.MilevaDBStmtSummaryHistorySize,
  2089  	variable.MilevaDBStmtSummaryMaxStmtCount,
  2090  	variable.MilevaDBStmtSummaryMaxALLEGROSQLLength,
  2091  	variable.MilevaDBMaxDeltaSchemaCount,
  2092  	variable.MilevaDBCaptureCausetBaseline,
  2093  	variable.MilevaDBUseCausetBaselines,
  2094  	variable.MilevaDBEvolveCausetBaselines,
  2095  	variable.MilevaDBIsolationReadEngines,
  2096  	variable.MilevaDBStoreLimit,
  2097  	variable.MilevaDBAllowAutoRandExplicitInsert,
  2098  	variable.MilevaDBEnableClusteredIndex,
  2099  	variable.MilevaDBPartitionPruneMode,
  2100  	variable.MilevaDBSlowLogMasking,
  2101  	variable.MilevaDBRedactLog,
  2102  	variable.MilevaDBEnableTelemetry,
  2103  	variable.MilevaDBShardAllocateStep,
  2104  	variable.MilevaDBEnableChangeDeferredCausetType,
  2105  	variable.MilevaDBEnableAmendPessimisticTxn,
  2106  }
  2107  
  2108  var (
  2109  	loadCommonGlobalVarsALLEGROSQLOnce sync.Once
  2110  	loadCommonGlobalVarsALLEGROSQL     string
  2111  )
  2112  
  2113  func initLoadCommonGlobalVarsALLEGROSQL() {
  2114  	loadCommonGlobalVarsALLEGROSQLOnce.Do(func() {
  2115  		vars := append(make([]string, 0, len(builtinGlobalVariable)+len(variable.PluginVarNames)), builtinGlobalVariable...)
  2116  		if len(variable.PluginVarNames) > 0 {
  2117  			vars = append(vars, variable.PluginVarNames...)
  2118  		}
  2119  		loadCommonGlobalVarsALLEGROSQL = "select HIGH_PRIORITY * from allegrosql.global_variables where variable_name in ('" + strings.Join(vars, quoteCommaQuote) + "')"
  2120  	})
  2121  }
  2122  
  2123  // loadCommonGlobalVariablesIfNeeded loads and applies commonly used global variables for the stochastik.
  2124  func (s *stochastik) loadCommonGlobalVariablesIfNeeded() error {
  2125  	initLoadCommonGlobalVarsALLEGROSQL()
  2126  	vars := s.stochastikVars
  2127  	if vars.CommonGlobalLoaded {
  2128  		return nil
  2129  	}
  2130  	if s.Value(stochastikctx.Initing) != nil {
  2131  		// When running bootstrap or upgrade, we should not access global storage.
  2132  		return nil
  2133  	}
  2134  
  2135  	var err error
  2136  	// Use GlobalVariableCache if MilevaDB just loaded global variables within 2 second ago.
  2137  	// When a lot of connections connect to MilevaDB simultaneously, it can protect EinsteinDB spacetime region from overload.
  2138  	gvc := petri.GetPetri(s).GetGlobalVarsCache()
  2139  	loadFunc := func() ([]chunk.Row, []*ast.ResultField, error) {
  2140  		return s.InterDircRestrictedALLEGROSQL(loadCommonGlobalVarsALLEGROSQL)
  2141  	}
  2142  	rows, fields, err := gvc.LoadGlobalVariables(loadFunc)
  2143  	if err != nil {
  2144  		logutil.BgLogger().Warn("failed to load global variables",
  2145  			zap.Uint64("conn", s.stochastikVars.ConnectionID), zap.Error(err))
  2146  		return err
  2147  	}
  2148  	vars.CommonGlobalLoaded = true
  2149  
  2150  	for _, event := range rows {
  2151  		varName := event.GetString(0)
  2152  		varVal := event.GetCauset(1, &fields[1].DeferredCauset.FieldType)
  2153  		if _, ok := vars.GetSystemVar(varName); !ok {
  2154  			err = variable.SetStochastikSystemVar(s.stochastikVars, varName, varVal)
  2155  			if err != nil {
  2156  				return err
  2157  			}
  2158  		}
  2159  	}
  2160  
  2161  	// when client set Capability Flags CLIENT_INTERACTIVE, init wait_timeout with interactive_timeout
  2162  	if vars.ClientCapability&allegrosql.ClientInteractive > 0 {
  2163  		if varVal, ok := vars.GetSystemVar(variable.InteractiveTimeout); ok {
  2164  			if err := vars.SetSystemVar(variable.WaitTimeout, varVal); err != nil {
  2165  				return err
  2166  			}
  2167  		}
  2168  	}
  2169  
  2170  	vars.CommonGlobalLoaded = true
  2171  	return nil
  2172  }
  2173  
  2174  // PrepareTxnCtx starts a goroutine to begin a transaction if needed, and creates a new transaction context.
  2175  // It is called before we execute a allegrosql query.
  2176  func (s *stochastik) PrepareTxnCtx(ctx context.Context) {
  2177  	s.currentCtx = ctx
  2178  	if s.txn.validOrPending() {
  2179  		return
  2180  	}
  2181  
  2182  	is := petri.GetPetri(s).SchemaReplicant()
  2183  	s.stochastikVars.TxnCtx = &variable.TransactionContext{
  2184  		SchemaReplicant: is,
  2185  		SchemaVersion:   is.SchemaMetaVersion(),
  2186  		CreateTime:      time.Now(),
  2187  		ShardStep:       int(s.stochastikVars.ShardAllocateStep),
  2188  	}
  2189  	if !s.stochastikVars.IsAutocommit() || s.stochastikVars.RetryInfo.Retrying {
  2190  		if s.stochastikVars.TxnMode == ast.Pessimistic {
  2191  			s.stochastikVars.TxnCtx.IsPessimistic = true
  2192  		}
  2193  	}
  2194  }
  2195  
  2196  // PrepareTSFuture uses to try to get ts future.
  2197  func (s *stochastik) PrepareTSFuture(ctx context.Context) {
  2198  	if !s.txn.validOrPending() {
  2199  		// Prepare the transaction future if the transaction is invalid (at the beginning of the transaction).
  2200  		txnFuture := s.getTxnFuture(ctx)
  2201  		s.txn.changeInvalidToPending(txnFuture)
  2202  	} else if s.txn.Valid() && s.GetStochastikVars().IsPessimisticReadConsistency() {
  2203  		// Prepare the memex future if the transaction is valid in RC transactions.
  2204  		s.GetStochastikVars().TxnCtx.SetStmtFutureForRC(s.getTxnFuture(ctx).future)
  2205  	}
  2206  }
  2207  
  2208  // RefreshTxnCtx implements context.RefreshTxnCtx interface.
  2209  func (s *stochastik) RefreshTxnCtx(ctx context.Context) error {
  2210  	if err := s.doCommit(ctx); err != nil {
  2211  		return err
  2212  	}
  2213  
  2214  	return s.NewTxn(ctx)
  2215  }
  2216  
  2217  // InitTxnWithStartTS create a transaction with startTS.
  2218  func (s *stochastik) InitTxnWithStartTS(startTS uint64) error {
  2219  	if s.txn.Valid() {
  2220  		return nil
  2221  	}
  2222  
  2223  	// no need to get txn from txnFutureCh since txn should init with startTs
  2224  	txn, err := s.causetstore.BeginWithStartTS(startTS)
  2225  	if err != nil {
  2226  		return err
  2227  	}
  2228  	txn.SetVars(s.stochastikVars.KVVars)
  2229  	s.txn.changeInvalidToValid(txn)
  2230  	err = s.loadCommonGlobalVariablesIfNeeded()
  2231  	if err != nil {
  2232  		return err
  2233  	}
  2234  	return nil
  2235  }
  2236  
  2237  // GetStore gets the causetstore of stochastik.
  2238  func (s *stochastik) GetStore() ekv.CausetStorage {
  2239  	return s.causetstore
  2240  }
  2241  
  2242  func (s *stochastik) ShowProcess() *soliton.ProcessInfo {
  2243  	var pi *soliton.ProcessInfo
  2244  	tmp := s.processInfo.Load()
  2245  	if tmp != nil {
  2246  		pi = tmp.(*soliton.ProcessInfo)
  2247  	}
  2248  	return pi
  2249  }
  2250  
  2251  // logStmt logs some crucial ALLEGROALLEGROSQL including: CREATE USER/GRANT PRIVILEGE/CHANGE PASSWORD/DBS etc and normal ALLEGROALLEGROSQL
  2252  // if variable.ProcessGeneralLog is set.
  2253  func logStmt(execStmt *interlock.InterDircStmt, vars *variable.StochastikVars) {
  2254  	switch stmt := execStmt.StmtNode.(type) {
  2255  	case *ast.CreateUserStmt, *ast.DropUserStmt, *ast.AlterUserStmt, *ast.SetPwdStmt, *ast.GrantStmt,
  2256  		*ast.RevokeStmt, *ast.AlterTableStmt, *ast.CreateDatabaseStmt, *ast.CreateIndexStmt, *ast.CreateTableStmt,
  2257  		*ast.DroFIDelatabaseStmt, *ast.DropIndexStmt, *ast.DropTableStmt, *ast.RenameTableStmt, *ast.TruncateTableStmt:
  2258  		user := vars.User
  2259  		schemaVersion := vars.TxnCtx.SchemaVersion
  2260  		if ss, ok := execStmt.StmtNode.(ast.SensitiveStmtNode); ok {
  2261  			logutil.BgLogger().Info("CRUCIAL OPERATION",
  2262  				zap.Uint64("conn", vars.ConnectionID),
  2263  				zap.Int64("schemaVersion", schemaVersion),
  2264  				zap.String("secure text", ss.SecureText()),
  2265  				zap.Stringer("user", user))
  2266  		} else {
  2267  			logutil.BgLogger().Info("CRUCIAL OPERATION",
  2268  				zap.Uint64("conn", vars.ConnectionID),
  2269  				zap.Int64("schemaVersion", schemaVersion),
  2270  				zap.String("cur_db", vars.CurrentDB),
  2271  				zap.String("allegrosql", stmt.Text()),
  2272  				zap.Stringer("user", user))
  2273  		}
  2274  	default:
  2275  		logQuery(execStmt.GetTextToLog(), vars)
  2276  	}
  2277  }
  2278  
  2279  func logQuery(query string, vars *variable.StochastikVars) {
  2280  	if atomic.LoadUint32(&variable.ProcessGeneralLog) != 0 && !vars.InRestrictedALLEGROSQL {
  2281  		query = interlock.QueryReplacer.Replace(query)
  2282  		if !config.RedactLogEnabled() {
  2283  			query = query + vars.PreparedParams.String()
  2284  		}
  2285  		logutil.BgLogger().Info("GENERAL_LOG",
  2286  			zap.Uint64("conn", vars.ConnectionID),
  2287  			zap.Stringer("user", vars.User),
  2288  			zap.Int64("schemaVersion", vars.TxnCtx.SchemaVersion),
  2289  			zap.Uint64("txnStartTS", vars.TxnCtx.StartTS),
  2290  			zap.Uint64("forUFIDelateTS", vars.TxnCtx.GetForUFIDelateTS()),
  2291  			zap.Bool("isReadConsistency", vars.IsReadConsistencyTxn()),
  2292  			zap.String("current_db", vars.CurrentDB),
  2293  			zap.String("txn_mode", vars.GetReadableTxnMode()),
  2294  			zap.String("allegrosql", query))
  2295  	}
  2296  }
  2297  
  2298  func (s *stochastik) recordOnTransactionInterDircution(err error, counter int, duration float64) {
  2299  	if s.stochastikVars.TxnCtx.IsPessimistic {
  2300  		if err != nil {
  2301  			memexPerTransactionPessimisticError.Observe(float64(counter))
  2302  			transactionDurationPessimisticAbort.Observe(duration)
  2303  		} else {
  2304  			memexPerTransactionPessimisticOK.Observe(float64(counter))
  2305  			transactionDurationPessimisticCommit.Observe(duration)
  2306  		}
  2307  	} else {
  2308  		if err != nil {
  2309  			memexPerTransactionOptimisticError.Observe(float64(counter))
  2310  			transactionDurationOptimisticAbort.Observe(duration)
  2311  		} else {
  2312  			memexPerTransactionOptimisticOK.Observe(float64(counter))
  2313  			transactionDurationOptimisticCommit.Observe(duration)
  2314  		}
  2315  	}
  2316  }