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