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 }