github.com/matrixorigin/matrixone@v1.2.0/pkg/pb/txn/txn.go (about) 1 // Copyright 2021 - 2022 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 txn 16 17 import ( 18 "bytes" 19 "encoding/hex" 20 "fmt" 21 "strings" 22 23 "github.com/matrixorigin/matrixone/pkg/common/moerr" 24 "github.com/matrixorigin/matrixone/pkg/pb/metadata" 25 ) 26 27 const ( 28 // SkipResponseFlag skip response. 29 SkipResponseFlag uint32 = 1 30 ) 31 32 // NewTxnRequest create TxnRequest by CNOpRequest 33 func NewTxnRequest(request *CNOpRequest) TxnRequest { 34 return TxnRequest{CNRequest: request} 35 } 36 37 // GetCNOpResponse returns the CNOpResponse from TxnResponse 38 func GetCNOpResponse(response TxnResponse) CNOpResponse { 39 return *response.CNOpResponse 40 } 41 42 // HasFlag returns true if has the spec flag 43 func (m TxnResponse) HasFlag(flag uint32) bool { 44 return m.Flag&flag > 0 45 } 46 47 // DebugString returns debug string 48 func (m TxnRequest) DebugString() string { 49 return m.DebugStringWithPayload(true) 50 } 51 52 // DebugStringWithPayload returns debug string with payload bytes if 53 // withPayload is true 54 func (m TxnRequest) DebugStringWithPayload(withPayload bool) string { 55 var buffer bytes.Buffer 56 57 buffer.WriteString(fmt.Sprintf("%d: ", m.RequestID)) 58 59 buffer.WriteString("<") 60 buffer.WriteString(m.Txn.DebugString()) 61 buffer.WriteString(">/") 62 63 buffer.WriteString(m.Method.String()) 64 buffer.WriteString("/") 65 buffer.WriteString(fmt.Sprintf("F-%d", m.Flag)) 66 67 if withPayload && m.CNRequest != nil { 68 buffer.WriteString("/<") 69 buffer.WriteString(m.CNRequest.DebugString()) 70 buffer.WriteString(">") 71 } 72 buffer.WriteString("/=><") 73 buffer.WriteString(m.GetTargetTN().DebugString()) 74 buffer.WriteString(">") 75 return buffer.String() 76 } 77 78 // DebugString returns debug string 79 func (m TxnError) DebugString() string { 80 return fmt.Sprintf("%d: %s", m.TxnErrCode, m.UnwrapError().Error()) 81 } 82 83 // DebugString returns debug string 84 func (m TxnResponse) DebugString() string { 85 var buffer bytes.Buffer 86 87 buffer.WriteString(fmt.Sprintf("%d: ", 88 m.RequestID)) 89 90 if m.Txn != nil { 91 buffer.WriteString("<") 92 buffer.WriteString(m.Txn.DebugString()) 93 buffer.WriteString(">/") 94 } 95 96 buffer.WriteString(m.Method.String()) 97 buffer.WriteString("/") 98 buffer.WriteString(fmt.Sprintf("F:%d", m.Flag)) 99 100 if m.TxnError != nil { 101 buffer.WriteString("/") 102 buffer.WriteString(m.TxnError.DebugString()) 103 } 104 105 if m.CNOpResponse != nil { 106 buffer.WriteString("/") 107 buffer.WriteString(m.CNOpResponse.DebugString()) 108 } 109 110 return buffer.String() 111 } 112 113 // DebugString returns debug string 114 func (m CNOpRequest) DebugString() string { 115 return fmt.Sprintf("O:%d-D:%d", m.OpCode, len(m.Payload)) 116 } 117 118 // DebugString returns debug string 119 func (m CNOpResponse) DebugString() string { 120 return fmt.Sprintf("D:%d", len(m.Payload)) 121 } 122 123 // DebugString returns debug string 124 func (m TxnMeta) DebugString() string { 125 var buffer bytes.Buffer 126 127 buffer.WriteString(hex.EncodeToString(m.ID)) 128 buffer.WriteString("/") 129 buffer.WriteString(m.Status.String()) 130 buffer.WriteString("/S:") 131 buffer.WriteString(m.SnapshotTS.DebugString()) 132 133 if !m.PreparedTS.IsEmpty() { 134 buffer.WriteString("/P:") 135 buffer.WriteString(m.PreparedTS.DebugString()) 136 } 137 138 if !m.CommitTS.IsEmpty() { 139 buffer.WriteString("/C:") 140 buffer.WriteString(m.CommitTS.DebugString()) 141 } 142 143 n := len(m.TNShards) 144 var buf bytes.Buffer 145 buf.WriteString("/<") 146 for idx, tn := range m.TNShards { 147 buf.WriteString(tn.DebugString()) 148 if idx < n-1 { 149 buf.WriteString(", ") 150 } 151 } 152 buf.WriteString(">") 153 return buffer.String() 154 } 155 156 // GetTargetTN return tn shard ID that message need send to. 157 func (m TxnRequest) GetTargetTN() metadata.TNShard { 158 switch m.Method { 159 case TxnMethod_Read, TxnMethod_Write, TxnMethod_DEBUG: 160 return m.CNRequest.Target 161 case TxnMethod_Commit: 162 return m.Txn.TNShards[0] 163 case TxnMethod_Rollback: 164 return m.Txn.TNShards[0] 165 case TxnMethod_Prepare: 166 return m.PrepareRequest.TNShard 167 case TxnMethod_GetStatus: 168 return m.GetStatusRequest.TNShard 169 case TxnMethod_CommitTNShard: 170 return m.CommitTNShardRequest.TNShard 171 case TxnMethod_RollbackTNShard: 172 return m.RollbackTNShardRequest.TNShard 173 default: 174 panic(fmt.Sprintf("unknown txn request method: %v", m.Method)) 175 } 176 } 177 178 // SetID implement morpc Messgae 179 func (m *TxnRequest) SetID(id uint64) { 180 m.RequestID = id 181 } 182 183 // GetID implement morpc Messgae 184 func (m *TxnRequest) GetID() uint64 { 185 return m.RequestID 186 } 187 188 // SetID implement morpc Messgae 189 func (m *TxnResponse) SetID(id uint64) { 190 m.RequestID = id 191 } 192 193 // GetID implement morpc Messgae 194 func (m *TxnResponse) GetID() uint64 { 195 return m.RequestID 196 } 197 198 // RequestsDebugString returns requests debug string 199 func RequestsDebugString(requests []TxnRequest, withPayload bool) string { 200 n := len(requests) 201 var buf bytes.Buffer 202 buf.WriteString("[") 203 for idx, req := range requests { 204 buf.WriteString(req.DebugStringWithPayload(withPayload)) 205 if idx < n-1 { 206 buf.WriteString(", ") 207 } 208 } 209 buf.WriteString("]") 210 return buf.String() 211 } 212 213 // ResponsesDebugString returns responses debug string 214 func ResponsesDebugString(responses []TxnResponse) string { 215 n := len(responses) 216 var buf bytes.Buffer 217 buf.WriteString("[") 218 for idx, resp := range responses { 219 buf.WriteString(resp.DebugString()) 220 if idx < n-1 { 221 buf.WriteString(", ") 222 } 223 } 224 buf.WriteString("]") 225 return buf.String() 226 } 227 228 // WrapError wrapper error to TxnError 229 func WrapError(err error, internalCode uint16) *TxnError { 230 if me, ok := err.(*moerr.Error); ok { 231 data, e := me.MarshalBinary() 232 if e != nil { 233 panic(e) 234 } 235 v := &TxnError{Error: data, Code: uint32(me.ErrorCode())} 236 v.TxnErrCode = v.Code 237 if internalCode != 0 { 238 v.TxnErrCode = uint32(internalCode) 239 } 240 return v 241 } 242 243 return WrapError(moerr.NewInternalErrorNoCtx(err.Error()), internalCode) 244 } 245 246 // UnwrapError unwrap the moerr from the TxnError 247 func (m TxnError) UnwrapError() error { 248 err := &moerr.Error{} 249 if e := err.UnmarshalBinary(m.Error); e != nil { 250 panic(e) 251 } 252 return err 253 } 254 255 // GetTxnMode get txn mode from string 256 func GetTxnMode(value string) TxnMode { 257 for name, m := range TxnMode_value { 258 if strings.EqualFold(name, value) { 259 return TxnMode(m) 260 } 261 } 262 panic("BUG") 263 } 264 265 // GetTxnIsolation get txn mode from string 266 func GetTxnIsolation(value string) TxnIsolation { 267 for name, m := range TxnIsolation_value { 268 if strings.EqualFold(name, value) { 269 return TxnIsolation(m) 270 } 271 } 272 panic("BUG") 273 } 274 275 // ValidTxnMode valid txn mode 276 func ValidTxnMode(value string) bool { 277 found := true 278 for name := range TxnMode_value { 279 if strings.EqualFold(name, value) { 280 found = true 281 break 282 } 283 } 284 return found 285 } 286 287 // ValidTxnIsolation valid txn isolation 288 func ValidTxnIsolation(value string) bool { 289 found := true 290 for name := range TxnIsolation_value { 291 if strings.EqualFold(name, value) { 292 found = true 293 break 294 } 295 } 296 return found 297 } 298 299 // IsRCIsolation returns the isolation of current txn 300 func (m TxnMeta) IsRCIsolation() bool { 301 return m.Isolation == TxnIsolation_RC 302 } 303 304 // IsPessimistic returns true if txn is in pessimistic mode 305 func (m TxnMeta) IsPessimistic() bool { 306 return m.Mode == TxnMode_Pessimistic 307 }