github.com/matrixorigin/matrixone@v1.2.0/pkg/vm/engine/tae/catalog/base.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 catalog 16 17 import ( 18 "fmt" 19 // "io" 20 "sync" 21 22 "github.com/matrixorigin/matrixone/pkg/common/moerr" 23 "github.com/matrixorigin/matrixone/pkg/container/types" 24 "github.com/matrixorigin/matrixone/pkg/logutil" 25 "github.com/matrixorigin/matrixone/pkg/util/stack" 26 "github.com/matrixorigin/matrixone/pkg/vm/engine/tae/common" 27 "github.com/matrixorigin/matrixone/pkg/vm/engine/tae/iface/txnif" 28 "github.com/matrixorigin/matrixone/pkg/vm/engine/tae/txn/txnbase" 29 ) 30 31 type BaseEntry interface { 32 //for global checkpoint 33 RLock() 34 RUnlock() 35 DeleteBeforeLocked(ts types.TS) bool 36 DeleteBefore(ts types.TS) bool 37 } 38 39 func CompareUint64(left, right uint64) int { 40 if left > right { 41 return 1 42 } else if left < right { 43 return -1 44 } 45 return 0 46 } 47 48 type BaseEntryImpl[T BaseNode[T]] struct { 49 //chain of MetadataMVCCNode 50 *txnbase.MVCCChain[*MVCCNode[T]] 51 } 52 53 func NewReplayBaseEntry[T BaseNode[T]](factory func() T) *BaseEntryImpl[T] { 54 be := &BaseEntryImpl[T]{ 55 MVCCChain: txnbase.NewMVCCChain(CompareBaseNode[T], NewEmptyMVCCNodeFactory(factory), nil), 56 } 57 return be 58 } 59 60 func NewBaseEntry[T BaseNode[T]](factory func() T) *BaseEntryImpl[T] { 61 return &BaseEntryImpl[T]{ 62 MVCCChain: txnbase.NewMVCCChain(CompareBaseNode[T], NewEmptyMVCCNodeFactory(factory), nil), 63 } 64 } 65 66 func (be *BaseEntryImpl[T]) StringLocked() string { 67 return be.MVCCChain.StringLocked() 68 } 69 70 func (be *BaseEntryImpl[T]) String() string { 71 be.RLock() 72 defer be.RUnlock() 73 return be.StringLocked() 74 } 75 76 func (be *BaseEntryImpl[T]) PPString(level common.PPLevel, depth int, prefix string) string { 77 s := fmt.Sprintf("%s%s%s", common.RepeatStr("\t", depth), prefix, be.StringLocked()) 78 return s 79 } 80 81 func (be *BaseEntryImpl[T]) CreateWithTS(ts types.TS, baseNode T) { 82 node := &MVCCNode[T]{ 83 EntryMVCCNode: &EntryMVCCNode{ 84 CreatedAt: ts, 85 }, 86 TxnMVCCNode: txnbase.NewTxnMVCCNodeWithTS(ts), 87 BaseNode: baseNode, 88 } 89 be.Insert(node) 90 } 91 92 func (be *BaseEntryImpl[T]) CreateWithTxn(txn txnif.AsyncTxn, baseNode T) { 93 if txn == nil { 94 logutil.Warnf("unexpected txn is nil: %+v", stack.Callers(0)) 95 } 96 node := &MVCCNode[T]{ 97 EntryMVCCNode: &EntryMVCCNode{ 98 CreatedAt: txnif.UncommitTS, 99 }, 100 TxnMVCCNode: txnbase.NewTxnMVCCNodeWithTxn(txn), 101 BaseNode: baseNode, 102 } 103 be.Insert(node) 104 } 105 106 // used when replay 107 func (be *BaseEntryImpl[T]) CreateWithStartAndEnd(start, end types.TS, baseNode T) { 108 node := &MVCCNode[T]{ 109 EntryMVCCNode: &EntryMVCCNode{ 110 CreatedAt: end, 111 }, 112 TxnMVCCNode: txnbase.NewTxnMVCCNodeWithStartEnd(start, end), 113 BaseNode: baseNode, 114 } 115 be.Insert(node) 116 } 117 118 func (be *BaseEntryImpl[T]) TryGetTerminatedTS(waitIfcommitting bool) (terminated bool, TS types.TS) { 119 be.RLock() 120 defer be.RUnlock() 121 return be.TryGetTerminatedTSLocked(waitIfcommitting) 122 } 123 124 func (be *BaseEntryImpl[T]) TryGetTerminatedTSLocked(waitIfcommitting bool) (terminated bool, TS types.TS) { 125 node := be.GetLatestCommittedNodeLocked() 126 if node == nil { 127 return 128 } 129 if node.HasDropCommitted() { 130 return true, node.DeletedAt 131 } 132 return 133 } 134 func (be *BaseEntryImpl[T]) PrepareAdd(txn txnif.TxnReader) (err error) { 135 if err = be.ConflictCheck(txn); err != nil { 136 return 137 } 138 // check duplication then 139 be.RLock() 140 defer be.RUnlock() 141 if txn == nil || be.GetTxn() != txn { 142 if !be.HasDropCommittedLocked() { 143 return moerr.GetOkExpectedDup() 144 } 145 } else { 146 if be.ensureVisibleAndNotDropped(txn) { 147 return moerr.GetOkExpectedDup() 148 } 149 } 150 return 151 } 152 153 func (be *BaseEntryImpl[T]) ConflictCheck(txn txnif.TxnReader) (err error) { 154 be.RLock() 155 defer be.RUnlock() 156 if txn != nil { 157 needWait, waitTxn := be.NeedWaitCommittingLocked(txn.GetStartTS()) 158 if needWait { 159 be.RUnlock() 160 waitTxn.GetTxnState(true) 161 be.RLock() 162 } 163 err = be.CheckConflictLocked(txn) 164 if err != nil { 165 return 166 } 167 } 168 return 169 } 170 func (be *BaseEntryImpl[T]) getOrSetUpdateNodeLocked(txn txnif.TxnReader) (newNode bool, node *MVCCNode[T]) { 171 entry := be.GetLatestNodeLocked() 172 if entry.IsSameTxn(txn) { 173 return false, entry 174 } else { 175 node := entry.CloneData() 176 node.TxnMVCCNode = txnbase.NewTxnMVCCNodeWithTxn(txn) 177 be.Insert(node) 178 return true, node 179 } 180 } 181 182 func (be *BaseEntryImpl[T]) DeleteLocked(txn txnif.TxnReader) (isNewNode bool, err error) { 183 var entry *MVCCNode[T] 184 isNewNode, entry = be.getOrSetUpdateNodeLocked(txn) 185 entry.Delete() 186 return 187 } 188 189 func (be *BaseEntryImpl[T]) DeleteBefore(ts types.TS) bool { 190 be.RLock() 191 defer be.RUnlock() 192 return be.DeleteBeforeLocked(ts) 193 } 194 195 func (be *BaseEntryImpl[T]) DeleteBeforeLocked(ts types.TS) bool { 196 createAt := be.GetDeleteAtLocked() 197 if createAt.IsEmpty() { 198 return false 199 } 200 return createAt.Less(&ts) 201 } 202 203 func (be *BaseEntryImpl[T]) NeedWaitCommittingLocked(startTS types.TS) (bool, txnif.TxnReader) { 204 un := be.GetLatestNodeLocked() 205 if un == nil { 206 return false, nil 207 } 208 return un.NeedWaitCommitting(startTS) 209 } 210 211 func (be *BaseEntryImpl[T]) HasDropCommitted() bool { 212 be.RLock() 213 defer be.RUnlock() 214 return be.HasDropCommittedLocked() 215 } 216 217 func (be *BaseEntryImpl[T]) HasDropCommittedLocked() bool { 218 un := be.GetLatestCommittedNodeLocked() 219 if un == nil { 220 return false 221 } 222 return un.HasDropCommitted() 223 } 224 225 func (be *BaseEntryImpl[T]) ensureVisibleAndNotDropped(txn txnif.TxnReader) bool { 226 visible, dropped := be.GetVisibilityLocked(txn) 227 if !visible { 228 return false 229 } 230 return !dropped 231 } 232 233 func (be *BaseEntryImpl[T]) GetVisibilityLocked(txn txnif.TxnReader) (visible, dropped bool) { 234 un := be.GetVisibleNodeLocked(txn) 235 if un == nil { 236 return 237 } 238 visible = true 239 if un.IsSameTxn(txn) { 240 dropped = un.HasDropIntent() 241 } else { 242 dropped = un.HasDropCommitted() 243 } 244 return 245 } 246 247 func (be *BaseEntryImpl[T]) IsVisibleWithLock(txn txnif.TxnReader, mu *sync.RWMutex) (ok bool, err error) { 248 needWait, txnToWait := be.NeedWaitCommittingLocked(txn.GetStartTS()) 249 if needWait { 250 mu.RUnlock() 251 txnToWait.GetTxnState(true) 252 mu.RLock() 253 } 254 ok = be.ensureVisibleAndNotDropped(txn) 255 return 256 } 257 258 func (be *BaseEntryImpl[T]) DropEntryLocked(txn txnif.TxnReader) (isNewNode bool, err error) { 259 err = be.CheckConflictLocked(txn) 260 if err != nil { 261 return 262 } 263 if be.HasDropCommittedLocked() { 264 return false, moerr.GetOkExpectedEOB() 265 } 266 isNewNode, err = be.DeleteLocked(txn) 267 return 268 } 269 270 func (be *BaseEntryImpl[T]) DeleteAfter(ts types.TS) bool { 271 un := be.GetLatestNodeLocked() 272 if un == nil { 273 return false 274 } 275 return un.DeletedAt.Greater(&ts) 276 } 277 278 func (be *BaseEntryImpl[T]) GetCreatedAtLocked() types.TS { 279 un := be.GetLatestNodeLocked() 280 if un == nil { 281 return types.TS{} 282 } 283 return un.CreatedAt 284 } 285 286 func (be *BaseEntryImpl[T]) GetDeleteAtLocked() types.TS { 287 un := be.GetLatestNodeLocked() 288 if un == nil { 289 return types.TS{} 290 } 291 return un.DeletedAt 292 } 293 294 func (be *BaseEntryImpl[T]) GetVisibility(txn txnif.TxnReader) (visible, dropped bool) { 295 be.RLock() 296 defer be.RUnlock() 297 needWait, txnToWait := be.NeedWaitCommittingLocked(txn.GetStartTS()) 298 if needWait { 299 be.RUnlock() 300 txnToWait.GetTxnState(true) 301 be.RLock() 302 } 303 return be.GetVisibilityLocked(txn) 304 }