197 lines
5.7 KiB
Go
197 lines
5.7 KiB
Go
// /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
|
||
}
|