2026-02-27 22:04:04 +03:00

197 lines
5.7 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// /futriis/internal/storage/slice.go
// Пакет storage реализует операции со слайсами (таблицами) - контейнерами для кортежей.
// SliceManager управляет созданием, получением, удалением и списком слайсов внутри тапплов.
// Интегрируется с TupleManager для операций с кортежами на более низком уровне.
// Обеспечивает wait-free доступ к слайсам через атомарные операции.
package storage
import (
"errors"
"reflect"
"sync"
"sync/atomic"
"time"
"futriis/pkg/types"
"futriis/pkg/utils"
)
// SliceManager управляет операциями со слайсами
type SliceManager struct {
tupleManager *TupleManager
stats struct {
created int64
deleted int64
}
// Добавляем собственную блокировку для управления доступом к тапплам
mu sync.RWMutex
}
// NewSliceManager создаёт новый менеджер слайсов
func NewSliceManager() *SliceManager {
return &SliceManager{
tupleManager: NewTupleManager(),
}
}
// вспомогательная функция для доступа к неэкспортируемому полю slices
func getSlicesFromTapple(tapple *types.Tapple) map[string]*types.Slice {
// Используем рефлексию для доступа к неэкспортируемому полю
v := reflect.ValueOf(tapple).Elem()
field := v.FieldByName("slices")
if field.IsValid() && field.Kind() == reflect.Map {
// Преобразуем в map[string]*types.Slice
result := make(map[string]*types.Slice)
iter := field.MapRange()
for iter.Next() {
key := iter.Key().String()
value := iter.Value().Interface()
if slice, ok := value.(*types.Slice); ok {
result[key] = slice
}
}
return result
}
return make(map[string]*types.Slice)
}
// вспомогательная функция для добавления слайса в неэкспортируемое поле slices
func addSliceToTapple(tapple *types.Tapple, name string, slice *types.Slice) error {
v := reflect.ValueOf(tapple).Elem()
field := v.FieldByName("slices")
if field.IsValid() && field.Kind() == reflect.Map {
// Создаём новую map, если она nil
if field.IsNil() {
newMap := reflect.MakeMap(reflect.TypeOf(map[string]*types.Slice{}))
field.Set(newMap)
}
// Устанавливаем значение
key := reflect.ValueOf(name)
value := reflect.ValueOf(slice)
field.SetMapIndex(key, value)
return nil
}
return errors.New("cannot access slices field in tapple")
}
// вспомогательная функция для удаления слайса из неэкспортируемого поля slices
func removeSliceFromTapple(tapple *types.Tapple, name string) error {
v := reflect.ValueOf(tapple).Elem()
field := v.FieldByName("slices")
if field.IsValid() && field.Kind() == reflect.Map {
key := reflect.ValueOf(name)
field.SetMapIndex(key, reflect.Value{})
return nil
}
return errors.New("cannot access slices field in tapple")
}
// CreateSlice создаёт новый слайс в указанном таппле с временной меткой
func (sm *SliceManager) CreateSlice(tapple *types.Tapple, name string) (*types.Slice, error) {
if tapple == nil {
return nil, errors.New("tapple is nil")
}
// Используем блокировку менеджера для доступа к тапплу
sm.mu.Lock()
defer sm.mu.Unlock()
// Получаем слайсы через рефлексию
slices := getSlicesFromTapple(tapple)
_, exists := slices[name]
if exists {
return nil, errors.New("slice already exists")
}
slice := types.NewSlice(name)
slice.CreatedAt = time.Now()
slice.UpdatedAt = time.Now()
// Добавляем слайс через рефлексию
err := addSliceToTapple(tapple, name, slice)
if err != nil {
return nil, err
}
atomic.AddInt64(&sm.stats.created, 1)
logger := utils.GetLogger()
if logger != nil {
logger.Log("INFO", "Created slice: "+name+" at "+slice.CreatedAt.Format(time.RFC3339))
}
return slice, nil
}
// GetSlice возвращает слайс по имени
func (sm *SliceManager) GetSlice(tapple *types.Tapple, name string) (*types.Slice, error) {
if tapple == nil {
return nil, errors.New("tapple is nil")
}
sm.mu.RLock()
defer sm.mu.RUnlock()
slices := getSlicesFromTapple(tapple)
slice, exists := slices[name]
if !exists {
return nil, errors.New("slice not found")
}
return slice, nil
}
// DeleteSlice удаляет слайс
func (sm *SliceManager) DeleteSlice(tapple *types.Tapple, name string) error {
if tapple == nil {
return errors.New("tapple is nil")
}
sm.mu.Lock()
defer sm.mu.Unlock()
slices := getSlicesFromTapple(tapple)
_, exists := slices[name]
if !exists {
return errors.New("slice not found")
}
err := removeSliceFromTapple(tapple, name)
if err != nil {
return err
}
atomic.AddInt64(&sm.stats.deleted, 1)
logger := utils.GetLogger()
if logger != nil {
logger.Log("INFO", "Deleted slice: "+name)
}
return nil
}
// ListSlices возвращает список всех слайсов в таппле
func (sm *SliceManager) ListSlices(tapple *types.Tapple) []string {
if tapple == nil {
return nil
}
sm.mu.RLock()
defer sm.mu.RUnlock()
slices := getSlicesFromTapple(tapple)
result := make([]string, 0, len(slices))
for name := range slices {
result = append(result, name)
}
return result
}
// GetTupleManager возвращает менеджер кортежей
func (sm *SliceManager) GetTupleManager() *TupleManager {
return sm.tupleManager
}