github.com/matrixorigin/matrixone@v1.2.0/pkg/vm/engine/tae/txn/txnbase/command.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 txnbase 16 17 import ( 18 "bytes" 19 "fmt" 20 "io" 21 "math" 22 23 "github.com/matrixorigin/matrixone/pkg/container/types" 24 "github.com/matrixorigin/matrixone/pkg/objectio" 25 26 "github.com/matrixorigin/matrixone/pkg/vm/engine/tae/iface/txnif" 27 "github.com/matrixorigin/matrixone/pkg/vm/engine/tae/model" 28 ) 29 30 const ( 31 IOET_WALTxnEntry uint16 = 3000 32 IOET_WALTxnCommand_Composed uint16 = 3001 33 IOET_WALTxnCommand_TxnState uint16 = 3002 34 35 IOET_WALTxnEntry_V1 uint16 = 1 36 IOET_WALTxnEntry_V2 uint16 = 2 37 IOET_WALTxnEntry_V3 uint16 = 3 38 IOET_WALTxnCommand_Composed_V1 uint16 = 1 39 IOET_WALTxnCommand_TxnState_V1 uint16 = 1 40 41 IOET_WALTxnEntry_CurrVer = IOET_WALTxnEntry_V3 42 IOET_WALTxnCommand_Composed_CurrVer = IOET_WALTxnCommand_Composed_V1 43 IOET_WALTxnCommand_TxnState_CurrVer = IOET_WALTxnCommand_TxnState_V1 44 45 // CmdBufReserved is reserved size of cmd buffer, mainly the size of TxnCtx.Memo. 46 // ComposedCmd.CmdBufLimit is the max buffer size that could be sent out to log-service. 47 // This value is normally the max RPC message size which is configured in config of DN. 48 // The message contains mainly commands, but also other information whose size is CmdBufReserved. 49 // TODO(volgariver6): this buf size is about the max size of TxnCt.Memo, we need to calculate 50 // the exact size of it. 51 CmdBufReserved = 1024 * 1024 * 10 52 ) 53 54 func init() { 55 objectio.RegisterIOEnrtyCodec( 56 objectio.IOEntryHeader{ 57 Type: IOET_WALTxnEntry, 58 Version: IOET_WALTxnEntry_V1, 59 }, 60 nil, 61 func(b []byte) (any, error) { 62 txnEntry := NewEmptyTxnCmd() 63 err := txnEntry.UnmarshalBinaryWithVersion(b, IOET_WALTxnEntry_V1) 64 return txnEntry, err 65 }, 66 ) 67 objectio.RegisterIOEnrtyCodec( 68 objectio.IOEntryHeader{ 69 Type: IOET_WALTxnEntry, 70 Version: IOET_WALTxnEntry_V2, 71 }, 72 nil, 73 func(b []byte) (any, error) { 74 txnEntry := NewEmptyTxnCmd() 75 err := txnEntry.UnmarshalBinaryWithVersion(b, IOET_WALTxnEntry_V2) 76 return txnEntry, err 77 }, 78 ) 79 objectio.RegisterIOEnrtyCodec( 80 objectio.IOEntryHeader{ 81 Type: IOET_WALTxnEntry, 82 Version: IOET_WALTxnEntry_V3, 83 }, 84 nil, 85 func(b []byte) (any, error) { 86 txnEntry := NewEmptyTxnCmd() 87 err := txnEntry.UnmarshalBinaryWithVersion(b, IOET_WALTxnEntry_V3) 88 return txnEntry, err 89 }, 90 ) 91 objectio.RegisterIOEnrtyCodec( 92 objectio.IOEntryHeader{ 93 Type: IOET_WALTxnCommand_Composed, 94 Version: IOET_WALTxnCommand_Composed_V1, 95 }, 96 nil, 97 func(b []byte) (any, error) { 98 txnEntry := NewComposedCmd(0) 99 err := txnEntry.UnmarshalBinary(b) 100 return txnEntry, err 101 }, 102 ) 103 objectio.RegisterIOEnrtyCodec( 104 objectio.IOEntryHeader{ 105 Type: IOET_WALTxnCommand_TxnState, 106 Version: IOET_WALTxnCommand_TxnState_V1, 107 }, 108 nil, 109 func(b []byte) (any, error) { 110 txnEntry := NewEmptyTxnStateCmd() 111 err := txnEntry.UnmarshalBinary(b) 112 return txnEntry, err 113 }, 114 ) 115 } 116 117 type BaseCmd struct{} 118 119 func (base *BaseCmd) Close() {} 120 121 type TxnCmd struct { 122 *ComposedCmd 123 *TxnCtx 124 Txn txnif.AsyncTxn 125 126 // for replay 127 isLast bool 128 Lsn uint64 129 } 130 131 type TxnStateCmd struct { 132 ID string 133 State txnif.TxnState 134 CommitTs types.TS 135 } 136 137 type ComposedCmd struct { 138 Cmds []txnif.TxnCmd 139 140 // CmdBufLimit indicates max cmd buffer size. We can only send out 141 // the cmd buffer whose size is less than it. 142 CmdBufLimit int64 143 144 // lastPos is the position in the Cmds list, before which the cmds have 145 // been marshalled into buffer. 146 LastPos int 147 } 148 149 type BaseCustomizedCmd struct { 150 BaseCmd 151 ID uint32 152 Impl txnif.TxnCmd 153 } 154 155 func NewBaseCustomizedCmd(id uint32, impl txnif.TxnCmd) *BaseCustomizedCmd { 156 return &BaseCustomizedCmd{ 157 ID: id, 158 Impl: impl, 159 } 160 } 161 162 func NewComposedCmd(maxSize uint64) *ComposedCmd { 163 if maxSize < CmdBufReserved { 164 maxSize = math.MaxInt64 165 } 166 return &ComposedCmd{ 167 Cmds: make([]txnif.TxnCmd, 0), 168 CmdBufLimit: int64(maxSize - CmdBufReserved), 169 LastPos: -1, // init value. 170 } 171 } 172 173 func (c *BaseCustomizedCmd) GetID() uint32 { 174 return c.ID 175 } 176 177 func NewEmptyTxnStateCmd() *TxnStateCmd { 178 return &TxnStateCmd{} 179 } 180 181 func NewTxnStateCmd(id string, state txnif.TxnState, cts types.TS) *TxnStateCmd { 182 return &TxnStateCmd{ 183 ID: id, 184 State: state, 185 CommitTs: cts, 186 } 187 } 188 189 func (c *TxnStateCmd) WriteTo(w io.Writer) (n int64, err error) { 190 t := c.GetType() 191 if _, err = w.Write(types.EncodeUint16(&t)); err != nil { 192 return 193 } 194 n += 2 195 ver := IOET_WALTxnCommand_TxnState_CurrVer 196 if _, err = w.Write(types.EncodeUint16(&ver)); err != nil { 197 return 198 } 199 n += 2 200 var sn int64 201 if sn, err = objectio.WriteString(c.ID, w); err != nil { 202 return 203 } 204 n += sn 205 state := int32(c.State) 206 if _, err = w.Write(types.EncodeInt32(&state)); err != nil { 207 return 208 } 209 n += 4 210 if _, err = w.Write(c.CommitTs[:]); err != nil { 211 return 212 } 213 n += types.TxnTsSize 214 return 215 } 216 217 func (c *TxnStateCmd) ReadFrom(r io.Reader) (n int64, err error) { 218 var sn int64 219 if c.ID, sn, err = objectio.ReadString(r); err != nil { 220 return 221 } 222 n += sn 223 state := int32(0) 224 if _, err = r.Read(types.EncodeInt32(&state)); err != nil { 225 return 226 } 227 c.State = txnif.TxnState(state) 228 n += 4 229 if _, err = r.Read(c.CommitTs[:]); err != nil { 230 return 231 } 232 n += types.TxnTsSize 233 return 234 } 235 func (c *TxnStateCmd) MarshalBinary() (buf []byte, err error) { 236 var bbuf bytes.Buffer 237 if _, err = c.WriteTo(&bbuf); err != nil { 238 return 239 } 240 buf = bbuf.Bytes() 241 return 242 } 243 func (c *TxnStateCmd) ApplyCommit() {} 244 func (c *TxnStateCmd) ApplyRollback() {} 245 func (c *TxnStateCmd) SetReplayTxn(_ txnif.AsyncTxn) {} 246 func (c *TxnStateCmd) UnmarshalBinary(buf []byte) (err error) { 247 bbuf := bytes.NewBuffer(buf) 248 _, err = c.ReadFrom(bbuf) 249 return err 250 } 251 func (c *TxnStateCmd) GetType() uint16 { return IOET_WALTxnCommand_TxnState } 252 func (c *TxnStateCmd) Desc() string { 253 return fmt.Sprintf("Tid=%s,State=%s,Cts=%s", c.ID, txnif.TxnStrState(c.State), c.CommitTs.ToString()) 254 } 255 func (c *TxnStateCmd) String() string { 256 return fmt.Sprintf("Tid=%s,State=%v,Cts=%s", c.ID, txnif.TxnStrState(c.State), c.CommitTs.ToString()) 257 } 258 func (c *TxnStateCmd) VerboseString() string { 259 return fmt.Sprintf("Tid=%s,State=%v,Cts=%s", c.ID, txnif.TxnStrState(c.State), c.CommitTs.ToString()) 260 } 261 func (c *TxnStateCmd) Close() { 262 } 263 264 func NewTxnCmd(maxMessageSize uint64) *TxnCmd { 265 return &TxnCmd{ 266 ComposedCmd: NewComposedCmd(maxMessageSize), 267 TxnCtx: &TxnCtx{}, 268 } 269 } 270 func NewEmptyTxnCmd() *TxnCmd { 271 return &TxnCmd{ 272 TxnCtx: NewEmptyTxnCtx(), 273 } 274 } 275 func NewLastTxnCmd() *TxnCmd { 276 return &TxnCmd{ 277 isLast: true, 278 } 279 } 280 func (c *TxnCmd) IsLastCmd() bool { return c.isLast } 281 func (c *TxnCmd) ApplyCommit() { 282 c.ComposedCmd.ApplyCommit() 283 } 284 func (c *TxnCmd) ApplyRollback() { 285 c.ComposedCmd.ApplyRollback() 286 } 287 func (c *TxnCmd) SetReplayTxn(txn txnif.AsyncTxn) { 288 c.ComposedCmd.SetReplayTxn(txn) 289 } 290 func (c *TxnCmd) SetTxn(txn txnif.AsyncTxn) { 291 c.Txn = txn 292 c.ID = txn.GetID() 293 c.StartTS = txn.GetStartTS() 294 c.PrepareTS = txn.GetPrepareTS() 295 c.Participants = txn.GetParticipants() 296 c.Memo = txn.GetMemo() 297 } 298 func (c *TxnCmd) WriteTo(w io.Writer) (n int64, err error) { 299 t := c.GetType() 300 if _, err = w.Write(types.EncodeUint16(&t)); err != nil { 301 return 302 } 303 n += 2 304 v := IOET_WALTxnEntry_CurrVer 305 if _, err = w.Write(types.EncodeUint16(&v)); err != nil { 306 return 307 } 308 n += 2 309 var sn int64 310 buf, err := c.ComposedCmd.MarshalBinary() 311 if err != nil { 312 return 313 } 314 if sn, err = objectio.WriteBytes(buf, w); err != nil { 315 return 316 } 317 n += sn 318 if sn, err = objectio.WriteString(c.ID, w); err != nil { 319 return 320 } 321 n += sn 322 //start ts 323 if _, err = w.Write(c.StartTS[:]); err != nil { 324 return 325 } 326 n += types.TxnTsSize 327 //prepare ts 328 if _, err = w.Write(c.PrepareTS[:]); err != nil { 329 return 330 } 331 n += types.TxnTsSize 332 //participants 333 length := uint32(len(c.Participants)) 334 if _, err = w.Write(types.EncodeUint32(&length)); err != nil { 335 return 336 } 337 n += 4 338 for _, p := range c.Participants { 339 if _, err = w.Write(types.EncodeUint64(&p)); err != nil { 340 return 341 } 342 n += 8 343 } 344 if sn, err = c.Memo.WriteTo(w); err != nil { 345 return 346 } 347 n += sn 348 return 349 } 350 func (c *TxnCmd) ReadFromWithVersion(r io.Reader, ver uint16) (n int64, err error) { 351 var sn int64 352 if c.ID, sn, err = objectio.ReadString(r); err != nil { 353 return 354 } 355 n += sn 356 // start timestamp 357 if _, err = r.Read(c.StartTS[:]); err != nil { 358 return 359 } 360 n += types.TxnTsSize 361 // prepare timestamp 362 if _, err = r.Read(c.PrepareTS[:]); err != nil { 363 return 364 } 365 n += types.TxnTsSize 366 // participants 367 num := uint32(0) 368 if _, err = r.Read(types.EncodeUint32(&num)); err != nil { 369 return 370 } 371 n += 4 372 c.Participants = make([]uint64, num) 373 for i := 0; i < int(num); i++ { 374 id := uint64(0) 375 if _, err = r.Read(types.EncodeUint64(&id)); err != nil { 376 break 377 } else { 378 c.Participants = append(c.Participants, id) 379 n += 8 380 } 381 } 382 MemoVersion := model.MemoTreeVersion1 383 if ver >= IOET_WALTxnEntry_V2 { 384 MemoVersion = model.MemoTreeVersion2 385 } 386 if ver >= IOET_WALTxnEntry_V3 { 387 MemoVersion = model.MemoTreeVersion3 388 } 389 390 if sn, err = c.Memo.ReadFromWithVersion(r, MemoVersion); err != nil { 391 return 392 } 393 n += sn 394 return 395 } 396 397 func (c *TxnCmd) MarshalBinary() (buf []byte, err error) { 398 var bbuf bytes.Buffer 399 if _, err = c.WriteTo(&bbuf); err != nil { 400 return 401 } 402 buf = bbuf.Bytes() 403 return 404 } 405 func (c *TxnCmd) UnmarshalBinaryWithVersion(buf []byte, ver uint16) (err error) { 406 c.ComposedCmd = NewComposedCmd(0) 407 composeedCmdBufLength := types.DecodeUint32(buf[:4]) 408 n := 4 409 cmd, err := BuildCommandFrom(buf[n : n+int(composeedCmdBufLength)]) 410 if err != nil { 411 return 412 } 413 c.ComposedCmd = cmd.(*ComposedCmd) 414 n += int(composeedCmdBufLength) 415 bbuf := bytes.NewBuffer(buf[n:]) 416 _, err = c.ReadFromWithVersion(bbuf, ver) 417 return err 418 } 419 func (c *TxnCmd) GetType() uint16 { return IOET_WALTxnEntry } 420 func (c *TxnCmd) Desc() string { 421 return fmt.Sprintf("Tid=%X,Is2PC=%v,%s", c.ID, c.Is2PC(), c.ComposedCmd.Desc()) 422 } 423 func (c *TxnCmd) String() string { 424 return fmt.Sprintf("Tid=%X,Is2PC=%v,%s", c.ID, c.Is2PC(), c.ComposedCmd.String()) 425 } 426 func (c *TxnCmd) VerboseString() string { 427 return fmt.Sprintf("Tid=%X,Is2PC=%v,%s", c.ID, c.Is2PC(), c.ComposedCmd.VerboseString()) 428 } 429 func (c *TxnCmd) Close() { 430 c.ComposedCmd.Close() 431 } 432 433 func (cc *ComposedCmd) ApplyCommit() { 434 for _, c := range cc.Cmds { 435 c.ApplyCommit() 436 } 437 } 438 func (cc *ComposedCmd) ApplyRollback() { 439 for _, c := range cc.Cmds { 440 c.ApplyRollback() 441 } 442 } 443 func (cc *ComposedCmd) SetReplayTxn(txn txnif.AsyncTxn) { 444 for _, c := range cc.Cmds { 445 c.SetReplayTxn(txn) 446 } 447 } 448 func (cc *ComposedCmd) Close() { 449 for _, cmd := range cc.Cmds { 450 cmd.Close() 451 } 452 } 453 func (cc *ComposedCmd) GetType() uint16 { 454 return IOET_WALTxnCommand_Composed 455 } 456 457 func (cc *ComposedCmd) MarshalBinary() (buf []byte, err error) { 458 // cmdBuf only buffers the cmds. 459 var cmdBuf bytes.Buffer 460 461 if cc.LastPos < 0 { 462 cc.LastPos = 0 463 } 464 prevLastPos := cc.LastPos 465 if _, err = cc.WriteTo(&cmdBuf); err != nil { 466 return 467 } 468 469 // headBuf buffers the header data. 470 var headerBuf bytes.Buffer 471 t := cc.GetType() 472 if _, err = headerBuf.Write(types.EncodeUint16(&t)); err != nil { 473 return 474 } 475 ver := IOET_WALTxnCommand_Composed_CurrVer 476 if _, err = headerBuf.Write(types.EncodeUint16(&ver)); err != nil { 477 return 478 } 479 var length uint32 480 if cc.LastPos == 0 { 481 length = uint32(len(cc.Cmds) - prevLastPos) 482 } else { 483 length = uint32(cc.LastPos - prevLastPos) 484 } 485 if _, err = headerBuf.Write(types.EncodeUint32(&length)); err != nil { 486 return 487 } 488 489 buf = append(headerBuf.Bytes(), cmdBuf.Bytes()...) 490 return 491 } 492 493 func (cc *ComposedCmd) UnmarshalBinary(buf []byte) (err error) { 494 var n int64 495 length := uint32(0) 496 length = types.DecodeUint32(buf[n : n+4]) 497 n += 4 498 for i := 0; i < int(length); i++ { 499 bufLength := types.DecodeUint32(buf[n : n+4]) 500 n += 4 501 subCmd, err := BuildCommandFrom(buf[n : n+int64(bufLength)]) 502 if err != nil { 503 return err 504 } 505 n += int64(bufLength) 506 cc.AddCmd(subCmd.(txnif.TxnCmd)) 507 } 508 return err 509 } 510 511 func (cc *ComposedCmd) WriteTo(w io.Writer) (n int64, err error) { 512 for idx, cmd := range cc.Cmds[cc.LastPos:] { 513 var buf []byte 514 var sn int64 515 if buf, err = cmd.MarshalBinary(); err != nil { 516 return 517 } 518 // If the size cmd buffer is bigger than the limit, stop push items into 519 // the buffer and update cc.LastPos. 520 // We do the check before write the cmd to writer, there must be cmds 521 // that have not been pushed into the buffer. So do NOT need to set 522 // cc.LastPos to zero. 523 if n+int64(len(buf))+4 >= cc.CmdBufLimit { 524 cc.LastPos += idx 525 return 526 } 527 if sn, err = objectio.WriteBytes(buf, w); err != nil { 528 return 529 } 530 n += sn 531 } 532 cc.LastPos = 0 533 return 534 } 535 536 func (cc *ComposedCmd) AddCmd(cmd txnif.TxnCmd) { 537 cc.Cmds = append(cc.Cmds, cmd) 538 } 539 540 func (cc *ComposedCmd) MoreCmds() bool { 541 return cc.LastPos != 0 542 } 543 544 func (cc *ComposedCmd) ToString(prefix string) string { 545 s := fmt.Sprintf("%sComposedCmd: Cnt=%d", prefix, len(cc.Cmds)) 546 for _, cmd := range cc.Cmds { 547 s = fmt.Sprintf("%s\n%s\t%s", s, prefix, cmd.String()) 548 } 549 return s 550 } 551 552 func (cc *ComposedCmd) ToDesc(prefix string) string { 553 s := fmt.Sprintf("%sComposedCmd: Cnt=%d", prefix, len(cc.Cmds)) 554 for _, cmd := range cc.Cmds { 555 s = fmt.Sprintf("%s\n%s\t%s", s, prefix, cmd.Desc()) 556 } 557 return s 558 } 559 func (cc *ComposedCmd) ToVerboseString(prefix string) string { 560 s := fmt.Sprintf("%sComposedCmd: Cnt=%d", prefix, len(cc.Cmds)) 561 for _, cmd := range cc.Cmds { 562 s = fmt.Sprintf("%s\n%s\t%s", s, prefix, cmd.VerboseString()) 563 } 564 return s 565 } 566 567 func (cc *ComposedCmd) VerboseString() string { 568 return cc.ToVerboseString("") 569 } 570 func (cc *ComposedCmd) String() string { 571 return cc.ToString("") 572 } 573 func (cc *ComposedCmd) Desc() string { 574 return cc.ToDesc("") 575 } 576 577 func BuildCommandFrom(buf []byte) (cmd any, err error) { 578 head := objectio.DecodeIOEntryHeader(buf) 579 codec := objectio.GetIOEntryCodec(*head) 580 return codec.Decode(buf[4:]) 581 }