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 }