github.com/matrixorigin/matrixone@v0.7.0/pkg/vm/engine/tae/txn/txnbase/mvccslice.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  
    20  	"github.com/matrixorigin/matrixone/pkg/container/types"
    21  	"github.com/matrixorigin/matrixone/pkg/vm/engine/tae/iface/txnif"
    22  	"github.com/matrixorigin/matrixone/pkg/vm/engine/tae/wal"
    23  )
    24  
    25  type MVCCSlice struct {
    26  	MVCC      []txnif.MVCCNode
    27  	comparefn func(txnif.MVCCNode, txnif.MVCCNode) int
    28  }
    29  
    30  func NewMVCCSlice(newnodefn func() txnif.MVCCNode,
    31  	comparefn func(txnif.MVCCNode, txnif.MVCCNode) int) *MVCCSlice {
    32  	return &MVCCSlice{
    33  		MVCC:      make([]txnif.MVCCNode, 0),
    34  		comparefn: comparefn,
    35  	}
    36  }
    37  func (be *MVCCSlice) StringLocked() string {
    38  	var w bytes.Buffer
    39  
    40  	length := len(be.MVCC)
    41  	for i := length - 1; i >= 0; i-- {
    42  		version := be.MVCC[i]
    43  		_, _ = w.WriteString(" -> ")
    44  		_, _ = w.WriteString(version.String())
    45  	}
    46  	return w.String()
    47  }
    48  
    49  // for replay
    50  func (be *MVCCSlice) GetTs() types.TS {
    51  	return be.GetUpdateNodeLocked().GetEnd()
    52  }
    53  
    54  // func (be *MVCCSlice) GetTxn() txnif.TxnReader { return be.GetUpdateNodeLocked().GetTxn() }
    55  
    56  func (be *MVCCSlice) InsertNode(un txnif.MVCCNode) {
    57  	be.MVCC = append(be.MVCC, un)
    58  }
    59  
    60  // GetUpdateNode gets the latest UpdateNode.
    61  // It is useful in making command, apply state(e.g. ApplyCommit),
    62  // check confilct.
    63  func (be *MVCCSlice) GetUpdateNodeLocked() txnif.MVCCNode {
    64  	length := len(be.MVCC)
    65  	if length == 0 {
    66  		return nil
    67  	}
    68  	return be.MVCC[length-1]
    69  }
    70  
    71  // GetCommittedNode gets the latest committed UpdateNode.
    72  // It's useful when check whether the catalog/metadata entry is deleted.
    73  func (be *MVCCSlice) GetCommittedNode() (node txnif.MVCCNode) {
    74  	length := len(be.MVCC)
    75  	for i := length - 1; i >= 0; i-- {
    76  		un := be.MVCC[i]
    77  		if !un.IsActive() && !un.IsCommitting() {
    78  			node = un
    79  			break
    80  		}
    81  	}
    82  	return
    83  }
    84  func (be *MVCCSlice) DeleteNode(node txnif.MVCCNode) {
    85  	length := len(be.MVCC)
    86  	for i := length - 1; i >= 0; i-- {
    87  		un := be.MVCC[i]
    88  		compare := be.comparefn(un, node)
    89  		if compare == 0 {
    90  			be.MVCC = append(be.MVCC[:i], be.MVCC[i+1:]...)
    91  			break
    92  		} else if compare < 0 {
    93  			break
    94  		}
    95  	}
    96  }
    97  func (be *MVCCSlice) SearchNode(o txnif.MVCCNode) (node txnif.MVCCNode) {
    98  	for _, n := range be.MVCC {
    99  		if be.comparefn(n, o) == 0 {
   100  			node = n
   101  			break
   102  		}
   103  	}
   104  	return
   105  }
   106  
   107  func (be *MVCCSlice) GetVisibleNode(ts types.TS) (node txnif.MVCCNode) {
   108  	length := len(be.MVCC)
   109  	for i := length - 1; i >= 0; i-- {
   110  		un := be.MVCC[i]
   111  		var visible bool
   112  		if visible = un.IsVisible(ts); visible {
   113  			node = un
   114  			break
   115  		}
   116  	}
   117  	return
   118  }
   119  
   120  func (be *MVCCSlice) GetLastNonAbortedNode() (node txnif.MVCCNode) {
   121  	length := len(be.MVCC)
   122  	for i := length - 1; i >= 0; i-- {
   123  		un := be.MVCC[i]
   124  		if !un.IsAborted() {
   125  			node = un
   126  			break
   127  		}
   128  	}
   129  	return
   130  }
   131  
   132  func (be *MVCCSlice) SearchNodeByTS(ts types.TS) (node txnif.MVCCNode) {
   133  	for _, n := range be.MVCC {
   134  		if n.GetStart().Equal(ts) {
   135  			node = n
   136  			break
   137  		}
   138  	}
   139  	return
   140  }
   141  func (be *MVCCSlice) ForEach(fn func(un txnif.MVCCNode) bool, reverse bool) {
   142  	if reverse {
   143  		be.forEachReverse(fn)
   144  	} else {
   145  		be.forEach(fn)
   146  	}
   147  }
   148  func (be *MVCCSlice) Close() {
   149  	be.forEach(func(un txnif.MVCCNode) bool {
   150  		un.Close()
   151  		return true
   152  	})
   153  }
   154  func (be *MVCCSlice) forEach(fn func(un txnif.MVCCNode) bool) {
   155  	for i := len(be.MVCC) - 1; i >= 0; i-- {
   156  		n := be.MVCC[i]
   157  		gonext := fn(n)
   158  		if !gonext {
   159  			break
   160  		}
   161  	}
   162  }
   163  func (be *MVCCSlice) forEachReverse(fn func(un txnif.MVCCNode) bool) {
   164  	for _, n := range be.MVCC {
   165  		gonext := fn(n)
   166  		if !gonext {
   167  			break
   168  		}
   169  	}
   170  }
   171  
   172  // GetNodeToRead gets UpdateNode according to the timestamp.
   173  // It returns the UpdateNode in the same txn as the read txn
   174  // or returns the latest UpdateNode with commitTS less than the timestamp.
   175  // todo getend or getcommitts
   176  func (be *MVCCSlice) GetNodeToReadByPrepareTS(ts types.TS) (offset int, node txnif.MVCCNode) {
   177  	if len(be.MVCC) == 0 {
   178  		return 0, nil
   179  	}
   180  	lastAppend := be.MVCC[len(be.MVCC)-1]
   181  
   182  	// 1. Last append node is in the window and it was already committed
   183  	if ts.Greater(lastAppend.GetPrepare()) {
   184  		return len(be.MVCC) - 1, lastAppend
   185  	}
   186  	start, end := 0, len(be.MVCC)-1
   187  	var mid int
   188  	for start <= end {
   189  		mid = (start + end) / 2
   190  		if be.MVCC[mid].GetPrepare().Less(ts) {
   191  			start = mid + 1
   192  		} else if be.MVCC[mid].GetPrepare().Greater(ts) {
   193  			end = mid - 1
   194  		} else {
   195  			break
   196  		}
   197  	}
   198  	if mid == 0 && be.MVCC[mid].GetPrepare().Greater(ts) {
   199  		// 2. The first node is found and it was committed after ts
   200  		return 0, nil
   201  	} else if mid != 0 && be.MVCC[mid].GetPrepare().Greater(ts) {
   202  		// 3. A node (not first) is found and it was committed after ts. Use the prev node
   203  		mid = mid - 1
   204  	}
   205  	return mid, be.MVCC[mid]
   206  }
   207  
   208  func (be *MVCCSlice) SearchNodeByCompareFn(fn func(a txnif.MVCCNode) int) (offset int, node txnif.MVCCNode) {
   209  	if len(be.MVCC) == 0 {
   210  		return 0, nil
   211  	}
   212  	lastAppend := be.MVCC[len(be.MVCC)-1]
   213  
   214  	// 1. Last append node is in the window and it was already committed
   215  	if fn(lastAppend) < 0 {
   216  		return 0, nil
   217  	}
   218  	start, end := 0, len(be.MVCC)-1
   219  	var mid int
   220  	for start <= end {
   221  		mid = (start + end) / 2
   222  		if fn(be.MVCC[mid]) < 0 {
   223  			start = mid + 1
   224  		} else if fn(be.MVCC[mid]) > 0 {
   225  			end = mid - 1
   226  		} else {
   227  			break
   228  		}
   229  	}
   230  	if fn(be.MVCC[mid]) != 0 {
   231  		return 0, nil
   232  	}
   233  	return mid, be.MVCC[mid]
   234  }
   235  
   236  func (be *MVCCSlice) IsEmpty() bool {
   237  	return len(be.MVCC) == 0
   238  }
   239  
   240  func (be *MVCCSlice) IsCommitting() bool {
   241  	node := be.GetUpdateNodeLocked()
   242  	if node == nil {
   243  		return false
   244  	}
   245  	return node.IsCommitting()
   246  }
   247  
   248  func (be *MVCCSlice) IsCommitted() bool {
   249  	un := be.GetUpdateNodeLocked()
   250  	if un == nil {
   251  		return false
   252  	}
   253  	return un.IsCommitted()
   254  }
   255  
   256  func (be *MVCCSlice) LoopInRange(start, end types.TS, fn func(txnif.MVCCNode) bool) (indexes []*wal.Index) {
   257  	startOffset, node := be.GetNodeToReadByPrepareTS(start)
   258  	if node != nil && node.GetPrepare().Less(start) {
   259  		startOffset++
   260  	}
   261  	endOffset, node := be.GetNodeToReadByPrepareTS(end)
   262  	if node == nil {
   263  		return nil
   264  	}
   265  	for i := endOffset; i >= startOffset; i-- {
   266  		if !fn(be.MVCC[i]) {
   267  			break
   268  		}
   269  	}
   270  	return
   271  }
   272  
   273  func (be *MVCCSlice) LoopOffsetRange(start, end int, fn func(txnif.MVCCNode) bool) {
   274  	for i := start; i <= end; i++ {
   275  		if !fn(be.MVCC[i]) {
   276  			break
   277  		}
   278  	}
   279  }
   280  
   281  func (be *MVCCSlice) GetNodeByOffset(offset int) txnif.MVCCNode {
   282  	return be.MVCC[offset]
   283  }