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 }