|
- package server
-
- import (
- "fmt"
- )
-
- import (
- "github.com/transaction-wg/seata-golang/pkg/base/meta"
- "github.com/transaction-wg/seata-golang/pkg/base/protocal"
- "github.com/transaction-wg/seata-golang/pkg/tc/event"
- "github.com/transaction-wg/seata-golang/pkg/tc/holder"
- "github.com/transaction-wg/seata-golang/pkg/tc/lock"
- "github.com/transaction-wg/seata-golang/pkg/tc/session"
- "github.com/transaction-wg/seata-golang/pkg/util/log"
- "github.com/transaction-wg/seata-golang/pkg/util/runtime"
- "github.com/transaction-wg/seata-golang/pkg/util/time"
- )
-
- /**
- * +--------------------+-----------------------+--------------------+
- * | TC |Method(InBound) |Method(OutBound) |
- * +--------------------+-----------------------+--------------------+
- * | |Begin | |
- * | |BranchRegister | |
- * | AT&TCC |BranchReport |branchCommit |
- * | (DefaultCore) |Commit |branchRollback |
- * | |Rollback | |
- * | |GetStatus | |
- * +--------------------+-----------------------+--------------------+
- * | AT |LockQuery | |
- * +--------------------+-----------------------+--------------------+
- * | |(GlobalReport) | |
- * | |doGlobalCommit | |
- * | SAGA |doGlobalRollBack | |
- * | |doGlobalReport | |
- * +--------------------+-----------------------+--------------------+
- *
- * 参考 [effective go 之 Embedding](#https://my.oschina.net/pengfeix/blog/109967)
- * Go does not provide the typical, type-driven notion of subclassing,
- * but it does have the ability to “borrow” pieces of an implementation
- * by embedding types within a struct or interface.
- * Go 没有像其它面向对象语言中的类继承概念,但是,它可以通过在结构体或者接口中嵌入
- * 其它的类型,来使用被嵌入类型的功能。
- *
- * 原本 JAVA 版 Seata Sever 设计了 Core 接口,AbstractCore 实现该接口,ATCore、
- * TccCore、SagaCore 都继承 AbstractCore。使 ATCore、TccCore、SagaCore 每一
- * 个类单独拿出来都是 Core 接口的实现。但 Go 版的 Seata 我不打算这样设计。我们将
- * Core 接口里定义的接口方法拿出来,如上面的表格所示,一个全局事务的周期分别对应 Begin、
- * BranchRegister、BranchReport、Commit、Rollback 接口方法,这些接口方法适用于
- * AT 模式和 TCC 模式(SAGA 模式暂不了解,先不考虑)。AT 模式会多一个 LockQuery
- * 的接口。另外 OutBound 方向上有两个接口 branchCommit、branchRollback。JAVA 版
- * 的设计中 doGlobalCommit、doGlobalRollBack、doGlobalReport 其实是私有方法,
- * 这里用首字母小些开头的方法区分。那么 Go 版本的 DefaultCore 设计就出来了(暂不考虑 SAGA),
- * DefaultCore 内嵌入 ATCore。
- *
- */
- type AbstractCore struct {
- MessageSender ServerMessageSender
- }
-
- type ATCore struct {
- AbstractCore
- }
-
- type SAGACore struct {
- AbstractCore
- }
-
- type DefaultCore struct {
- AbstractCore
- ATCore
- SAGACore
- coreMap map[meta.BranchType]interface{}
- }
-
- func NewCore(sender ServerMessageSender) TransactionCoordinator {
- return &DefaultCore{
- AbstractCore: AbstractCore{MessageSender: sender},
- ATCore: ATCore{},
- SAGACore: SAGACore{},
- coreMap: make(map[meta.BranchType]interface{}),
- }
- }
-
- func (core *ATCore) branchSessionLock(globalSession *session.GlobalSession, branchSession *session.BranchSession) error {
- result := lock.GetLockManager().AcquireLock(branchSession)
- if !result {
- return &meta.TransactionException{
- Code: meta.TransactionExceptionCodeLockKeyConflict,
- Message: fmt.Sprintf("Branch lock acquire failed xid = %s branchID = %d",
- globalSession.XID, branchSession.BranchID),
- }
- }
- return nil
- }
-
- func (core *ATCore) branchSessionUnlock(branchSession *session.BranchSession) error {
- lock.GetLockManager().ReleaseLock(branchSession)
- return nil
- }
-
- func (core *ATCore) LockQuery(branchType meta.BranchType,
- resourceID string,
- xid string,
- lockKeys string) bool {
- return lock.GetLockManager().IsLockable(xid, resourceID, lockKeys)
- }
-
- func (core *SAGACore) doGlobalCommit(globalSession *session.GlobalSession, retrying bool) (bool, error) {
- return true, nil
- }
-
- func (core *SAGACore) doGlobalRollback(globalSession *session.GlobalSession, retrying bool) (bool, error) {
- return true, nil
- }
-
- func (core *SAGACore) doGlobalReport(globalSession *session.GlobalSession, xid string, param meta.GlobalStatus) error {
- return nil
- }
-
- func (core *DefaultCore) Begin(applicationID string, transactionServiceGroup string, name string, timeout int32) (string, error) {
- gs := session.NewGlobalSession(
- session.WithGsApplicationID(applicationID),
- session.WithGsTransactionServiceGroup(transactionServiceGroup),
- session.WithGsTransactionName(name),
- session.WithGsTimeout(timeout),
- )
-
- gs.Begin()
- err := holder.GetSessionHolder().RootSessionManager.AddGlobalSession(gs)
- if err != nil {
- return "", meta.NewTransactionException(err,
- meta.WithTransactionExceptionCode(meta.TransactionExceptionCodeBeginFailed))
- }
-
- runtime.GoWithRecover(func() {
- evt := event.NewGlobalTransactionEvent(gs.TransactionID, event.RoleTC, gs.TransactionName, gs.BeginTime, 0, gs.Status)
- event.EventBus.GlobalTransactionEventChannel <- evt
- }, nil)
-
- log.Infof("Successfully begin global transaction xid = {}", gs.XID)
- return gs.XID, nil
- }
-
- func (core *DefaultCore) BranchRegister(branchType meta.BranchType,
- resourceID string,
- clientID string,
- xid string,
- applicationData []byte,
- lockKeys string) (int64, error) {
- gs, err := assertGlobalSessionNotNull(xid, false)
- if err != nil {
- return 0, err
- }
- defer gs.Unlock()
- gs.Lock()
-
- err1 := globalSessionStatusCheck(gs)
- if err1 != nil {
- return 0, err
- }
-
- bs := session.NewBranchSessionByGlobal(*gs,
- session.WithBsBranchType(branchType),
- session.WithBsResourceID(resourceID),
- session.WithBsApplicationData(applicationData),
- session.WithBsLockKey(lockKeys),
- session.WithBsClientID(clientID),
- )
-
- if branchType == meta.BranchTypeAT {
- err2 := core.ATCore.branchSessionLock(gs, bs)
- if err2 != nil {
- return 0, err2
- }
- }
- gs.Add(bs)
- err3 := holder.GetSessionHolder().RootSessionManager.AddBranchSession(gs, bs)
- if err3 != nil {
- return 0, meta.NewTransactionException(err3,
- meta.WithTransactionExceptionCode(meta.TransactionExceptionCodeBranchRegisterFailed),
- meta.WithMessage(fmt.Sprintf("Branch register failed,xid = %s, branchID = %d", gs.XID, bs.BranchID)))
- }
- bs.Status = meta.BranchStatusRegistered
-
- log.Infof("Successfully register branch xid = %s, branchID = %d", gs.XID, bs.BranchID)
- return bs.BranchID, nil
- }
-
- func globalSessionStatusCheck(globalSession *session.GlobalSession) error {
- if !globalSession.Active {
- return &meta.TransactionException{
- Code: meta.TransactionExceptionCodeGlobalTransactionNotActive,
- Message: fmt.Sprintf("Could not register branch into global session xid = %s status = %d", globalSession.XID, globalSession.Status),
- }
- }
- if globalSession.Status != meta.GlobalStatusBegin {
- return &meta.TransactionException{
- Code: meta.TransactionExceptionCodeGlobalTransactionStatusInvalid,
- Message: fmt.Sprintf("Could not register branch into global session xid = %s status = %d while expecting %d",
- globalSession.XID, globalSession.Status, meta.GlobalStatusBegin),
- }
- }
- return nil
- }
-
- func assertGlobalSessionNotNull(xid string, withBranchSessions bool) (*session.GlobalSession, error) {
- gs := holder.GetSessionHolder().FindGlobalSessionWithBranchSessions(xid, withBranchSessions)
- if gs == nil {
- log.Errorf("Could not found global transaction xid = %s", xid)
- return nil, &meta.TransactionException{
- Code: meta.TransactionExceptionCodeGlobalTransactionNotExist,
- Message: fmt.Sprintf("Could not found global transaction xid = %s", xid),
- }
- }
- return gs, nil
- }
-
- func (core *DefaultCore) BranchReport(branchType meta.BranchType,
- xid string,
- branchID int64,
- status meta.BranchStatus,
- applicationData []byte) error {
- gs, err := assertGlobalSessionNotNull(xid, true)
- if err != nil {
- return nil
- }
-
- bs := gs.GetBranch(branchID)
- if bs == nil {
- return &meta.TransactionException{
- Code: meta.TransactionExceptionCodeBranchTransactionNotExist,
- Message: fmt.Sprintf("Could not found branch session xid = %s branchID = %d",
- xid, branchID),
- }
- }
-
- bs.Status = status
- err1 := holder.GetSessionHolder().RootSessionManager.UpdateBranchSessionStatus(bs, status)
- if err1 != nil {
- return meta.NewTransactionException(err1,
- meta.WithTransactionExceptionCode(meta.TransactionExceptionCodeBranchReportFailed),
- meta.WithMessage(fmt.Sprintf("Branch report failed,xid = %s, branchID = %d", xid, bs.BranchID)))
- }
-
- log.Infof("Successfully branch report xid = %s, branchID = %d", xid, bs.BranchID)
- return nil
- }
-
- func (core *DefaultCore) LockQuery(branchType meta.BranchType, resourceID string, xid string, lockKeys string) (bool, error) {
- return true, nil
- }
-
- func (core *DefaultCore) branchCommit(globalSession *session.GlobalSession, branchSession *session.BranchSession) (meta.BranchStatus, error) {
- request := protocal.BranchCommitRequest{}
- request.XID = branchSession.XID
- request.BranchID = branchSession.BranchID
- request.ResourceID = branchSession.ResourceID
- request.ApplicationData = branchSession.ApplicationData
- request.BranchType = branchSession.BranchType
-
- resp, err := core.branchCommitSend(request, globalSession, branchSession)
- if err != nil {
- return 0, meta.NewTransactionException(err,
- meta.WithTransactionExceptionCode(meta.TransactionExceptionCodeFailedToSendBranchCommitRequest),
- meta.WithMessage(fmt.Sprintf("Send branch commit failed, xid = %s branchID = %d",
- branchSession.XID, branchSession.BranchID)))
- }
- return resp, err
- }
-
- func (core *DefaultCore) branchCommitSend(request protocal.BranchCommitRequest,
- globalSession *session.GlobalSession, branchSession *session.BranchSession) (meta.BranchStatus, error) {
- resp, err := core.MessageSender.SendSyncRequest(branchSession.ResourceID, branchSession.ClientID, request)
- if err != nil {
- return 0, err
- }
- response := resp.(protocal.BranchCommitResponse)
- return response.BranchStatus, nil
- }
-
- func (core *DefaultCore) branchRollback(globalSession *session.GlobalSession, branchSession *session.BranchSession) (meta.BranchStatus, error) {
- request := protocal.BranchRollbackRequest{}
- request.XID = branchSession.XID
- request.BranchID = branchSession.BranchID
- request.ResourceID = branchSession.ResourceID
- request.ApplicationData = branchSession.ApplicationData
- request.BranchType = branchSession.BranchType
-
- resp, err := core.branchRollbackSend(request, globalSession, branchSession)
- if err != nil {
- return 0, meta.NewTransactionException(err,
- meta.WithTransactionExceptionCode(meta.TransactionExceptionCodeFailedToSendBranchRollbackRequest),
- meta.WithMessage(fmt.Sprintf("Send branch rollback failed, xid = %s branchID = %d",
- branchSession.XID, branchSession.BranchID)))
- }
- return resp, err
- }
-
- func (core *DefaultCore) branchRollbackSend(request protocal.BranchRollbackRequest,
- globalSession *session.GlobalSession, branchSession *session.BranchSession) (meta.BranchStatus, error) {
- resp, err := core.MessageSender.SendSyncRequest(branchSession.ResourceID, branchSession.ClientID, request)
- if err != nil {
- return 0, err
- }
- response := resp.(protocal.BranchRollbackResponse)
- return response.BranchStatus, nil
- }
-
- func (core *DefaultCore) Commit(xid string) (meta.GlobalStatus, error) {
- globalSession := holder.GetSessionHolder().RootSessionManager.FindGlobalSession(xid)
- if globalSession == nil {
- return meta.GlobalStatusFinished, nil
- }
- shouldCommit := func(gs *session.GlobalSession) bool {
- gs.Lock()
- defer gs.Unlock()
- if gs.Active {
- gs.Active = false
- }
- lock.GetLockManager().ReleaseGlobalSessionLock(gs)
- if gs.Status == meta.GlobalStatusBegin {
- changeGlobalSessionStatus(gs, meta.GlobalStatusCommitting)
- return true
- }
- return false
- }(globalSession)
-
- if !shouldCommit {
- if globalSession.Status == meta.GlobalStatusAsyncCommitting {
- return meta.GlobalStatusCommitted, nil
- }
- return globalSession.Status, nil
- }
-
- if globalSession.CanBeCommittedAsync() {
- asyncCommit(globalSession)
- return meta.GlobalStatusCommitted, nil
- } else {
- _, err := core.doGlobalCommit(globalSession, false)
- if err != nil {
- return 0, err
- }
- }
-
- return globalSession.Status, nil
- }
-
- func (core *DefaultCore) doGlobalCommit(globalSession *session.GlobalSession, retrying bool) (bool, error) {
- var (
- success = true
- err error
- )
-
- runtime.GoWithRecover(func() {
- evt := event.NewGlobalTransactionEvent(
- globalSession.TransactionID,
- event.RoleTC,
- globalSession.TransactionName,
- globalSession.BeginTime,
- 0,
- globalSession.Status,
- )
- event.EventBus.GlobalTransactionEventChannel <- evt
- }, nil)
-
- if globalSession.IsSaga() {
- success, err = core.SAGACore.doGlobalCommit(globalSession, retrying)
- } else {
- for _, bs := range globalSession.GetSortedBranches() {
- if bs.Status == meta.BranchStatusPhaseOneFailed {
- _, err := core.branchRollback(globalSession, bs)
- if err == nil {
- removeBranchSession(globalSession, bs)
- }
- break
- }
- branchStatus, err1 := core.branchCommit(globalSession, bs)
- if err1 != nil {
- log.Errorf("Exception committing branch %v", bs)
- if !retrying {
- queueToRetryCommit(globalSession)
- }
- return false, err1
- }
- switch branchStatus {
- case meta.BranchStatusPhaseTwoCommitted:
- removeBranchSession(globalSession, bs)
- continue
- case meta.BranchStatusPhaseTwoCommitFailedCanNotRetry:
- {
- // 二阶段提交失败且不能 Retry,不能异步提交,则移除 GlobalSession,Why?
- if globalSession.CanBeCommittedAsync() {
- log.Errorf("By [%s], failed to commit branch %v", bs.Status.String(), bs)
- continue
- } else {
- endCommitFailed(globalSession)
- log.Errorf("Finally, failed to commit global[%d] since branch[%d] commit failed", globalSession.XID, bs.BranchID)
- return false, nil
- }
- }
- default:
- {
- if !retrying {
- queueToRetryCommit(globalSession)
- return false, nil
- }
- if globalSession.CanBeCommittedAsync() {
- log.Errorf("By [%s], failed to commit branch %v", bs.Status.String(), bs)
- continue
- } else {
- log.Errorf("ResultCodeFailed to commit global[%d] since branch[%d] commit failed, will retry later.", globalSession.XID, bs.BranchID)
- return false, nil
- }
- }
- }
- }
- if globalSession.HasBranch() {
- log.Infof("Global[%d] committing is NOT done.", globalSession.XID)
- return false, nil
- }
- }
-
- if success {
- endCommitted(globalSession)
-
- runtime.GoWithRecover(func() {
- evt := event.NewGlobalTransactionEvent(
- globalSession.TransactionID,
- event.RoleTC,
- globalSession.TransactionName,
- globalSession.BeginTime,
- int64(time.CurrentTimeMillis()),
- globalSession.Status,
- )
- event.EventBus.GlobalTransactionEventChannel <- evt
- }, nil)
-
- log.Infof("Global[%d] committing is successfully done.", globalSession.XID)
- }
- return success, err
- }
-
- func (core *DefaultCore) Rollback(xid string) (meta.GlobalStatus, error) {
- globalSession := holder.GetSessionHolder().RootSessionManager.FindGlobalSession(xid)
- if globalSession == nil {
- return meta.GlobalStatusFinished, nil
- }
- shouldRollBack := func(gs *session.GlobalSession) bool {
- gs.Lock()
- defer gs.Unlock()
- if gs.Active {
- gs.Active = false // Highlight: Firstly, close the session, then no more branch can be registered.
- }
- if gs.Status == meta.GlobalStatusBegin {
- changeGlobalSessionStatus(gs, meta.GlobalStatusRollingBack)
- return true
- }
- return false
- }(globalSession)
-
- if !shouldRollBack {
- return globalSession.Status, nil
- }
-
- core.doGlobalRollback(globalSession, false)
- return globalSession.Status, nil
- }
-
- func (core *DefaultCore) doGlobalRollback(globalSession *session.GlobalSession, retrying bool) (bool, error) {
- var (
- success = true
- err error
- )
-
- runtime.GoWithRecover(func() {
- evt := event.NewGlobalTransactionEvent(globalSession.TransactionID, event.RoleTC, globalSession.TransactionName, globalSession.BeginTime, 0, globalSession.Status)
- event.EventBus.GlobalTransactionEventChannel <- evt
- }, nil)
-
- if globalSession.IsSaga() {
- success, err = core.SAGACore.doGlobalRollback(globalSession, retrying)
- } else {
- for _, bs := range globalSession.GetSortedBranches() {
- if bs.Status == meta.BranchStatusPhaseOneFailed {
- removeBranchSession(globalSession, bs)
- continue
- }
- branchStatus, err1 := core.branchRollback(globalSession, bs)
- if err1 != nil {
- log.Errorf("Exception rolling back branch xid=%d branchID=%d", globalSession.XID, bs.BranchID)
- if !retrying {
- queueToRetryRollback(globalSession)
- }
- return false, err1
- }
- switch branchStatus {
- case meta.BranchStatusPhaseTwoRolledBack:
- removeBranchSession(globalSession, bs)
- log.Infof("Successfully rollback branch xid=%d branchID=%d", globalSession.XID, bs.BranchID)
- continue
- case meta.BranchStatusPhaseTwoRollbackFailedCanNotRetry:
- endRollBackFailed(globalSession)
- log.Infof("ResultCodeFailed to rollback branch and stop retry xid=%d branchID=%d", globalSession.XID, bs.BranchID)
- return false, nil
- default:
- log.Infof("ResultCodeFailed to rollback branch xid=%d branchID=%d", globalSession.XID, bs.BranchID)
- if !retrying {
- queueToRetryRollback(globalSession)
- }
- return false, nil
- }
- }
-
- // In db mode, there is a problem of inconsistent data in multiple copies, resulting in new branch
- // transaction registration when rolling back.
- // 1. New branch transaction and rollback branch transaction have no data association
- // 2. New branch transaction has data association with rollback branch transaction
- // The second query can solve the first problem, and if it is the second problem, it may cause a rollback
- // failure due to data changes.
- gs := holder.GetSessionHolder().RootSessionManager.FindGlobalSession(globalSession.XID)
- if gs != nil && gs.HasBranch() {
- log.Infof("Global[%d] rolling back is NOT done.", globalSession.XID)
- return false, nil
- }
- }
- if success {
- endRollBacked(globalSession)
-
- runtime.GoWithRecover(func() {
- evt := event.NewGlobalTransactionEvent(globalSession.TransactionID, event.RoleTC, globalSession.TransactionName, globalSession.BeginTime,
- int64(time.CurrentTimeMillis()), globalSession.Status)
- event.EventBus.GlobalTransactionEventChannel <- evt
- }, nil)
-
- log.Infof("Successfully rollback global, xid = %d", globalSession.XID)
- }
- return success, err
- }
-
- func (core *DefaultCore) GetStatus(xid string) (meta.GlobalStatus, error) {
- gs := holder.GetSessionHolder().RootSessionManager.FindGlobalSession(xid)
- if gs == nil {
- return meta.GlobalStatusFinished, nil
- } else {
- return gs.Status, nil
- }
- }
-
- func (core *DefaultCore) GlobalReport(xid string, globalStatus meta.GlobalStatus) (meta.GlobalStatus, error) {
- gs := holder.GetSessionHolder().RootSessionManager.FindGlobalSession(xid)
- if gs == nil {
- return globalStatus, nil
- }
- core.doGlobalReport(gs, xid, globalStatus)
- return gs.Status, nil
- }
-
- func (core *DefaultCore) doGlobalReport(globalSession *session.GlobalSession, xid string, globalStatus meta.GlobalStatus) error {
- if globalSession.IsSaga() {
- return core.SAGACore.doGlobalReport(globalSession, xid, globalStatus)
- }
- return nil
- }
-
- func endRollBacked(globalSession *session.GlobalSession) {
- if isTimeoutGlobalStatus(globalSession.Status) {
- changeGlobalSessionStatus(globalSession, meta.GlobalStatusTimeoutRolledBack)
- } else {
- changeGlobalSessionStatus(globalSession, meta.GlobalStatusRolledBack)
- }
- lock.GetLockManager().ReleaseGlobalSessionLock(globalSession)
- holder.GetSessionHolder().RootSessionManager.RemoveGlobalSession(globalSession)
- }
-
- func endRollBackFailed(globalSession *session.GlobalSession) {
- if isTimeoutGlobalStatus(globalSession.Status) {
- changeGlobalSessionStatus(globalSession, meta.GlobalStatusTimeoutRollbackFailed)
- } else {
- changeGlobalSessionStatus(globalSession, meta.GlobalStatusRollbackFailed)
- }
- lock.GetLockManager().ReleaseGlobalSessionLock(globalSession)
- holder.GetSessionHolder().RootSessionManager.RemoveGlobalSession(globalSession)
- }
-
- func queueToRetryRollback(globalSession *session.GlobalSession) {
- holder.GetSessionHolder().RetryRollbackingSessionManager.AddGlobalSession(globalSession)
- if isTimeoutGlobalStatus(globalSession.Status) {
- changeGlobalSessionStatus(globalSession, meta.GlobalStatusTimeoutRollbackRetrying)
- } else {
- changeGlobalSessionStatus(globalSession, meta.GlobalStatusRollbackRetrying)
- }
- }
-
- func isTimeoutGlobalStatus(status meta.GlobalStatus) bool {
- return status == meta.GlobalStatusTimeoutRolledBack ||
- status == meta.GlobalStatusTimeoutRollbackFailed ||
- status == meta.GlobalStatusTimeoutRollingBack ||
- status == meta.GlobalStatusTimeoutRollbackRetrying
- }
-
- func endCommitted(globalSession *session.GlobalSession) {
- changeGlobalSessionStatus(globalSession, meta.GlobalStatusCommitted)
- lock.GetLockManager().ReleaseGlobalSessionLock(globalSession)
- holder.GetSessionHolder().RootSessionManager.RemoveGlobalSession(globalSession)
- }
-
- func endCommitFailed(globalSession *session.GlobalSession) {
- changeGlobalSessionStatus(globalSession, meta.GlobalStatusCommitFailed)
- lock.GetLockManager().ReleaseGlobalSessionLock(globalSession)
- holder.GetSessionHolder().RootSessionManager.RemoveGlobalSession(globalSession)
- }
-
- func queueToRetryCommit(globalSession *session.GlobalSession) {
- holder.GetSessionHolder().RetryCommittingSessionManager.AddGlobalSession(globalSession)
- changeGlobalSessionStatus(globalSession, meta.GlobalStatusCommitRetrying)
- }
-
- func asyncCommit(globalSession *session.GlobalSession) {
- holder.GetSessionHolder().AsyncCommittingSessionManager.AddGlobalSession(globalSession)
- changeGlobalSessionStatus(globalSession, meta.GlobalStatusAsyncCommitting)
- }
-
- func changeGlobalSessionStatus(globalSession *session.GlobalSession, status meta.GlobalStatus) {
- globalSession.Status = status
- holder.GetSessionHolder().RootSessionManager.UpdateGlobalSessionStatus(globalSession, status)
- }
-
- func removeBranchSession(globalSession *session.GlobalSession, branchSession *session.BranchSession) {
- lock.GetLockManager().ReleaseLock(branchSession)
- globalSession.Remove(branchSession)
- holder.GetSessionHolder().RootSessionManager.RemoveBranchSession(globalSession, branchSession)
- }
|