github.com/matrixorigin/matrixone@v1.2.0/pkg/txn/storage/memorystorage/memorytable/batch.go (about)

     1  // Copyright 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 memorytable
    16  
    17  import (
    18  	"database/sql"
    19  	"sync/atomic"
    20  
    21  	"github.com/matrixorigin/matrixone/pkg/common/moerr"
    22  )
    23  
    24  // Batch represents a batch of operations that commit atomically
    25  type Batch[
    26  	K Ordered[K],
    27  	V any,
    28  	R Row[K, V],
    29  ] struct {
    30  	txTable   *transactionTable
    31  	initState *tableState[K, V]
    32  	state     *tableState[K, V]
    33  	lastErr   error
    34  }
    35  
    36  // NewBatch creates a new batch for tx
    37  func (t *Table[K, V, R]) NewBatch(tx *Transaction) (*Batch[K, V, R], error) {
    38  	txTable, err := t.getTransactionTable(tx)
    39  	if err != nil {
    40  		return nil, err
    41  	}
    42  	initState := txTable.state.Load().(*tableState[K, V])
    43  	return &Batch[K, V, R]{
    44  		txTable:   txTable,
    45  		initState: initState,
    46  		state:     initState.clone(),
    47  	}, nil
    48  }
    49  
    50  // Commit commits the batch
    51  func (b *Batch[K, V, R]) Commit() {
    52  	if b.lastErr != nil {
    53  		panic("batch is invalid")
    54  	}
    55  	if !b.txTable.state.CompareAndSwap(b.initState, b.state) {
    56  		panic("concurrent mutation")
    57  	}
    58  }
    59  
    60  // Insert inserts a row
    61  func (b *Batch[K, V, R]) Insert(row R) (err error) {
    62  	if b.lastErr != nil {
    63  		panic("batch is invalid")
    64  	}
    65  	defer func() {
    66  		if err != nil {
    67  			b.lastErr = err
    68  		}
    69  	}()
    70  
    71  	key := row.Key()
    72  	pair := &KVPair[K, V]{
    73  		Key: key,
    74  	}
    75  
    76  	_, ok := b.state.tree.Get(TreeNode[K, V]{
    77  		KVPair: pair,
    78  	})
    79  	if ok {
    80  		return moerr.NewDuplicateNoCtx()
    81  	}
    82  
    83  	pair.KVValue = new(KVValue[K, V])
    84  	pair.ID = atomic.AddInt64(&nextKVPairID, 1)
    85  	pair.Value = row.Value()
    86  	pair.Indexes = row.Indexes()
    87  	b.state.setPair(pair, nil)
    88  
    89  	return nil
    90  }
    91  
    92  // Update updates a row
    93  func (b *Batch[K, V, R]) Update(row R) (err error) {
    94  	if b.lastErr != nil {
    95  		panic("batch is invalid")
    96  	}
    97  	defer func() {
    98  		if err != nil {
    99  			b.lastErr = err
   100  		}
   101  	}()
   102  
   103  	key := row.Key()
   104  	pair := &KVPair[K, V]{
   105  		Key: key,
   106  	}
   107  
   108  	oldNode, ok := b.state.tree.Get(TreeNode[K, V]{
   109  		KVPair: pair,
   110  	})
   111  	if !ok {
   112  		return sql.ErrNoRows
   113  	}
   114  
   115  	pair.KVValue = new(KVValue[K, V])
   116  	pair.ID = atomic.AddInt64(&nextKVPairID, 1)
   117  	pair.Value = row.Value()
   118  	pair.Indexes = row.Indexes()
   119  	b.state.setPair(pair, oldNode.KVPair)
   120  
   121  	return nil
   122  }
   123  
   124  // Delete deletes a row
   125  func (b *Batch[K, V, R]) Delete(key K) (err error) {
   126  	if b.lastErr != nil {
   127  		panic("batch is invalid")
   128  	}
   129  	defer func() {
   130  		if err != nil {
   131  			b.lastErr = err
   132  		}
   133  	}()
   134  
   135  	pivot := KVPair[K, V]{
   136  		Key: key,
   137  	}
   138  
   139  	oldNode, ok := b.state.tree.Get(TreeNode[K, V]{
   140  		KVPair: &pivot,
   141  	})
   142  	if !ok {
   143  		return sql.ErrNoRows
   144  	}
   145  
   146  	b.state.unsetPair(pivot, oldNode.KVPair)
   147  
   148  	return nil
   149  }
   150  
   151  // Upsert update or insert a row
   152  func (b *Batch[K, V, R]) Upsert(row R) (err error) {
   153  	if b.lastErr != nil {
   154  		panic("batch is invalid")
   155  	}
   156  	defer func() {
   157  		if err != nil {
   158  			b.lastErr = err
   159  		}
   160  	}()
   161  
   162  	key := row.Key()
   163  	pair := &KVPair[K, V]{
   164  		Key: key,
   165  	}
   166  
   167  	oldNode, _ := b.state.tree.Get(TreeNode[K, V]{
   168  		KVPair: pair,
   169  	})
   170  	pair.KVValue = new(KVValue[K, V])
   171  	pair.ID = atomic.AddInt64(&nextKVPairID, 1)
   172  	pair.Value = row.Value()
   173  	pair.Indexes = row.Indexes()
   174  	b.state.setPair(pair, oldNode.KVPair)
   175  
   176  	return nil
   177  }
   178  
   179  // Get gets the value of key
   180  func (b *Batch[K, V, R]) Get(key K) (value V, err error) {
   181  	if b.lastErr != nil {
   182  		panic("batch is invalid")
   183  	}
   184  	defer func() {
   185  		if err != nil {
   186  			b.lastErr = err
   187  		}
   188  	}()
   189  
   190  	node := TreeNode[K, V]{
   191  		KVPair: &KVPair[K, V]{
   192  			Key: key,
   193  		},
   194  	}
   195  	node, ok := b.state.tree.Get(node)
   196  	if !ok {
   197  		err = sql.ErrNoRows
   198  		return
   199  	}
   200  	value = node.KVPair.Value
   201  	return
   202  }