github.com/whtcorpsinc/MilevaDB-Prod@v0.0.0-20211104133533-f57f4be3b597/interlock/write.go (about)

     1  // Copyright 2020 WHTCORPS INC, Inc.
     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  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  package interlock
    15  
    16  import (
    17  	"context"
    18  	"strings"
    19  
    20  	"github.com/opentracing/opentracing-go"
    21  	"github.com/whtcorpsinc/BerolinaSQL/allegrosql"
    22  	"github.com/whtcorpsinc/BerolinaSQL/ast"
    23  	"github.com/whtcorpsinc/milevadb/blockcodec"
    24  	"github.com/whtcorpsinc/milevadb/causet"
    25  	"github.com/whtcorpsinc/milevadb/causet/blocks"
    26  	"github.com/whtcorpsinc/milevadb/ekv"
    27  	"github.com/whtcorpsinc/milevadb/memex"
    28  	"github.com/whtcorpsinc/milevadb/soliton/codec"
    29  	"github.com/whtcorpsinc/milevadb/soliton/memory"
    30  	"github.com/whtcorpsinc/milevadb/spacetime/autoid"
    31  	"github.com/whtcorpsinc/milevadb/stochastikctx"
    32  	"github.com/whtcorpsinc/milevadb/types"
    33  )
    34  
    35  var (
    36  	_ InterlockingDirectorate = &UFIDelateInterDirc{}
    37  	_ InterlockingDirectorate = &DeleteInterDirc{}
    38  	_ InterlockingDirectorate = &InsertInterDirc{}
    39  	_ InterlockingDirectorate = &ReplaceInterDirc{}
    40  	_ InterlockingDirectorate = &LoadDataInterDirc{}
    41  )
    42  
    43  // uFIDelateRecord uFIDelates the event specified by the handle `h`, from `oldData` to `newData`.
    44  // `modified` means which defCausumns are really modified. It's used for secondary indices.
    45  // Length of `oldData` and `newData` equals to length of `t.WriblockDefCauss()`.
    46  // The return values:
    47  //     1. changed (bool) : does the uFIDelate really change the event values. e.g. uFIDelate set i = 1 where i = 1;
    48  //     2. err (error) : error in the uFIDelate.
    49  func uFIDelateRecord(ctx context.Context, sctx stochastikctx.Context, h ekv.Handle, oldData, newData []types.Causet, modified []bool, t causet.Block,
    50  	onDup bool, memTracker *memory.Tracker) (bool, error) {
    51  	if span := opentracing.SpanFromContext(ctx); span != nil && span.Tracer() != nil {
    52  		span1 := span.Tracer().StartSpan("interlock.uFIDelateRecord", opentracing.ChildOf(span.Context()))
    53  		defer span1.Finish()
    54  		ctx = opentracing.ContextWithSpan(ctx, span1)
    55  	}
    56  	txn, err := sctx.Txn(false)
    57  	if err != nil {
    58  		return false, err
    59  	}
    60  	memUsageOfTxnState := txn.Size()
    61  	defer memTracker.Consume(int64(txn.Size() - memUsageOfTxnState))
    62  	sc := sctx.GetStochastikVars().StmtCtx
    63  	changed, handleChanged := false, false
    64  	// onUFIDelateSpecified is for "UFIDelATE SET ts_field = old_value", the
    65  	// timestamp field is explicitly set, but not changed in fact.
    66  	onUFIDelateSpecified := make(map[int]bool)
    67  	var newHandle ekv.Handle
    68  
    69  	// We can iterate on public defCausumns not wriblock defCausumns,
    70  	// because all of them are sorted by their `Offset`, which
    71  	// causes all wriblock defCausumns are after public defCausumns.
    72  
    73  	// 1. Cast modified values.
    74  	for i, defCaus := range t.DefCauss() {
    75  		if modified[i] {
    76  			// Cast changed fields with respective defCausumns.
    77  			v, err := causet.CastValue(sctx, newData[i], defCaus.ToInfo(), false, false)
    78  			if err != nil {
    79  				return false, err
    80  			}
    81  			newData[i] = v
    82  		}
    83  	}
    84  
    85  	// 2. Handle the bad null error.
    86  	for i, defCaus := range t.DefCauss() {
    87  		var err error
    88  		if err = defCaus.HandleBadNull(&newData[i], sc); err != nil {
    89  			return false, err
    90  		}
    91  	}
    92  
    93  	// 3. Compare causet, then handle some flags.
    94  	for i, defCaus := range t.DefCauss() {
    95  		cmp, err := newData[i].CompareCauset(sc, &oldData[i])
    96  		if err != nil {
    97  			return false, err
    98  		}
    99  		if cmp != 0 {
   100  			changed = true
   101  			modified[i] = true
   102  			// Rebase auto increment id if the field is changed.
   103  			if allegrosql.HasAutoIncrementFlag(defCaus.Flag) {
   104  				recordID, err := getAutoRecordID(newData[i], &defCaus.FieldType, false)
   105  				if err != nil {
   106  					return false, err
   107  				}
   108  				if err = t.RebaseAutoID(sctx, recordID, true, autoid.EventIDAllocType); err != nil {
   109  					return false, err
   110  				}
   111  			}
   112  			if defCaus.IsPKHandleDeferredCauset(t.Meta()) {
   113  				handleChanged = true
   114  				newHandle = ekv.IntHandle(newData[i].GetInt64())
   115  				// Rebase auto random id if the field is changed.
   116  				if err := rebaseAutoRandomValue(sctx, t, &newData[i], defCaus); err != nil {
   117  					return false, err
   118  				}
   119  			}
   120  			if defCaus.IsCommonHandleDeferredCauset(t.Meta()) {
   121  				pkIdx := blocks.FindPrimaryIndex(t.Meta())
   122  				handleChanged = true
   123  				pkDts := make([]types.Causet, 0, len(pkIdx.DeferredCausets))
   124  				for _, idxDefCaus := range pkIdx.DeferredCausets {
   125  					pkDts = append(pkDts, newData[idxDefCaus.Offset])
   126  				}
   127  				blockcodec.TruncateIndexValues(t.Meta(), pkIdx, pkDts)
   128  				handleBytes, err := codec.EncodeKey(sctx.GetStochastikVars().StmtCtx, nil, pkDts...)
   129  				if err != nil {
   130  					return false, err
   131  				}
   132  				newHandle, err = ekv.NewCommonHandle(handleBytes)
   133  				if err != nil {
   134  					return false, err
   135  				}
   136  			}
   137  		} else {
   138  			if allegrosql.HasOnUFIDelateNowFlag(defCaus.Flag) && modified[i] {
   139  				// It's for "UFIDelATE t SET ts = ts" and ts is a timestamp.
   140  				onUFIDelateSpecified[i] = true
   141  			}
   142  			modified[i] = false
   143  		}
   144  	}
   145  
   146  	sc.AddTouchedEvents(1)
   147  	// If no changes, nothing to do, return directly.
   148  	if !changed {
   149  		// See https://dev.allegrosql.com/doc/refman/5.7/en/allegrosql-real-connect.html  CLIENT_FOUND_ROWS
   150  		if sctx.GetStochastikVars().ClientCapability&allegrosql.ClientFoundEvents > 0 {
   151  			sc.AddAffectedEvents(1)
   152  		}
   153  
   154  		physicalID := t.Meta().ID
   155  		if pt, ok := t.(causet.PartitionedBlock); ok {
   156  			p, err := pt.GetPartitionByEvent(sctx, oldData)
   157  			if err != nil {
   158  				return false, err
   159  			}
   160  			physicalID = p.GetPhysicalID()
   161  		}
   162  
   163  		unchangedEventKey := blockcodec.EncodeEventKeyWithHandle(physicalID, h)
   164  		txnCtx := sctx.GetStochastikVars().TxnCtx
   165  		if txnCtx.IsPessimistic {
   166  			txnCtx.AddUnchangedEventKey(unchangedEventKey)
   167  		}
   168  		return false, nil
   169  	}
   170  
   171  	// 4. Fill values into on-uFIDelate-now fields, only if they are really changed.
   172  	for i, defCaus := range t.DefCauss() {
   173  		if allegrosql.HasOnUFIDelateNowFlag(defCaus.Flag) && !modified[i] && !onUFIDelateSpecified[i] {
   174  			if v, err := memex.GetTimeValue(sctx, strings.ToUpper(ast.CurrentTimestamp), defCaus.Tp, int8(defCaus.Decimal)); err == nil {
   175  				newData[i] = v
   176  				modified[i] = true
   177  			} else {
   178  				return false, err
   179  			}
   180  		}
   181  	}
   182  
   183  	// 5. If handle changed, remove the old then add the new record, otherwise uFIDelate the record.
   184  	if handleChanged {
   185  		if sc.DupKeyAsWarning {
   186  			// For `UFIDelATE IGNORE`/`INSERT IGNORE ON DUPLICATE KEY UFIDelATE`
   187  			// If the new handle exists, this will avoid to remove the record.
   188  			err = blocks.CheckHandleExists(ctx, sctx, t, newHandle, newData)
   189  			if err != nil {
   190  				return false, err
   191  			}
   192  		}
   193  		if err = t.RemoveRecord(sctx, h, oldData); err != nil {
   194  			return false, err
   195  		}
   196  		// the `affectedEvents` is increased when adding new record.
   197  		if sc.DupKeyAsWarning {
   198  			_, err = t.AddRecord(sctx, newData, causet.IsUFIDelate, causet.SkipHandleCheck, causet.WithCtx(ctx))
   199  		} else {
   200  			_, err = t.AddRecord(sctx, newData, causet.IsUFIDelate, causet.WithCtx(ctx))
   201  		}
   202  
   203  		if err != nil {
   204  			return false, err
   205  		}
   206  		if onDup {
   207  			sc.AddAffectedEvents(1)
   208  		}
   209  	} else {
   210  		// UFIDelate record to new value and uFIDelate index.
   211  		if err = t.UFIDelateRecord(ctx, sctx, h, oldData, newData, modified); err != nil {
   212  			return false, err
   213  		}
   214  		if onDup {
   215  			sc.AddAffectedEvents(2)
   216  		} else {
   217  			sc.AddAffectedEvents(1)
   218  		}
   219  	}
   220  	sc.AddUFIDelatedEvents(1)
   221  	sc.AddCopiedEvents(1)
   222  
   223  	return true, nil
   224  }
   225  
   226  func rebaseAutoRandomValue(sctx stochastikctx.Context, t causet.Block, newData *types.Causet, defCaus *causet.DeferredCauset) error {
   227  	blockInfo := t.Meta()
   228  	if !blockInfo.ContainsAutoRandomBits() {
   229  		return nil
   230  	}
   231  	recordID, err := getAutoRecordID(*newData, &defCaus.FieldType, false)
   232  	if err != nil {
   233  		return err
   234  	}
   235  	if recordID < 0 {
   236  		return nil
   237  	}
   238  	layout := autoid.NewAutoRandomIDLayout(&defCaus.FieldType, blockInfo.AutoRandomBits)
   239  	// Set bits except incremental_bits to zero.
   240  	recordID = recordID & (1<<layout.IncrementalBits - 1)
   241  	return t.SlabPredictors(sctx).Get(autoid.AutoRandomType).Rebase(blockInfo.ID, recordID, true)
   242  }
   243  
   244  // resetErrDataTooLong reset ErrDataTooLong error msg.
   245  // types.ErrDataTooLong is produced in types.ProduceStrWithSpecifiedTp, there is no defCausumn info in there,
   246  // so we reset the error msg here, and wrap old err with errors.Wrap.
   247  func resetErrDataTooLong(defCausName string, rowIdx int, err error) error {
   248  	newErr := types.ErrDataTooLong.GenWithStack("Data too long for defCausumn '%v' at event %v", defCausName, rowIdx)
   249  	return newErr
   250  }