github.com/matrixorigin/matrixone@v1.2.0/pkg/frontend/txn.go (about) 1 // Copyright 2021 Matrix Origin 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package frontend 16 17 import ( 18 "context" 19 "errors" 20 "sync" 21 22 "github.com/google/uuid" 23 24 "github.com/matrixorigin/matrixone/pkg/clusterservice" 25 "github.com/matrixorigin/matrixone/pkg/common/mpool" 26 "github.com/matrixorigin/matrixone/pkg/logutil" 27 "github.com/matrixorigin/matrixone/pkg/pb/metadata" 28 "github.com/matrixorigin/matrixone/pkg/txn/clock" 29 "github.com/matrixorigin/matrixone/pkg/vm/engine/memoryengine" 30 31 "go.uber.org/zap" 32 33 "github.com/matrixorigin/matrixone/pkg/common/moerr" 34 moruntime "github.com/matrixorigin/matrixone/pkg/common/runtime" 35 "github.com/matrixorigin/matrixone/pkg/defines" 36 "github.com/matrixorigin/matrixone/pkg/txn/client" 37 "github.com/matrixorigin/matrixone/pkg/txn/storage/memorystorage" 38 "github.com/matrixorigin/matrixone/pkg/util/metric" 39 "github.com/matrixorigin/matrixone/pkg/util/trace" 40 "github.com/matrixorigin/matrixone/pkg/vm/engine" 41 ) 42 43 var ( 44 dumpUUID = uuid.UUID{} 45 ) 46 47 // get errors during the transaction. rollback the transaction 48 func rollbackTxnFunc(ses FeSession, execErr error, execCtx *ExecCtx) error { 49 incStatementErrorsCounter(execCtx.tenant, execCtx.stmt) 50 /* 51 Cases | set Autocommit = 1/0 | BEGIN statement | 52 --------------------------------------------------- 53 Case1 1 Yes 54 Case2 1 No 55 Case3 0 Yes 56 Case4 0 No 57 --------------------------------------------------- 58 update error message in Case1,Case3,Case4. 59 */ 60 if ses.GetTxnHandler().InMultiStmtTransactionMode() && ses.GetTxnHandler().InActiveTxn() { 61 ses.cleanCache() 62 } 63 logError(ses, ses.GetDebugString(), execErr.Error()) 64 execCtx.txnOpt.byRollback = execCtx.txnOpt.byRollback || isErrorRollbackWholeTxn(execErr) 65 txnErr := ses.GetTxnHandler().Rollback(execCtx) 66 if txnErr != nil { 67 logStatementStatus(execCtx.reqCtx, ses, execCtx.stmt, fail, txnErr) 68 return txnErr 69 } 70 logStatementStatus(execCtx.reqCtx, ses, execCtx.stmt, fail, execErr) 71 return execErr 72 } 73 74 // execution succeeds during the transaction. commit the transaction 75 func commitTxnFunc(ses FeSession, 76 execCtx *ExecCtx) (retErr error) { 77 // Call a defer function -- if TxnCommitSingleStatement paniced, we 78 // want to catch it and convert it to an error. 79 defer func() { 80 if r := recover(); r != nil { 81 retErr = moerr.ConvertPanicError(execCtx.reqCtx, r) 82 } 83 }() 84 85 //load data handle txn failure internally 86 retErr = ses.GetTxnHandler().Commit(execCtx) 87 if retErr != nil { 88 logStatementStatus(execCtx.reqCtx, ses, execCtx.stmt, fail, retErr) 89 } 90 return 91 } 92 93 // finish the transaction 94 func finishTxnFunc(ses FeSession, execErr error, execCtx *ExecCtx) (err error) { 95 // First recover all panics. If paniced, we will abort. 96 if r := recover(); r != nil { 97 recoverErr := moerr.ConvertPanicError(execCtx.reqCtx, r) 98 logError(ses, ses.GetDebugString(), "recover from panic", zap.Error(recoverErr), zap.Error(execErr)) 99 } 100 101 if execCtx.txnOpt.byCommit { 102 //commit the txn by the COMMIT statement 103 err = ses.GetTxnHandler().Commit(execCtx) 104 if err != nil { 105 logStatementStatus(execCtx.reqCtx, ses, execCtx.stmt, fail, err) 106 } 107 } else if execCtx.txnOpt.byRollback { 108 //roll back the txn by the ROLLBACK statement 109 err = ses.GetTxnHandler().Rollback(execCtx) 110 if err != nil { 111 logStatementStatus(execCtx.reqCtx, ses, execCtx.stmt, fail, err) 112 return err 113 } 114 } else { 115 if execErr == nil { 116 err = commitTxnFunc(ses, execCtx) 117 if err == nil { 118 return err 119 } 120 // if commitTxnFunc failed, we will roll back the transaction. 121 execErr = err 122 } 123 124 return rollbackTxnFunc(ses, execErr, execCtx) 125 } 126 return 127 } 128 129 type FeTxnOption struct { 130 //byBegin denotes the txn started by the BEGIN stmt 131 byBegin bool 132 //autoCommit the variable AUTOCOMMIT is enabled 133 autoCommit bool 134 //byCommit denotes the txn committed by the COMMIT 135 byCommit bool 136 //byRollback denotes the txn rolled back by the ROLLBACK. 137 //or error types that need to roll back the whole txn. 138 byRollback bool 139 } 140 141 const ( 142 defaultServerStatus uint32 = uint32(SERVER_STATUS_AUTOCOMMIT) 143 defaultOptionBits uint32 = OPTION_AUTOCOMMIT 144 ) 145 146 type TxnHandler struct { 147 mu sync.Mutex 148 149 storage engine.Engine 150 tempStorage *memorystorage.Storage 151 tempTnService *metadata.TNService 152 tempEngine *memoryengine.Engine 153 txnOp TxnOperator 154 155 //connCtx is the ancestor of the txnCtx. 156 //it is initialized at the TxnHandler object created and 157 //exists always. 158 //it starts from the routineCtx. 159 connCtx context.Context 160 161 // it is for the transaction and different from the requestCtx. 162 // it is created before the transaction is started and 163 // is not released after the transaction is commit or rollback. 164 // the lifetime of txnCtx is longer than the requestCtx and 165 // the same as the connCtx. 166 // it inherits the connCtx. 167 // it can not be canceled at the KillQuery 168 txnCtx context.Context 169 txnCtxCancel context.CancelFunc 170 171 shareTxn bool 172 173 //the server status 174 serverStatus uint32 175 176 //the option bits 177 optionBits uint32 178 } 179 180 func InitTxnHandler(storage engine.Engine, connCtx context.Context, txnOp TxnOperator) *TxnHandler { 181 ret := &TxnHandler{ 182 storage: &engine.EntireEngine{Engine: storage}, 183 connCtx: connCtx, 184 txnOp: txnOp, 185 shareTxn: txnOp != nil, 186 serverStatus: defaultServerStatus, 187 optionBits: defaultOptionBits, 188 } 189 ret.txnCtx, ret.txnCtxCancel = context.WithCancel(connCtx) 190 return ret 191 } 192 193 func (th *TxnHandler) Close() { 194 th.mu.Lock() 195 defer th.mu.Unlock() 196 th.storage = nil 197 th.tempStorage = nil 198 th.tempTnService = nil 199 th.tempEngine = nil 200 th.txnOp = nil 201 th.connCtx = nil 202 if th.txnCtxCancel != nil { 203 th.txnCtxCancel() 204 } 205 th.txnCtx = nil 206 } 207 208 func (th *TxnHandler) GetConnCtx() context.Context { 209 th.mu.Lock() 210 defer th.mu.Unlock() 211 return th.connCtx 212 } 213 214 func (th *TxnHandler) GetTxnCtx() context.Context { 215 th.mu.Lock() 216 defer th.mu.Unlock() 217 return th.txnCtx 218 } 219 220 // invalidateTxnUnsafe releases the txnOp and clears the server status bit SERVER_STATUS_IN_TRANS 221 func (th *TxnHandler) invalidateTxnUnsafe() { 222 th.txnOp = nil 223 resetBits(&th.serverStatus, defaultServerStatus) 224 resetBits(&th.optionBits, defaultOptionBits) 225 } 226 227 func (th *TxnHandler) InActiveTxn() bool { 228 th.mu.Lock() 229 defer th.mu.Unlock() 230 return th.inActiveTxnUnsafe() 231 } 232 233 // inActiveTxnUnsafe can not be used outside the TxnHandler. 234 // refresh server status also 235 func (th *TxnHandler) inActiveTxnUnsafe() bool { 236 if th.txnOp != nil && th.txnCtx == nil { 237 panic("txnOp != nil and txnCtx == nil") 238 } 239 return th.txnOp != nil && th.txnCtx != nil 240 } 241 242 // Create starts a new txn. 243 // option bits decide the actual behaviour 244 func (th *TxnHandler) Create(execCtx *ExecCtx) error { 245 var err error 246 th.mu.Lock() 247 defer th.mu.Unlock() 248 249 // check BEGIN stmt 250 if execCtx.txnOpt.byBegin || !th.inActiveTxnUnsafe() { 251 //commit existed txn anyway 252 err = th.createUnsafe(execCtx) 253 if err != nil { 254 return err 255 } 256 resetBits(&th.serverStatus, defaultServerStatus) 257 resetBits(&th.optionBits, defaultOptionBits) 258 setBits(&th.serverStatus, uint32(SERVER_STATUS_IN_TRANS)) 259 260 if execCtx.txnOpt.byBegin { 261 setBits(&th.optionBits, OPTION_BEGIN) 262 } else { 263 clearBits(&th.optionBits, OPTION_BEGIN) 264 } 265 266 if execCtx.txnOpt.autoCommit { 267 clearBits(&th.optionBits, OPTION_NOT_AUTOCOMMIT) 268 setBits(&th.serverStatus, uint32(SERVER_STATUS_AUTOCOMMIT)) 269 } else { 270 setBits(&th.optionBits, OPTION_NOT_AUTOCOMMIT) 271 clearBits(&th.serverStatus, uint32(SERVER_STATUS_AUTOCOMMIT)) 272 } 273 } 274 return nil 275 } 276 277 // starts a new txn. 278 // if there is a txn existed, commit it before creating a new one. 279 func (th *TxnHandler) createUnsafe(execCtx *ExecCtx) error { 280 var err error 281 defer th.inActiveTxnUnsafe() 282 if th.shareTxn { 283 return moerr.NewInternalError(execCtx.reqCtx, "NewTxn: the share txn is not allowed to create new txn") 284 } 285 286 //in active txn 287 //commit existed txn first 288 err = th.commitUnsafe(execCtx) 289 if err != nil { 290 /* 291 fix issue 6024. 292 When we get a w-w conflict during commit the txn, 293 we convert the error into a readable error. 294 */ 295 if moerr.IsMoErrCode(err, moerr.ErrTxnWWConflict) { 296 return moerr.NewInternalError(execCtx.reqCtx, writeWriteConflictsErrorInfo()) 297 } 298 return err 299 } 300 301 defer func() { 302 if err != nil { 303 tenant := execCtx.tenant 304 incTransactionErrorsCounter(tenant, metric.SQLTypeBegin) 305 } 306 }() 307 err = th.createTxnOpUnsafe(execCtx) 308 if err != nil { 309 return err 310 } 311 if th.txnCtx == nil { 312 panic("context should not be nil") 313 } 314 var accId uint32 315 accId, err = defines.GetAccountId(execCtx.reqCtx) 316 if err != nil { 317 return err 318 } 319 tempCtx := defines.AttachAccountId(th.txnCtx, accId) 320 err = th.storage.New(tempCtx, th.txnOp) 321 if err != nil { 322 execCtx.ses.SetTxnId(dumpUUID[:]) 323 } else { 324 execCtx.ses.SetTxnId(th.txnOp.Txn().ID) 325 } 326 return err 327 } 328 329 // createTxnOpUnsafe creates a new txn operator using TxnClient. Should not be called outside txn 330 func (th *TxnHandler) createTxnOpUnsafe(execCtx *ExecCtx) error { 331 var err error 332 if getGlobalPu().TxnClient == nil { 333 panic("must set txn client") 334 } 335 336 if th.shareTxn { 337 return moerr.NewInternalError(execCtx.reqCtx, "NewTxnOperator: the share txn is not allowed to create new txn") 338 } 339 340 var opts []client.TxnOption 341 rt := moruntime.ProcessLevelRuntime() 342 if rt != nil { 343 if v, ok := rt.GetGlobalVariables(moruntime.TxnOptions); ok { 344 opts = v.([]client.TxnOption) 345 } 346 } 347 if th.txnCtx == nil { 348 panic("context should not be nil") 349 } 350 351 accountID := uint32(0) 352 userName := "" 353 connectionID := uint32(0) 354 if execCtx.proto != nil { 355 connectionID = execCtx.proto.ConnectionID() 356 } 357 if execCtx.ses.GetTenantInfo() != nil { 358 accountID = execCtx.ses.GetTenantInfo().TenantID 359 userName = execCtx.ses.GetTenantInfo().User 360 } 361 sessionInfo := execCtx.ses.GetDebugString() 362 opts = append(opts, 363 client.WithTxnCreateBy( 364 accountID, 365 userName, 366 execCtx.ses.GetUUIDString(), 367 connectionID), 368 client.WithSessionInfo(sessionInfo)) 369 370 if execCtx.ses.GetFromRealUser() { 371 opts = append(opts, 372 client.WithUserTxn()) 373 } 374 375 if execCtx.ses.IsBackgroundSession() || 376 execCtx.ses.DisableTrace() { 377 opts = append(opts, client.WithDisableTrace(true)) 378 } else { 379 varVal, err := execCtx.ses.GetSessionVar(execCtx.reqCtx, "disable_txn_trace") 380 if err != nil { 381 return err 382 } 383 if gsv, ok := GSysVariables.GetDefinitionOfSysVar("disable_txn_trace"); ok { 384 if svbt, ok2 := gsv.GetType().(SystemVariableBoolType); ok2 { 385 if svbt.IsTrue(varVal) { 386 opts = append(opts, client.WithDisableTrace(true)) 387 } 388 } 389 } 390 } 391 392 th.txnOp, err = getGlobalPu().TxnClient.New( 393 th.txnCtx, 394 execCtx.ses.getLastCommitTS(), 395 opts...) 396 if err != nil { 397 return err 398 } 399 if th.txnOp == nil { 400 return moerr.NewInternalError(execCtx.reqCtx, "NewTxnOperator: txnClient new a null txn") 401 } 402 return err 403 } 404 405 func (th *TxnHandler) GetTxn() TxnOperator { 406 th.mu.Lock() 407 defer th.mu.Unlock() 408 return th.txnOp 409 } 410 411 // Commit commits the txn. 412 // option bits decide the actual commit behaviour 413 func (th *TxnHandler) Commit(execCtx *ExecCtx) error { 414 var err error 415 th.mu.Lock() 416 defer th.mu.Unlock() 417 /* 418 Commit Rules: 419 1, if it is in single-statement mode: 420 it commits. 421 2, if it is in multi-statement mode: 422 if the statement is the one can be executed in the active transaction, 423 the transaction need to be committed at the end of the statement. 424 */ 425 if !bitsIsSet(th.optionBits, OPTION_BEGIN|OPTION_NOT_AUTOCOMMIT) || 426 th.inActiveTxnUnsafe() && NeedToBeCommittedInActiveTransaction(execCtx.stmt) || 427 execCtx.txnOpt.byCommit { 428 err = th.commitUnsafe(execCtx) 429 if err != nil { 430 return err 431 } 432 } 433 //do nothing 434 return nil 435 } 436 437 func (th *TxnHandler) commitUnsafe(execCtx *ExecCtx) error { 438 _, span := trace.Start(execCtx.reqCtx, "TxnHandler.CommitTxn", 439 trace.WithKind(trace.SpanKindStatement)) 440 defer span.End(trace.WithStatementExtra(execCtx.ses.GetTxnId(), execCtx.ses.GetStmtId(), execCtx.ses.GetSqlOfStmt())) 441 var err error 442 defer th.inActiveTxnUnsafe() 443 if !th.inActiveTxnUnsafe() || th.shareTxn { 444 return nil 445 } 446 sessionInfo := execCtx.ses.GetDebugString() 447 if th.txnOp == nil { 448 th.invalidateTxnUnsafe() 449 } 450 if th.txnCtx == nil { 451 panic("context should not be nil") 452 } 453 if th.hasTempEngineUnsafe() && th.tempStorage != nil { 454 if th.txnCtx.Value(defines.TemporaryTN{}) == nil { 455 th.txnCtx = context.WithValue(th.txnCtx, defines.TemporaryTN{}, th.tempStorage) 456 } 457 } 458 storage := th.storage 459 ctx2, cancel := context.WithTimeout( 460 th.txnCtx, 461 storage.Hints().CommitOrRollbackTimeout, 462 ) 463 defer cancel() 464 val, e := execCtx.ses.GetSessionVar(execCtx.reqCtx, "mo_pk_check_by_dn") 465 if e != nil { 466 return e 467 } 468 if val != nil { 469 ctx2 = context.WithValue(ctx2, defines.PkCheckByTN{}, val.(int8)) 470 } 471 defer func() { 472 // metric count 473 tenant := execCtx.ses.GetTenantName() 474 incTransactionCounter(tenant) 475 if err != nil { 476 incTransactionErrorsCounter(tenant, metric.SQLTypeCommit) 477 } 478 }() 479 480 if logutil.GetSkip1Logger().Core().Enabled(zap.DebugLevel) { 481 txnId := th.txnOp.Txn().DebugString() 482 logDebugf(sessionInfo, "CommitTxn txnId:%s", txnId) 483 defer func() { 484 logDebugf(sessionInfo, "CommitTxn exit txnId:%s", txnId) 485 }() 486 } 487 if th.txnOp != nil { 488 commitTs := th.txnOp.Txn().CommitTS 489 execCtx.ses.SetTxnId(th.txnOp.Txn().ID) 490 err = th.txnOp.Commit(ctx2) 491 if err != nil { 492 th.invalidateTxnUnsafe() 493 } 494 execCtx.ses.updateLastCommitTS(commitTs) 495 } 496 th.invalidateTxnUnsafe() 497 execCtx.ses.SetTxnId(dumpUUID[:]) 498 return err 499 } 500 501 // Rollback rolls back the txn 502 // the option bits decide the actual behavior 503 func (th *TxnHandler) Rollback(execCtx *ExecCtx) error { 504 var err error 505 th.mu.Lock() 506 defer th.mu.Unlock() 507 /* 508 Rollback Rules: 509 1, if it is in single-statement mode (Case2): 510 it rollbacks. 511 2, if it is in multi-statement mode (Case1,Case3,Case4): 512 the transaction need to be rollback at the end of the statement. 513 (every error will abort the transaction.) 514 */ 515 if !bitsIsSet(th.optionBits, OPTION_BEGIN|OPTION_NOT_AUTOCOMMIT) || 516 th.inActiveTxnUnsafe() && NeedToBeCommittedInActiveTransaction(execCtx.stmt) || 517 execCtx.txnOpt.byRollback { 518 //Case1.1: autocommit && not_begin 519 //Case1.2: (not_autocommit || begin) && activeTxn && needToBeCommitted 520 //Case1.3: the error that should rollback the whole txn 521 err = th.rollbackUnsafe(execCtx) 522 } else { 523 //Case2: not ( autocommit && !begin ) && not ( activeTxn && needToBeCommitted ) 524 //<==> ( not_autocommit || begin ) && not ( activeTxn && needToBeCommitted ) 525 //just rollback statement 526 527 //non derived statement 528 if th.txnOp != nil && !execCtx.ses.IsDerivedStmt() { 529 err = th.txnOp.GetWorkspace().RollbackLastStatement(th.txnCtx) 530 if err != nil { 531 err4 := th.rollbackUnsafe(execCtx) 532 return errors.Join(err, err4) 533 } 534 } 535 } 536 return err 537 } 538 539 func (th *TxnHandler) rollbackUnsafe(execCtx *ExecCtx) error { 540 _, span := trace.Start(execCtx.reqCtx, "TxnHandler.RollbackTxn", 541 trace.WithKind(trace.SpanKindStatement)) 542 defer span.End(trace.WithStatementExtra(execCtx.ses.GetTxnId(), execCtx.ses.GetStmtId(), execCtx.ses.GetSqlOfStmt())) 543 var err error 544 defer th.inActiveTxnUnsafe() 545 if !th.inActiveTxnUnsafe() || th.shareTxn { 546 return nil 547 } 548 549 sessionInfo := execCtx.ses.GetDebugString() 550 551 if th.txnOp == nil { 552 th.invalidateTxnUnsafe() 553 } 554 if th.txnCtx == nil { 555 panic("context should not be nil") 556 } 557 if th.hasTempEngineUnsafe() && th.tempStorage != nil { 558 if th.txnCtx.Value(defines.TemporaryTN{}) == nil { 559 th.txnCtx = context.WithValue(th.txnCtx, defines.TemporaryTN{}, th.tempStorage) 560 } 561 } 562 ctx2, cancel := context.WithTimeout( 563 th.txnCtx, 564 th.storage.Hints().CommitOrRollbackTimeout, 565 ) 566 defer cancel() 567 defer func() { 568 // metric count 569 tenant := execCtx.ses.GetTenantName() 570 incTransactionCounter(tenant) 571 incTransactionErrorsCounter(tenant, metric.SQLTypeOther) // exec rollback cnt 572 if err != nil { 573 incTransactionErrorsCounter(tenant, metric.SQLTypeRollback) 574 } 575 }() 576 if logutil.GetSkip1Logger().Core().Enabled(zap.DebugLevel) { 577 txnId := th.txnOp.Txn().DebugString() 578 logDebugf(sessionInfo, "RollbackTxn txnId:%s", txnId) 579 defer func() { 580 logDebugf(sessionInfo, "RollbackTxn exit txnId:%s", txnId) 581 }() 582 } 583 if th.txnOp != nil { 584 execCtx.ses.SetTxnId(th.txnOp.Txn().ID) 585 err = th.txnOp.Rollback(ctx2) 586 if err != nil { 587 th.invalidateTxnUnsafe() 588 } 589 } 590 th.invalidateTxnUnsafe() 591 execCtx.ses.SetTxnId(dumpUUID[:]) 592 return err 593 } 594 595 /* 596 SetAutocommit sets the value of the system variable 'autocommit'. 597 598 It commits the active transaction if the old value is false and the new value is true. 599 */ 600 func (th *TxnHandler) SetAutocommit(execCtx *ExecCtx, old, on bool) error { 601 th.mu.Lock() 602 defer th.mu.Unlock() 603 //on -> on : do nothing 604 //off -> on : commit active txn 605 // if commit failed, clean OPTION_AUTOCOMMIT 606 // if commit succeeds, clean OPTION_BEGIN | OPTION_NOT_AUTOCOMMIT 607 // and set SERVER_STATUS_AUTOCOMMIT 608 //on -> off : 609 // clean OPTION_AUTOCOMMIT 610 // clean SERVER_STATUS_AUTOCOMMIT 611 // set OPTION_NOT_AUTOCOMMIT 612 //off -> off : do nothing 613 if !old && on { //off -> on 614 //activating autocommit 615 err := th.commitUnsafe(execCtx) 616 if err != nil { 617 clearBits(&th.optionBits, OPTION_AUTOCOMMIT) 618 return err 619 } 620 clearBits(&th.optionBits, OPTION_BEGIN|OPTION_NOT_AUTOCOMMIT) 621 setBits(&th.serverStatus, uint32(SERVER_STATUS_AUTOCOMMIT)) 622 } else if old && !on { //on -> off 623 clearBits(&th.optionBits, OPTION_AUTOCOMMIT) 624 clearBits(&th.serverStatus, uint32(SERVER_STATUS_AUTOCOMMIT)) 625 setBits(&th.optionBits, OPTION_NOT_AUTOCOMMIT) 626 } 627 return nil 628 } 629 630 func (th *TxnHandler) setAutocommitOn() { 631 th.mu.Lock() 632 defer th.mu.Unlock() 633 clearBits(&th.optionBits, OPTION_BEGIN|OPTION_NOT_AUTOCOMMIT) 634 setBits(&th.optionBits, OPTION_AUTOCOMMIT) 635 setBits(&th.serverStatus, uint32(SERVER_STATUS_AUTOCOMMIT)) 636 } 637 638 func (th *TxnHandler) IsShareTxn() bool { 639 th.mu.Lock() 640 defer th.mu.Unlock() 641 return th.shareTxn 642 } 643 644 func (th *TxnHandler) SetOptionBits(bits uint32) { 645 th.mu.Lock() 646 defer th.mu.Unlock() 647 setBits(&th.optionBits, bits) 648 } 649 650 func (th *TxnHandler) GetOptionBits() uint32 { 651 th.mu.Lock() 652 defer th.mu.Unlock() 653 return th.optionBits 654 } 655 656 func (th *TxnHandler) SetServerStatus(status uint16) { 657 th.mu.Lock() 658 defer th.mu.Unlock() 659 setBits(&th.serverStatus, uint32(status)) 660 } 661 662 func (th *TxnHandler) GetServerStatus() uint16 { 663 th.mu.Lock() 664 defer th.mu.Unlock() 665 return uint16(th.serverStatus) 666 } 667 668 func (th *TxnHandler) InMultiStmtTransactionMode() bool { 669 th.mu.Lock() 670 defer th.mu.Unlock() 671 return bitsIsSet(th.optionBits, OPTION_NOT_AUTOCOMMIT|OPTION_BEGIN) 672 } 673 674 func (th *TxnHandler) GetStorage() engine.Engine { 675 th.mu.Lock() 676 defer th.mu.Unlock() 677 return th.storage 678 } 679 680 func (th *TxnHandler) HasTempEngine() bool { 681 th.mu.Lock() 682 defer th.mu.Unlock() 683 return th.hasTempEngineUnsafe() 684 } 685 686 func (th *TxnHandler) hasTempEngineUnsafe() bool { 687 if entireEng, ok := th.storage.(*engine.EntireEngine); ok { 688 return entireEng.TempEngine != nil 689 } 690 return false 691 } 692 693 func (th *TxnHandler) OptionBitsIsSet(bit uint32) bool { 694 th.mu.Lock() 695 defer th.mu.Unlock() 696 return bitsIsSet(th.optionBits, bit) 697 } 698 699 func (th *TxnHandler) CreateTempStorage(ck clock.Clock) error { 700 th.mu.Lock() 701 defer th.mu.Unlock() 702 return th.createTempStorageUnsafe(ck) 703 } 704 705 func (th *TxnHandler) GetTempStorage() *memorystorage.Storage { 706 th.mu.Lock() 707 defer th.mu.Unlock() 708 if th.tempStorage == nil { 709 panic("temp table storage is not initialized") 710 } 711 return th.tempStorage 712 } 713 714 func (th *TxnHandler) GetTempTNService() *metadata.TNService { 715 th.mu.Lock() 716 defer th.mu.Unlock() 717 return th.tempTnService 718 } 719 720 func (th *TxnHandler) createTempStorageUnsafe(ck clock.Clock) error { 721 // Without concurrency, there is no potential for data competition 722 // Arbitrary value is OK since it's single sharded. Let's use 0xbeef 723 // suggested by @reusee 724 shards := []metadata.TNShard{ 725 { 726 ReplicaID: 0xbeef, 727 TNShardRecord: metadata.TNShardRecord{ShardID: 0xbeef}, 728 }, 729 } 730 // Arbitrary value is OK, for more information about TEMPORARY_TABLE_DN_ADDR, please refer to the comment in defines/const.go 731 tnAddr := defines.TEMPORARY_TABLE_TN_ADDR 732 uid, err := uuid.NewV7() 733 if err != nil { 734 return err 735 } 736 th.tempTnService = &metadata.TNService{ 737 ServiceID: uid.String(), 738 TxnServiceAddress: tnAddr, 739 Shards: shards, 740 } 741 742 ms, err := memorystorage.NewMemoryStorage( 743 mpool.MustNewZeroNoFixed(), 744 ck, 745 memoryengine.RandomIDGenerator, 746 ) 747 if err != nil { 748 return err 749 } 750 th.tempStorage = ms 751 return nil 752 } 753 754 func (th *TxnHandler) CreateTempEngine() { 755 th.mu.Lock() 756 defer th.mu.Unlock() 757 758 th.tempEngine = memoryengine.New( 759 context.TODO(), //!!!NOTE: memoryengine.New will neglect this context. 760 memoryengine.NewDefaultShardPolicy( 761 mpool.MustNewZeroNoFixed(), 762 ), 763 memoryengine.RandomIDGenerator, 764 clusterservice.NewMOCluster( 765 nil, 766 0, 767 clusterservice.WithDisableRefresh(), 768 clusterservice.WithServices(nil, []metadata.TNService{ 769 *th.tempTnService, 770 })), 771 ) 772 updateTempEngine(th.storage, th.tempEngine) 773 } 774 775 func (th *TxnHandler) GetTempEngine() *memoryengine.Engine { 776 th.mu.Lock() 777 defer th.mu.Unlock() 778 return th.tempEngine 779 }