146 lines
3.3 KiB
Go
146 lines
3.3 KiB
Go
// /futriis/internal/transaction/tx.go
|
|
// Пакет transaction реализует простые транзакции (не ACID)
|
|
|
|
package transaction
|
|
|
|
import (
|
|
"errors"
|
|
"sync"
|
|
|
|
"futriis/pkg/types"
|
|
)
|
|
|
|
// TxState состояние транзакции
|
|
type TxState int
|
|
|
|
const (
|
|
TxStateActive TxState = iota
|
|
TxStateCommited
|
|
TxStateRolledBack
|
|
)
|
|
|
|
// Operation представляет операцию в транзакции
|
|
type Operation struct {
|
|
Type string // create, update, delete
|
|
Tapple string
|
|
Slice string
|
|
Key string
|
|
Value interface{}
|
|
OldValue interface{}
|
|
}
|
|
|
|
// Transaction представляет транзакцию
|
|
type Transaction struct {
|
|
ID string
|
|
State TxState
|
|
Operations []Operation
|
|
mu sync.RWMutex
|
|
}
|
|
|
|
// TransactionManager управляет транзакциями
|
|
type TransactionManager struct {
|
|
transactions map[string]*Transaction
|
|
currentTx *Transaction
|
|
mu sync.RWMutex
|
|
}
|
|
|
|
// NewTransactionManager создаёт новый менеджер транзакций
|
|
func NewTransactionManager() *TransactionManager {
|
|
return &TransactionManager{
|
|
transactions: make(map[string]*Transaction),
|
|
}
|
|
}
|
|
|
|
// Begin начинает новую транзакцию
|
|
func (tm *TransactionManager) Begin() (string, error) {
|
|
tm.mu.Lock()
|
|
defer tm.mu.Unlock()
|
|
|
|
if tm.currentTx != nil && tm.currentTx.State == TxStateActive {
|
|
return "", errors.New("транзакция уже активна")
|
|
}
|
|
|
|
id := generateTxID()
|
|
tx := &Transaction{
|
|
ID: id,
|
|
State: TxStateActive,
|
|
Operations: make([]Operation, 0),
|
|
}
|
|
|
|
tm.transactions[id] = tx
|
|
tm.currentTx = tx
|
|
|
|
return id, nil
|
|
}
|
|
|
|
// Commit фиксирует текущую транзакцию
|
|
func (tm *TransactionManager) Commit() error {
|
|
tm.mu.Lock()
|
|
defer tm.mu.Unlock()
|
|
|
|
if tm.currentTx == nil {
|
|
return errors.New("нет активной транзакции")
|
|
}
|
|
|
|
if tm.currentTx.State != TxStateActive {
|
|
return errors.New("транзакция не активна")
|
|
}
|
|
|
|
tm.currentTx.State = TxStateCommited
|
|
tm.currentTx = nil
|
|
|
|
return nil
|
|
}
|
|
|
|
// Rollback откатывает текущую транзакцию
|
|
func (tm *TransactionManager) Rollback() error {
|
|
tm.mu.Lock()
|
|
defer tm.mu.Unlock()
|
|
|
|
if tm.currentTx == nil {
|
|
return errors.New("нет активной транзакции")
|
|
}
|
|
|
|
if tm.currentTx.State != TxStateActive {
|
|
return errors.New("транзакция не активна")
|
|
}
|
|
|
|
tm.currentTx.State = TxStateRolledBack
|
|
tm.currentTx = nil
|
|
|
|
return nil
|
|
}
|
|
|
|
// AddOperation добавляет операцию в текущую транзакцию
|
|
func (tm *TransactionManager) AddOperation(op Operation) error {
|
|
tm.mu.RLock()
|
|
tx := tm.currentTx
|
|
tm.mu.RUnlock()
|
|
|
|
if tx == nil {
|
|
return errors.New("нет активной транзакции")
|
|
}
|
|
|
|
tx.mu.Lock()
|
|
defer tx.mu.Unlock()
|
|
|
|
if tx.State != TxStateActive {
|
|
return errors.New("транзакция не активна")
|
|
}
|
|
|
|
tx.Operations = append(tx.Operations, op)
|
|
return nil
|
|
}
|
|
|
|
// GetCurrentTx возвращает текущую транзакцию
|
|
func (tm *TransactionManager) GetCurrentTx() *Transaction {
|
|
tm.mu.RLock()
|
|
defer tm.mu.RUnlock()
|
|
return tm.currentTx
|
|
}
|
|
|
|
// generateTxID генерирует ID транзакции
|
|
func generateTxID() string {
|
|
return "tx-" + types.GenerateID()
|
|
}
|