You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

global_session.go 7.6 kB

5 years ago
5 years ago
4 years ago
5 years ago
4 years ago
5 years ago
4 years ago
5 years ago
5 years ago
4 years ago
5 years ago
4 years ago
5 years ago
4 years ago
5 years ago
4 years ago
5 years ago
5 years ago
5 years ago
5 years ago
4 years ago
5 years ago
4 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
4 years ago
5 years ago
4 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
4 years ago
5 years ago
4 years ago
5 years ago
5 years ago
4 years ago
5 years ago
5 years ago
4 years ago
5 years ago
4 years ago
5 years ago
4 years ago
5 years ago
5 years ago
4 years ago
5 years ago
4 years ago
5 years ago
5 years ago
5 years ago
4 years ago
5 years ago
5 years ago
4 years ago
5 years ago
5 years ago
4 years ago
4 years ago
4 years ago
5 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  1. package session
  2. import (
  3. "bytes"
  4. "sort"
  5. "sync"
  6. )
  7. import (
  8. "github.com/pkg/errors"
  9. "vimagination.zapto.org/byteio"
  10. )
  11. import (
  12. "github.com/transaction-wg/seata-golang/pkg/base/common"
  13. "github.com/transaction-wg/seata-golang/pkg/base/meta"
  14. "github.com/transaction-wg/seata-golang/pkg/tc/config"
  15. "github.com/transaction-wg/seata-golang/pkg/util/log"
  16. "github.com/transaction-wg/seata-golang/pkg/util/time"
  17. "github.com/transaction-wg/seata-golang/pkg/util/uuid"
  18. )
  19. type GlobalSession struct {
  20. sync.Mutex
  21. XID string
  22. TransactionID int64
  23. Status meta.GlobalStatus
  24. ApplicationID string
  25. TransactionServiceGroup string
  26. TransactionName string
  27. Timeout int32
  28. BeginTime int64
  29. ApplicationData []byte
  30. Active bool
  31. BranchSessions map[*BranchSession]bool
  32. }
  33. type GlobalSessionOption func(session *GlobalSession)
  34. func WithGsXID(xid string) GlobalSessionOption {
  35. return func(session *GlobalSession) {
  36. session.XID = xid
  37. }
  38. }
  39. func WithGsTransactionID(transactionID int64) GlobalSessionOption {
  40. return func(session *GlobalSession) {
  41. session.TransactionID = transactionID
  42. }
  43. }
  44. func WithGsStatus(status meta.GlobalStatus) GlobalSessionOption {
  45. return func(session *GlobalSession) {
  46. session.Status = status
  47. }
  48. }
  49. func WithGsApplicationID(applicationID string) GlobalSessionOption {
  50. return func(session *GlobalSession) {
  51. session.ApplicationID = applicationID
  52. }
  53. }
  54. func WithGsTransactionServiceGroup(transactionServiceGroup string) GlobalSessionOption {
  55. return func(session *GlobalSession) {
  56. session.TransactionServiceGroup = transactionServiceGroup
  57. }
  58. }
  59. func WithGsTransactionName(transactionName string) GlobalSessionOption {
  60. return func(session *GlobalSession) {
  61. session.TransactionName = transactionName
  62. }
  63. }
  64. func WithGsTimeout(timeout int32) GlobalSessionOption {
  65. return func(session *GlobalSession) {
  66. session.Timeout = timeout
  67. }
  68. }
  69. func WithGsBeginTime(beginTime int64) GlobalSessionOption {
  70. return func(session *GlobalSession) {
  71. session.BeginTime = beginTime
  72. }
  73. }
  74. func WithGsApplicationData(applicationData []byte) GlobalSessionOption {
  75. return func(session *GlobalSession) {
  76. session.ApplicationData = applicationData
  77. }
  78. }
  79. func WithGsActive(active bool) GlobalSessionOption {
  80. return func(session *GlobalSession) {
  81. session.Active = active
  82. }
  83. }
  84. func NewGlobalSession(opts ...GlobalSessionOption) *GlobalSession {
  85. gs := &GlobalSession{
  86. BranchSessions: make(map[*BranchSession]bool),
  87. TransactionID: uuid.NextID(),
  88. Active: true,
  89. }
  90. gs.XID = common.GenerateXID(gs.TransactionID)
  91. for _, o := range opts {
  92. o(gs)
  93. }
  94. return gs
  95. }
  96. func (gs *GlobalSession) Add(branchSession *BranchSession) {
  97. branchSession.Status = meta.BranchStatusRegistered
  98. gs.BranchSessions[branchSession] = true
  99. }
  100. func (gs *GlobalSession) Remove(branchSession *BranchSession) {
  101. delete(gs.BranchSessions, branchSession)
  102. }
  103. func (gs *GlobalSession) CanBeCommittedAsync() bool {
  104. for branchSession := range gs.BranchSessions {
  105. if branchSession.BranchType == meta.BranchTypeTCC {
  106. return false
  107. }
  108. }
  109. return true
  110. }
  111. func (gs *GlobalSession) IsSaga() bool {
  112. for branchSession := range gs.BranchSessions {
  113. if branchSession.BranchType == meta.BranchTypeSAGA {
  114. return true
  115. } else {
  116. return false
  117. }
  118. }
  119. return false
  120. }
  121. func (gs *GlobalSession) IsTimeout() bool {
  122. return (time.CurrentTimeMillis() - uint64(gs.BeginTime)) > uint64(gs.Timeout)
  123. }
  124. func (gs *GlobalSession) IsRollbackingDead() bool {
  125. return (time.CurrentTimeMillis() - uint64(gs.BeginTime)) > uint64(2*6000)
  126. }
  127. func (gs *GlobalSession) GetSortedBranches() []*BranchSession {
  128. var branchSessions = make([]*BranchSession, 0)
  129. for branchSession := range gs.BranchSessions {
  130. branchSessions = append(branchSessions, branchSession)
  131. }
  132. return branchSessions
  133. }
  134. func (gs *GlobalSession) GetReverseSortedBranches() []*BranchSession {
  135. var branchSessions = gs.GetSortedBranches()
  136. sort.Sort(sort.Reverse(BranchSessionSlice(branchSessions)))
  137. return branchSessions
  138. }
  139. type BranchSessionSlice []*BranchSession
  140. func (p BranchSessionSlice) Len() int { return len(p) }
  141. func (p BranchSessionSlice) Less(i, j int) bool { return p[i].CompareTo(p[j]) > 0 }
  142. func (p BranchSessionSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
  143. func (gs *GlobalSession) GetBranch(branchID int64) *BranchSession {
  144. gs.Lock()
  145. defer gs.Unlock()
  146. for branchSession := range gs.BranchSessions {
  147. if branchSession.BranchID == branchID {
  148. return branchSession
  149. }
  150. }
  151. return nil
  152. }
  153. func (gs *GlobalSession) HasBranch() bool {
  154. return len(gs.BranchSessions) > 0
  155. }
  156. func (gs *GlobalSession) Begin() {
  157. gs.Status = meta.GlobalStatusBegin
  158. gs.BeginTime = int64(time.CurrentTimeMillis())
  159. gs.Active = true
  160. }
  161. func (gs *GlobalSession) Encode() ([]byte, error) {
  162. var (
  163. zero32 int32 = 0
  164. zero16 int16 = 0
  165. )
  166. size := calGlobalSessionSize(len(gs.ApplicationID), len(gs.TransactionServiceGroup), len(gs.TransactionName), len(gs.XID), len(gs.ApplicationData))
  167. if size > config.GetStoreConfig().MaxGlobalSessionSize {
  168. log.Errorf("global session size exceeded, size : %d maxGlobalSessionSize : %d", size, config.GetStoreConfig().MaxGlobalSessionSize)
  169. //todo compress
  170. return nil, errors.New("global session size exceeded.")
  171. }
  172. var b bytes.Buffer
  173. w := byteio.BigEndianWriter{Writer: &b}
  174. w.WriteInt64(gs.TransactionID)
  175. w.WriteInt32(gs.Timeout)
  176. // applicationID 长度不会超过 256
  177. if gs.ApplicationID != "" {
  178. w.WriteUint16(uint16(len(gs.ApplicationID)))
  179. w.WriteString(gs.ApplicationID)
  180. } else {
  181. w.WriteInt16(zero16)
  182. }
  183. if gs.TransactionServiceGroup != "" {
  184. w.WriteUint16(uint16(len(gs.TransactionServiceGroup)))
  185. w.WriteString(gs.TransactionServiceGroup)
  186. } else {
  187. w.WriteInt16(zero16)
  188. }
  189. if gs.TransactionName != "" {
  190. w.WriteUint16(uint16(len(gs.TransactionName)))
  191. w.WriteString(gs.TransactionName)
  192. } else {
  193. w.WriteInt16(zero16)
  194. }
  195. if gs.XID != "" {
  196. w.WriteUint32(uint32(len(gs.XID)))
  197. w.WriteString(gs.XID)
  198. } else {
  199. w.WriteInt32(zero32)
  200. }
  201. if gs.ApplicationData != nil {
  202. w.WriteUint32(uint32(len(gs.ApplicationData)))
  203. w.Write(gs.ApplicationData)
  204. } else {
  205. w.WriteInt32(zero32)
  206. }
  207. w.WriteInt64(gs.BeginTime)
  208. w.WriteByte(byte(gs.Status))
  209. return b.Bytes(), nil
  210. }
  211. func (gs *GlobalSession) Decode(b []byte) {
  212. var length32 uint32 = 0
  213. var length16 uint16 = 0
  214. r := byteio.BigEndianReader{Reader: bytes.NewReader(b)}
  215. gs.TransactionID, _, _ = r.ReadInt64()
  216. gs.Timeout, _, _ = r.ReadInt32()
  217. length16, _, _ = r.ReadUint16()
  218. if length16 > 0 {
  219. gs.ApplicationID, _, _ = r.ReadString(int(length16))
  220. }
  221. length16, _, _ = r.ReadUint16()
  222. if length16 > 0 {
  223. gs.TransactionServiceGroup, _, _ = r.ReadString(int(length16))
  224. }
  225. length16, _, _ = r.ReadUint16()
  226. if length16 > 0 {
  227. gs.TransactionName, _, _ = r.ReadString(int(length16))
  228. }
  229. length32, _, _ = r.ReadUint32()
  230. if length32 > 0 {
  231. gs.XID, _, _ = r.ReadString(int(length32))
  232. }
  233. length32, _, _ = r.ReadUint32()
  234. if length32 > 0 {
  235. gs.ApplicationData = make([]byte, length32, length32)
  236. r.Read(gs.ApplicationData)
  237. }
  238. gs.BeginTime, _, _ = r.ReadInt64()
  239. status, _ := r.ReadByte()
  240. gs.Status = meta.GlobalStatus(status)
  241. }
  242. func calGlobalSessionSize(applicationIDLen int,
  243. serviceGroupLen int,
  244. txNameLen int,
  245. xidLen int,
  246. applicationDataLen int,
  247. ) int {
  248. size := 8 + // transactionID
  249. 4 + // timeout
  250. 2 + // byApplicationIDBytes.length
  251. 2 + // byServiceGroupBytes.length
  252. 2 + // byTxNameBytes.length
  253. 4 + // xidBytes.length
  254. 4 + // applicationDataBytes.length
  255. 8 + // beginTime
  256. 1 + // statusCode
  257. applicationIDLen +
  258. serviceGroupLen +
  259. txNameLen +
  260. xidLen +
  261. applicationDataLen
  262. return size
  263. }