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 }