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  }