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),
|
||
}
|
||
}
|