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