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  }