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  }