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