package holder import ( "github.com/transaction-wg/seata-golang/pkg/base/meta" "github.com/transaction-wg/seata-golang/pkg/tc/config" "github.com/transaction-wg/seata-golang/pkg/tc/session" "github.com/transaction-wg/seata-golang/pkg/util/log" ) type FileBasedSessionManager struct { conf config.FileStoreConfig DefaultSessionManager } func NewFileBasedSessionManager(conf config.FileStoreConfig) SessionManager { transactionStoreManager := &FileTransactionStoreManager{} transactionStoreManager.InitFile(conf.FileDir) sessionManager := DefaultSessionManager{ AbstractSessionManager: AbstractSessionManager{ TransactionStoreManager: transactionStoreManager, Name: conf.FileDir, }, SessionMap: make(map[string]*session.GlobalSession), } transactionStoreManager.SessionManager = &sessionManager return &FileBasedSessionManager{ conf: conf, DefaultSessionManager: sessionManager, } } func (sessionManager *FileBasedSessionManager) Reload() { sessionManager.restoreSessions() sessionManager.washSessions() } func (sessionManager *FileBasedSessionManager) restoreSessions() { unhandledBranchBuffer := make(map[int64]*session.BranchSession) sessionManager.restoreSessionsToUnhandledBranchBuffer(true, unhandledBranchBuffer) sessionManager.restoreSessionsToUnhandledBranchBuffer(false, unhandledBranchBuffer) if len(unhandledBranchBuffer) > 0 { for _, branchSession := range unhandledBranchBuffer { found := sessionManager.SessionMap[branchSession.XID] if found == nil { log.Warnf("GlobalSession Does Not Exists For BranchSession [%d/%s]", branchSession.BranchID, branchSession.XID) } else { existingBranch := found.GetBranch(branchSession.BranchID) if existingBranch == nil { found.Add(branchSession) } else { existingBranch.Status = branchSession.Status } } } } } func (sessionManager *FileBasedSessionManager) restoreSessionsToUnhandledBranchBuffer(isHistory bool, unhandledBranchSessions map[int64]*session.BranchSession) { transactionStoreManager, ok := sessionManager.TransactionStoreManager.(ReloadableStore) if !ok { return } for { if transactionStoreManager.HasRemaining(isHistory) { stores := transactionStoreManager.ReadWriteStore(sessionManager.conf.SessionReloadReadSize, isHistory) sessionManager.restore(stores, unhandledBranchSessions) } else { break } } } func (sessionManager *FileBasedSessionManager) washSessions() { if len(sessionManager.SessionMap) > 0 { for _, globalSession := range sessionManager.SessionMap { switch globalSession.Status { case meta.GlobalStatusUnknown, meta.GlobalStatusCommitted, meta.GlobalStatusCommitFailed, meta.GlobalStatusRolledBack, meta.GlobalStatusRollbackFailed, meta.GlobalStatusTimeoutRolledBack, meta.GlobalStatusTimeoutRollbackFailed, meta.GlobalStatusFinished: // Remove all sessions finished delete(sessionManager.SessionMap, globalSession.XID) default: } } } } func (sessionManager *FileBasedSessionManager) restore(stores []*TransactionWriteStore, unhandledBranchSessions map[int64]*session.BranchSession) { for _, store := range stores { logOperation := store.LogOperation sessionStorable := store.SessionRequest switch logOperation { case LogOperationGlobalAdd, LogOperationGlobalUpdate: { globalSession := sessionStorable.(*session.GlobalSession) if globalSession.TransactionID == int64(0) { log.Errorf("Restore globalSession from file failed, the transactionID is zero , xid:%s", globalSession.XID) break } foundGlobalSession := sessionManager.SessionMap[globalSession.XID] if foundGlobalSession == nil { sessionManager.SessionMap[globalSession.XID] = globalSession } else { foundGlobalSession.Status = globalSession.Status } break } case LogOperationGlobalRemove: { globalSession := sessionStorable.(*session.GlobalSession) if globalSession.TransactionID == int64(0) { log.Errorf("Restore globalSession from file failed, the transactionID is zero , xid:%s", globalSession.XID) break } delete(sessionManager.SessionMap, globalSession.XID) break } case LogOperationBranchAdd, LogOperationBranchUpdate: { branchSession := sessionStorable.(*session.BranchSession) if branchSession.TransactionID == int64(0) { log.Errorf("Restore branchSession from file failed, the transactionID is zero , xid:%s", branchSession.XID) break } foundGlobalSession := sessionManager.SessionMap[branchSession.XID] if foundGlobalSession == nil { unhandledBranchSessions[branchSession.BranchID] = branchSession } else { existingBranch := foundGlobalSession.GetBranch(branchSession.BranchID) if existingBranch == nil { foundGlobalSession.Add(branchSession) } else { existingBranch.Status = branchSession.Status } } break } case LogOperationBranchRemove: { branchSession := sessionStorable.(*session.BranchSession) if branchSession.TransactionID == int64(0) { log.Errorf("Restore branchSession from file failed, the transactionID is zero , xid:%s", branchSession.XID) break } foundGlobalSession := sessionManager.SessionMap[branchSession.XID] if foundGlobalSession == nil { log.Infof("GlobalSession To Be Updated (Remove Branch) Does Not Exists [%d/%s]", branchSession.BranchID, branchSession.XID) } else { existingBranch := foundGlobalSession.GetBranch(branchSession.BranchID) if existingBranch == nil { log.Infof("BranchSession To Be Updated Does Not Exists [%d/%s]", branchSession.BranchID, branchSession.XID) } else { foundGlobalSession.Remove(existingBranch) } } break } default: } } }