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