github.com/matrixorigin/matrixone@v1.2.0/pkg/vm/engine/tae/txn/txnimpl/antidepend.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 txnimpl 16 17 import ( 18 "fmt" 19 20 "github.com/matrixorigin/matrixone/pkg/common/moerr" 21 "github.com/matrixorigin/matrixone/pkg/container/types" 22 "github.com/matrixorigin/matrixone/pkg/objectio" 23 "github.com/matrixorigin/matrixone/pkg/vm/engine/tae/catalog" 24 "github.com/matrixorigin/matrixone/pkg/vm/engine/tae/common" 25 "github.com/matrixorigin/matrixone/pkg/vm/engine/tae/iface/txnif" 26 ) 27 28 var ErrRWConflict = moerr.NewTxnRWConflictNoCtx() 29 30 func readWriteConfilictCheck[T catalog.BaseNode[T]](entry *catalog.BaseEntryImpl[T], ts types.TS) (err error) { 31 entry.RLock() 32 defer entry.RUnlock() 33 needWait, txnToWait := entry.GetLatestNodeLocked().NeedWaitCommitting(ts) 34 // TODO: 35 // I don't think we need to wait here any more. `block` and `Object` are 36 // local metadata and never be involved in a 2PC txn. So a prepared `block` 37 // will never be rollbacked 38 if needWait { 39 entry.RUnlock() 40 txnToWait.GetTxnState(true) 41 entry.RLock() 42 } 43 if entry.DeleteBeforeLocked(ts) { 44 err = ErrRWConflict 45 } 46 return 47 } 48 49 type warChecker struct { 50 txn txnif.AsyncTxn 51 catalog *catalog.Catalog 52 //conflictSet is a set of objs which had been deleted and committed. 53 conflictSet map[types.Objectid]bool 54 readSet map[types.Objectid]*catalog.ObjectEntry 55 cache map[types.Objectid]*catalog.ObjectEntry 56 } 57 58 func newWarChecker(txn txnif.AsyncTxn, c *catalog.Catalog) *warChecker { 59 checker := &warChecker{ 60 txn: txn, 61 catalog: c, 62 conflictSet: make(map[types.Objectid]bool), 63 readSet: make(map[types.Objectid]*catalog.ObjectEntry), 64 cache: make(map[types.Objectid]*catalog.ObjectEntry), 65 } 66 return checker 67 } 68 69 func (checker *warChecker) CacheGet( 70 dbID uint64, 71 tableID uint64, 72 ObjectID *types.Objectid) (object *catalog.ObjectEntry, err error) { 73 object = checker.cacheGet(ObjectID) 74 if object != nil { 75 return 76 } 77 db, err := checker.catalog.GetDatabaseByID(dbID) 78 if err != nil { 79 return 80 } 81 table, err := db.GetTableEntryByID(tableID) 82 if err != nil { 83 return 84 } 85 object, err = table.GetObjectByID(ObjectID) 86 if err != nil { 87 return 88 } 89 checker.Cache(object) 90 return 91 } 92 93 func (checker *warChecker) InsertByID( 94 dbID uint64, 95 tableID uint64, 96 ObjectID *types.Objectid, 97 ) { 98 obj, err := checker.CacheGet(dbID, tableID, ObjectID) 99 if err != nil { 100 panic(err) 101 } 102 checker.Insert(obj) 103 } 104 105 func (checker *warChecker) cacheGet(id *objectio.ObjectId) *catalog.ObjectEntry { 106 return checker.cache[*id] 107 } 108 func (checker *warChecker) Cache(obj *catalog.ObjectEntry) { 109 checker.cache[obj.ID] = obj 110 } 111 112 func (checker *warChecker) Insert(obj *catalog.ObjectEntry) { 113 checker.Cache(obj) 114 if checker.HasConflict(obj.ID) { 115 panic(fmt.Sprintf("cannot add conflicted %s into readset", obj.String())) 116 } 117 checker.readSet[obj.ID] = obj 118 } 119 120 func (checker *warChecker) checkOne(id *common.ID, ts types.TS) (err error) { 121 // defer func() { 122 // logutil.Infof("checkOne blk=%s ts=%s err=%v", id.BlockString(), ts.ToString(), err) 123 // }() 124 if checker.HasConflict(*id.ObjectID()) { 125 err = ErrRWConflict 126 return 127 } 128 entry := checker.readSet[*id.ObjectID()] 129 if entry == nil { 130 return 131 } 132 return readWriteConfilictCheck(entry.BaseEntryImpl, ts) 133 } 134 135 func (checker *warChecker) checkAll(ts types.TS) (err error) { 136 for _, obj := range checker.readSet { 137 if err = readWriteConfilictCheck(obj.BaseEntryImpl, ts); err != nil { 138 return 139 } 140 } 141 return 142 } 143 144 func (checker *warChecker) Delete(id *common.ID) { 145 checker.conflictSet[*id.ObjectID()] = true 146 delete(checker.readSet, *id.ObjectID()) 147 } 148 149 func (checker *warChecker) HasConflict(id types.Objectid) (y bool) { 150 _, y = checker.conflictSet[id] 151 return 152 }