150 lines
3.5 KiB
Go
150 lines
3.5 KiB
Go
|
|
// /futriis/internal/storage/tuple.go
|
|||
|
|
// Пакет storage реализует операции с кортежами (записями)
|
|||
|
|
|
|||
|
|
package storage
|
|||
|
|
|
|||
|
|
import (
|
|||
|
|
"errors"
|
|||
|
|
"sync/atomic"
|
|||
|
|
|
|||
|
|
"futriis/pkg/types"
|
|||
|
|
"futriis/pkg/utils"
|
|||
|
|
)
|
|||
|
|
// TupleManager управляет операциями с кортежами
|
|||
|
|
type TupleManager struct {
|
|||
|
|
stats struct {
|
|||
|
|
created int64
|
|||
|
|
updated int64
|
|||
|
|
deleted int64
|
|||
|
|
read int64
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// NewTupleManager создаёт новый менеджер кортежей
|
|||
|
|
func NewTupleManager() *TupleManager {
|
|||
|
|
return &TupleManager{}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// CreateTuple создаёт новый кортеж в указанном слайсе
|
|||
|
|
// Wait-free операция: использует атомарные операции для счётчиков
|
|||
|
|
func (tm *TupleManager) CreateTuple(slice *types.Slice, id string, fields map[string]interface{}) (*types.Tuple, error) {
|
|||
|
|
if slice == nil {
|
|||
|
|
return nil, errors.New("slice is nil")
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Проверяем существование кортежа
|
|||
|
|
slice.RLock()
|
|||
|
|
_, exists := slice.Tuples[id]
|
|||
|
|
slice.RUnlock()
|
|||
|
|
|
|||
|
|
if exists {
|
|||
|
|
return nil, errors.New("tuple already exists")
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Создаём новый кортеж
|
|||
|
|
tuple := types.NewTuple(id)
|
|||
|
|
for k, v := range fields {
|
|||
|
|
tuple.Fields[k] = v
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Добавляем в слайс
|
|||
|
|
slice.Lock()
|
|||
|
|
slice.Tuples[id] = tuple
|
|||
|
|
slice.Unlock()
|
|||
|
|
|
|||
|
|
// Атомарно увеличиваем счётчик созданных
|
|||
|
|
atomic.AddInt64(&tm.stats.created, 1)
|
|||
|
|
|
|||
|
|
// Логируем операцию
|
|||
|
|
logger := utils.GetLogger()
|
|||
|
|
if logger != nil {
|
|||
|
|
logger.Log("INFO", "Created tuple: "+id)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return tuple, nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ReadTuple читает кортеж по ID
|
|||
|
|
// Wait-free операция для чтения
|
|||
|
|
func (tm *TupleManager) ReadTuple(slice *types.Slice, id string) (*types.Tuple, error) {
|
|||
|
|
if slice == nil {
|
|||
|
|
return nil, errors.New("slice is nil")
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
slice.RLock()
|
|||
|
|
tuple, exists := slice.Tuples[id]
|
|||
|
|
slice.RUnlock()
|
|||
|
|
|
|||
|
|
if !exists {
|
|||
|
|
return nil, errors.New("tuple not found")
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
atomic.AddInt64(&tm.stats.read, 1)
|
|||
|
|
return tuple, nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// UpdateTuple обновляет поля кортежа
|
|||
|
|
func (tm *TupleManager) UpdateTuple(slice *types.Slice, id string, fields map[string]interface{}) (*types.Tuple, error) {
|
|||
|
|
if slice == nil {
|
|||
|
|
return nil, errors.New("slice is nil")
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
slice.Lock()
|
|||
|
|
defer slice.Unlock()
|
|||
|
|
|
|||
|
|
tuple, exists := slice.Tuples[id]
|
|||
|
|
if !exists {
|
|||
|
|
return nil, errors.New("tuple not found")
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Обновляем поля
|
|||
|
|
for k, v := range fields {
|
|||
|
|
tuple.Fields[k] = v
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
atomic.AddInt64(&tm.stats.updated, 1)
|
|||
|
|
|
|||
|
|
logger := utils.GetLogger()
|
|||
|
|
if logger != nil {
|
|||
|
|
logger.Log("INFO", "Updated tuple: "+id)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return tuple, nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// DeleteTuple удаляет кортеж
|
|||
|
|
func (tm *TupleManager) DeleteTuple(slice *types.Slice, id string) error {
|
|||
|
|
if slice == nil {
|
|||
|
|
return errors.New("slice is nil")
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
slice.Lock()
|
|||
|
|
_, exists := slice.Tuples[id]
|
|||
|
|
if !exists {
|
|||
|
|
slice.Unlock()
|
|||
|
|
return errors.New("tuple not found")
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
delete(slice.Tuples, id)
|
|||
|
|
slice.Unlock()
|
|||
|
|
|
|||
|
|
atomic.AddInt64(&tm.stats.deleted, 1)
|
|||
|
|
|
|||
|
|
logger := utils.GetLogger()
|
|||
|
|
if logger != nil {
|
|||
|
|
logger.Log("INFO", "Deleted tuple: "+id)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// GetStats возвращает статистику операций
|
|||
|
|
func (tm *TupleManager) GetStats() map[string]int64 {
|
|||
|
|
return map[string]int64{
|
|||
|
|
"created": atomic.LoadInt64(&tm.stats.created),
|
|||
|
|
"updated": atomic.LoadInt64(&tm.stats.updated),
|
|||
|
|
"deleted": atomic.LoadInt64(&tm.stats.deleted),
|
|||
|
|
"read": atomic.LoadInt64(&tm.stats.read),
|
|||
|
|
}
|
|||
|
|
}
|