github.com/matrixorigin/matrixone@v1.2.0/pkg/txn/storage/mem/kv_txn_storage.go (about)

     1  // Copyright 2021 - 2022 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 mem
    16  
    17  import (
    18  	"bytes"
    19  	"context"
    20  	"encoding/json"
    21  	"fmt"
    22  	"math"
    23  	"sync"
    24  	"time"
    25  
    26  	"github.com/matrixorigin/matrixone/pkg/common/moerr"
    27  	"github.com/matrixorigin/matrixone/pkg/logservice"
    28  	logpb "github.com/matrixorigin/matrixone/pkg/pb/logservice"
    29  	"github.com/matrixorigin/matrixone/pkg/pb/timestamp"
    30  	"github.com/matrixorigin/matrixone/pkg/pb/txn"
    31  	"github.com/matrixorigin/matrixone/pkg/txn/clock"
    32  	"github.com/matrixorigin/matrixone/pkg/txn/storage"
    33  )
    34  
    35  // MustParseGetPayload must parse get payload
    36  func MustParseGetPayload(payload []byte) [][]byte {
    37  	r := &message{}
    38  	r.mustUnmarshal(payload)
    39  	return r.Values
    40  }
    41  
    42  // NewSetTxnRequest returns a kv set txn request
    43  func NewSetTxnRequest(ks, vs [][]byte) txn.TxnRequest {
    44  	r := &message{Keys: ks, Values: vs}
    45  	return txn.TxnRequest{
    46  		Method: txn.TxnMethod_Write,
    47  		CNRequest: &txn.CNOpRequest{
    48  			OpCode:  setOpCode,
    49  			Payload: r.mustMarshal(),
    50  		},
    51  	}
    52  }
    53  
    54  // NewGetTxnRequest returns a kv get txn request
    55  func NewGetTxnRequest(ks [][]byte) txn.TxnRequest {
    56  	r := &message{Keys: ks}
    57  	return txn.TxnRequest{
    58  		Method: txn.TxnMethod_Read,
    59  		CNRequest: &txn.CNOpRequest{
    60  			OpCode:  getOpCode,
    61  			Payload: r.mustMarshal(),
    62  		},
    63  	}
    64  }
    65  
    66  // EventType event type
    67  type EventType int
    68  
    69  var (
    70  	// PrepareType prepare event
    71  	PrepareType = EventType(0)
    72  	// CommitType commit event
    73  	CommitType = EventType(1)
    74  	// CommittingType committing type
    75  	CommittingType = EventType(2)
    76  	// RollbackType rollback type
    77  	RollbackType = EventType(3)
    78  )
    79  
    80  // Event event
    81  type Event struct {
    82  	// Txn event txn
    83  	Txn txn.TxnMeta
    84  	// Type event type
    85  	Type EventType
    86  }
    87  
    88  // KVTxnStorage KV-based implementation of TxnStorage. Just used to test.
    89  type KVTxnStorage struct {
    90  	sync.RWMutex
    91  	logClient            logservice.Client
    92  	clock                clock.Clock
    93  	recoverFrom          logservice.Lsn
    94  	uncommittedTxn       map[string]*txn.TxnMeta
    95  	uncommittedKeyTxnMap map[string]*txn.TxnMeta
    96  	uncommitted          *KV
    97  	committed            *MVCCKV
    98  	eventC               chan Event
    99  }
   100  
   101  // NewKVTxnStorage create KV-based implementation of TxnStorage
   102  func NewKVTxnStorage(recoverFrom logservice.Lsn, logClient logservice.Client, clock clock.Clock) *KVTxnStorage {
   103  	return &KVTxnStorage{
   104  		logClient:            logClient,
   105  		clock:                clock,
   106  		recoverFrom:          recoverFrom,
   107  		uncommittedKeyTxnMap: make(map[string]*txn.TxnMeta),
   108  		uncommittedTxn:       make(map[string]*txn.TxnMeta),
   109  		uncommitted:          NewKV(),
   110  		committed:            NewMVCCKV(),
   111  		eventC:               make(chan Event, 1024*10),
   112  	}
   113  }
   114  
   115  func (kv *KVTxnStorage) GetEventC() chan Event {
   116  	return kv.eventC
   117  }
   118  
   119  func (kv *KVTxnStorage) GetUncommittedTxn(txnID []byte) *txn.TxnMeta {
   120  	kv.RLock()
   121  	defer kv.RUnlock()
   122  
   123  	return kv.uncommittedTxn[string(txnID)]
   124  }
   125  
   126  func (kv *KVTxnStorage) GetCommittedKV() *MVCCKV {
   127  	return kv.committed
   128  }
   129  
   130  func (kv *KVTxnStorage) GetUncommittedKV() *KV {
   131  	return kv.uncommitted
   132  }
   133  
   134  func (kv *KVTxnStorage) StartRecovery(ctx context.Context, c chan txn.TxnMeta) {
   135  	defer close(c)
   136  
   137  	if kv.recoverFrom < 1 {
   138  		return
   139  	}
   140  
   141  	for {
   142  		logs, lsn, err := kv.logClient.Read(ctx, kv.recoverFrom, math.MaxUint64)
   143  		if err != nil {
   144  			panic(err)
   145  		}
   146  
   147  		for _, log := range logs {
   148  			if log.Type == logpb.UserRecord {
   149  				klog := &KVLog{}
   150  				klog.MustUnmarshal(log.Data)
   151  
   152  				switch klog.Txn.Status {
   153  				case txn.TxnStatus_Prepared:
   154  					req := &message{}
   155  					req.Keys = klog.Keys
   156  					req.Values = klog.Values
   157  					_, err := kv.Write(ctx, klog.Txn, setOpCode, req.mustMarshal())
   158  					if err != nil {
   159  						panic(err)
   160  					}
   161  				case txn.TxnStatus_Committed:
   162  					kv.Lock()
   163  					if len(klog.Keys) == 0 {
   164  						kv.commitKeysLocked(klog.Txn, kv.getWriteKeysLocked(klog.Txn))
   165  					} else {
   166  						kv.commitWithKVLogLocked(klog)
   167  					}
   168  					kv.Unlock()
   169  				case txn.TxnStatus_Committing:
   170  					kv.Lock()
   171  					newTxn := kv.changeUncommittedTxnStatusLocked(klog.Txn.ID, txn.TxnStatus_Committing)
   172  					newTxn.CommitTS = klog.Txn.CommitTS
   173  					kv.Unlock()
   174  				default:
   175  					panic(fmt.Sprintf("invalid txn status %s", klog.Txn.Status.String()))
   176  				}
   177  
   178  				c <- klog.Txn
   179  			}
   180  		}
   181  
   182  		if lsn == kv.recoverFrom {
   183  			return
   184  		}
   185  	}
   186  }
   187  
   188  func (kv *KVTxnStorage) Start() error {
   189  	return nil
   190  }
   191  
   192  func (kv *KVTxnStorage) Close(ctx context.Context) error {
   193  	return nil
   194  }
   195  
   196  func (kv *KVTxnStorage) Destroy(ctx context.Context) error {
   197  	return nil
   198  }
   199  
   200  func (kv *KVTxnStorage) Read(ctx context.Context, txnMeta txn.TxnMeta, op uint32, payload []byte) (storage.ReadResult, error) {
   201  	kv.RLock()
   202  	defer kv.RUnlock()
   203  
   204  	req := &message{}
   205  	req.mustUnmarshal(payload)
   206  
   207  	result := newReadResult(req.Keys, txnMeta, kv.continueRead)
   208  	for idx, key := range req.Keys {
   209  		if t, ok := kv.uncommittedKeyTxnMap[string(key)]; ok && needWait(*t, txnMeta) {
   210  			result.waitTxns = append(result.waitTxns, t.ID)
   211  			result.unreaded = append(result.unreaded, idx)
   212  			continue
   213  		}
   214  
   215  		result.values[idx] = kv.readValue(key, txnMeta)
   216  	}
   217  	return result, nil
   218  }
   219  
   220  func (kv *KVTxnStorage) continueRead(rs *readResult) bool {
   221  	kv.RLock()
   222  	defer kv.RUnlock()
   223  
   224  	if len(rs.unreaded) == 0 {
   225  		return true
   226  	}
   227  
   228  	for _, idx := range rs.unreaded {
   229  		key := rs.keys[idx]
   230  		txnMeta := rs.txnMeta
   231  		if t, ok := kv.uncommittedKeyTxnMap[string(key)]; ok && needWait(*t, txnMeta) {
   232  			return false
   233  		}
   234  
   235  		rs.values[idx] = kv.readValue(key, txnMeta)
   236  	}
   237  	return true
   238  }
   239  
   240  func (kv *KVTxnStorage) readValue(key []byte, txnMeta txn.TxnMeta) []byte {
   241  	if t, ok := kv.uncommittedKeyTxnMap[string(key)]; ok && bytes.Equal(t.ID, txnMeta.ID) {
   242  		if v, ok := kv.uncommitted.Get(key); ok {
   243  			return v
   244  		}
   245  	}
   246  
   247  	var value []byte
   248  	kv.committed.AscendRange(key, timestamp.Timestamp{}, txnMeta.SnapshotTS, func(v []byte, _ timestamp.Timestamp) {
   249  		value = v
   250  	})
   251  	return value
   252  }
   253  
   254  func (kv *KVTxnStorage) Write(ctx context.Context, txnMeta txn.TxnMeta, op uint32, payload []byte) ([]byte, error) {
   255  	kv.Lock()
   256  	defer kv.Unlock()
   257  
   258  	req := &message{}
   259  	req.mustUnmarshal(payload)
   260  
   261  	newTxn := txnMeta
   262  	for idx, key := range req.Keys {
   263  		if t, ok := kv.uncommittedKeyTxnMap[string(key)]; ok {
   264  			if !bytes.Equal(t.ID, txnMeta.ID) {
   265  				return nil, moerr.NewTxnWriteConflictNoCtx("%s %s", t.ID, txnMeta.ID)
   266  			}
   267  		} else {
   268  			kv.uncommittedKeyTxnMap[string(key)] = &newTxn
   269  		}
   270  
   271  		if _, ok := kv.uncommittedTxn[string(txnMeta.ID)]; !ok {
   272  			kv.uncommittedTxn[string(txnMeta.ID)] = &newTxn
   273  		}
   274  
   275  		kv.uncommitted.Set(key, req.Values[idx])
   276  	}
   277  	return nil, nil
   278  }
   279  
   280  func (kv *KVTxnStorage) Prepare(ctx context.Context, txnMeta txn.TxnMeta) (timestamp.Timestamp, error) {
   281  	kv.Lock()
   282  	defer kv.Unlock()
   283  
   284  	if _, ok := kv.uncommittedTxn[string(txnMeta.ID)]; !ok {
   285  		return timestamp.Timestamp{}, moerr.NewMissingTxnNoCtx()
   286  	}
   287  
   288  	txnMeta.PreparedTS, _ = kv.clock.Now()
   289  	writeKeys := kv.getWriteKeysLocked(txnMeta)
   290  	if kv.hasConflict(txnMeta.SnapshotTS,
   291  		timestamp.Timestamp{PhysicalTime: math.MaxInt64, LogicalTime: math.MaxUint32},
   292  		writeKeys) {
   293  		return timestamp.Timestamp{}, moerr.NewTxnWriteConflictNoCtx("")
   294  	}
   295  
   296  	log := kv.getLogWithDataLocked(txnMeta)
   297  	log.Txn.Status = txn.TxnStatus_Prepared
   298  	lsn, err := kv.saveLog(log)
   299  	if err != nil {
   300  		return timestamp.Timestamp{}, err
   301  	}
   302  
   303  	newTxn := kv.changeUncommittedTxnStatusLocked(txnMeta.ID, txn.TxnStatus_Prepared)
   304  	newTxn.PreparedTS = txnMeta.PreparedTS
   305  	newTxn.TNShards = txnMeta.TNShards
   306  	kv.recoverFrom = lsn
   307  	kv.eventC <- Event{Txn: *newTxn, Type: PrepareType}
   308  	return txnMeta.PreparedTS, nil
   309  }
   310  
   311  func (kv *KVTxnStorage) Committing(ctx context.Context, txnMeta txn.TxnMeta) error {
   312  	kv.Lock()
   313  	defer kv.Unlock()
   314  
   315  	if _, ok := kv.uncommittedTxn[string(txnMeta.ID)]; !ok {
   316  		return moerr.NewMissingTxnNoCtx()
   317  	}
   318  
   319  	log := &KVLog{Txn: txnMeta}
   320  	log.Txn.Status = txn.TxnStatus_Committing
   321  	lsn, err := kv.saveLog(log)
   322  	if err != nil {
   323  		return err
   324  	}
   325  
   326  	newTxn := kv.changeUncommittedTxnStatusLocked(txnMeta.ID, txn.TxnStatus_Committing)
   327  	newTxn.CommitTS = txnMeta.CommitTS
   328  	kv.recoverFrom = lsn
   329  	kv.eventC <- Event{Txn: *newTxn, Type: CommittingType}
   330  	return nil
   331  }
   332  
   333  func (kv *KVTxnStorage) Commit(ctx context.Context, txnMeta txn.TxnMeta) (timestamp.Timestamp, error) {
   334  	kv.Lock()
   335  	defer kv.Unlock()
   336  
   337  	if _, ok := kv.uncommittedTxn[string(txnMeta.ID)]; !ok {
   338  		return timestamp.Timestamp{}, nil
   339  	}
   340  
   341  	if txnMeta.CommitTS.IsEmpty() {
   342  		txnMeta.CommitTS, _ = kv.clock.Now()
   343  	}
   344  	writeKeys := kv.getWriteKeysLocked(txnMeta)
   345  	if kv.hasConflict(txnMeta.SnapshotTS, txnMeta.CommitTS.Next(), writeKeys) {
   346  		return timestamp.Timestamp{}, moerr.NewTxnWriteConflictNoCtx("")
   347  	}
   348  
   349  	var log *KVLog
   350  	if txnMeta.Status == txn.TxnStatus_Active {
   351  		log = kv.getLogWithDataLocked(txnMeta)
   352  	} else if txnMeta.Status == txn.TxnStatus_Prepared ||
   353  		txnMeta.Status == txn.TxnStatus_Committing {
   354  		log = &KVLog{Txn: txnMeta}
   355  	} else {
   356  		panic(fmt.Sprintf("commit with invalid status: %s", txnMeta.Status))
   357  	}
   358  	log.Txn.Status = txn.TxnStatus_Committed
   359  	log.Txn.CommitTS = txnMeta.CommitTS
   360  	lsn, err := kv.saveLog(log)
   361  	if err != nil {
   362  		return timestamp.Timestamp{}, err
   363  	}
   364  
   365  	kv.commitKeysLocked(txnMeta, writeKeys)
   366  	kv.recoverFrom = lsn
   367  	kv.eventC <- Event{Txn: log.Txn, Type: CommitType}
   368  	return log.Txn.CommitTS, nil
   369  }
   370  
   371  func (kv *KVTxnStorage) Rollback(ctx context.Context, txnMeta txn.TxnMeta) error {
   372  	kv.Lock()
   373  	defer kv.Unlock()
   374  
   375  	if _, ok := kv.uncommittedTxn[string(txnMeta.ID)]; !ok {
   376  		return nil
   377  	}
   378  
   379  	var writeKeys [][]byte
   380  	for k, v := range kv.uncommittedKeyTxnMap {
   381  		if bytes.Equal(v.ID, txnMeta.ID) {
   382  			writeKeys = append(writeKeys, []byte(k))
   383  		}
   384  	}
   385  
   386  	for _, key := range writeKeys {
   387  		kv.uncommitted.Delete(key)
   388  		delete(kv.uncommittedKeyTxnMap, string(key))
   389  	}
   390  
   391  	delete(kv.uncommittedTxn, string(txnMeta.ID))
   392  	kv.eventC <- Event{Txn: txnMeta, Type: RollbackType}
   393  	return nil
   394  }
   395  
   396  func (kv *KVTxnStorage) Debug(ctx context.Context, meta txn.TxnMeta, op uint32, data []byte) ([]byte, error) {
   397  	return data, nil
   398  }
   399  
   400  func (kv *KVTxnStorage) getLogWithDataLocked(txnMeta txn.TxnMeta) *KVLog {
   401  	log := &KVLog{Txn: txnMeta}
   402  	for k, v := range kv.uncommittedKeyTxnMap {
   403  		if bytes.Equal(v.ID, txnMeta.ID) {
   404  			log.Keys = append(log.Keys, []byte(k))
   405  		}
   406  	}
   407  	if len(log.Keys) == 0 {
   408  		panic("commit empty write set")
   409  	}
   410  
   411  	for _, key := range log.Keys {
   412  		v, ok := kv.uncommitted.Get(key)
   413  		if !ok {
   414  			panic("missing write set")
   415  		}
   416  
   417  		log.Values = append(log.Values, v)
   418  	}
   419  	return log
   420  }
   421  
   422  func (kv *KVTxnStorage) hasConflict(from, to timestamp.Timestamp, writeKeys [][]byte) bool {
   423  	for _, key := range writeKeys {
   424  		n := 0
   425  		kv.committed.AscendRange(key, from, to, func(_ []byte, _ timestamp.Timestamp) {
   426  			n++
   427  		})
   428  		if n > 0 {
   429  			return true
   430  		}
   431  	}
   432  	return false
   433  }
   434  
   435  func (kv *KVTxnStorage) getWriteKeysLocked(txnMeta txn.TxnMeta) [][]byte {
   436  	var writeKeys [][]byte
   437  	for k, v := range kv.uncommittedKeyTxnMap {
   438  		if bytes.Equal(v.ID, txnMeta.ID) {
   439  			writeKeys = append(writeKeys, []byte(k))
   440  		}
   441  	}
   442  	return writeKeys
   443  }
   444  
   445  func (kv *KVTxnStorage) saveLog(log *KVLog) (logservice.Lsn, error) {
   446  	ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
   447  	defer cancel()
   448  	data := log.MustMarshal()
   449  	record := kv.logClient.GetLogRecord(len(data))
   450  	if len(record.Data) == 0 {
   451  		record.Data = data
   452  	} else {
   453  		copy(record.Data[len(record.Data)-len(data):], data)
   454  	}
   455  	return kv.logClient.Append(ctx, record)
   456  }
   457  
   458  func (kv *KVTxnStorage) commitWithKVLogLocked(klog *KVLog) {
   459  	for idx := range klog.Keys {
   460  		key := klog.Keys[idx]
   461  		value := klog.Values[idx]
   462  		kv.committed.Set(key, klog.Txn.CommitTS, value)
   463  	}
   464  }
   465  
   466  func (kv *KVTxnStorage) commitKeysLocked(txnMeta txn.TxnMeta, keys [][]byte) {
   467  	for _, key := range keys {
   468  		v, ok := kv.uncommitted.Get(key)
   469  		if !ok {
   470  			panic("missing write set")
   471  		}
   472  
   473  		kv.uncommitted.Delete(key)
   474  		delete(kv.uncommittedKeyTxnMap, string(key))
   475  		kv.committed.Set(key, txnMeta.CommitTS, v)
   476  	}
   477  	delete(kv.uncommittedTxn, string(txnMeta.ID))
   478  }
   479  
   480  func (kv *KVTxnStorage) changeUncommittedTxnStatusLocked(id []byte, status txn.TxnStatus) *txn.TxnMeta {
   481  	newTxn := kv.uncommittedTxn[string(id)]
   482  	newTxn.Status = status
   483  	return newTxn
   484  }
   485  
   486  func needWait(writeTxn, readTxn txn.TxnMeta) bool {
   487  	if bytes.Equal(writeTxn.ID, readTxn.ID) {
   488  		return false
   489  	}
   490  
   491  	switch writeTxn.Status {
   492  	case txn.TxnStatus_Prepared:
   493  		return readTxn.SnapshotTS.Greater(writeTxn.PreparedTS)
   494  	case txn.TxnStatus_Committing:
   495  		return readTxn.SnapshotTS.Greater(writeTxn.CommitTS)
   496  	}
   497  	return false
   498  }
   499  
   500  var (
   501  	setOpCode uint32 = 1
   502  	getOpCode uint32 = 2
   503  )
   504  
   505  type message struct {
   506  	Keys   [][]byte `json:"key,omitempty"`
   507  	Values [][]byte `json:"value,omitempty"`
   508  }
   509  
   510  func (r *message) mustUnmarshal(payload []byte) {
   511  	if err := json.Unmarshal(payload, r); err != nil {
   512  		panic(err)
   513  	}
   514  }
   515  
   516  func (r *message) mustMarshal() []byte {
   517  	v, err := json.Marshal(r)
   518  	if err != nil {
   519  		panic(err)
   520  	}
   521  	return v
   522  }
   523  
   524  type readResult struct {
   525  	txnMeta          txn.TxnMeta
   526  	keys             [][]byte
   527  	waitTxns         [][]byte
   528  	values           [][]byte
   529  	unreaded         []int
   530  	continueReadFunc func(rs *readResult) bool
   531  }
   532  
   533  func newReadResult(keys [][]byte, txnMeta txn.TxnMeta, continueReadFunc func(rs *readResult) bool) *readResult {
   534  	return &readResult{
   535  		keys:             keys,
   536  		values:           make([][]byte, len(keys)),
   537  		continueReadFunc: continueReadFunc,
   538  		txnMeta:          txnMeta,
   539  	}
   540  }
   541  
   542  func (rs *readResult) WaitTxns() [][]byte {
   543  	return rs.waitTxns
   544  }
   545  
   546  func (rs *readResult) Read() ([]byte, error) {
   547  	if !rs.continueReadFunc(rs) {
   548  		return nil, moerr.NewMissingTxnNoCtx()
   549  	}
   550  
   551  	resp := &message{Values: rs.values}
   552  	return resp.mustMarshal(), nil
   553  }
   554  
   555  func (rs *readResult) Release() {
   556  
   557  }