157 lines
4.9 KiB
Go
Raw Normal View History

2026-02-27 22:04:04 +03:00
// /futriis/internal/storage/tapple.go
// Пакет storage реализует операции с тапплами (базами данных) - контейнерами верхнего уровня.
// TappleManager управляет созданием, удалением и получением тапплов, каждый из которых содержит коллекцию слайсов (таблиц).
// Интегрируется с SliceManager для операций со слайсами.
// Обеспечивает wait-free хранение тапплов в памяти с использованием атомарных указателей.
package storage
import (
"errors"
"sync/atomic"
"time"
"unsafe"
"futriis/pkg/types"
"futriis/pkg/utils"
)
// TappleManager управляет операциями с тапплами (wait-free)
type TappleManager struct {
tapples unsafe.Pointer // Атомарный указатель на map[string]*types.Tapple
sliceManager *SliceManager
indexManager *IndexManager
stats struct {
created int64
deleted int64
}
}
// NewTappleManager создаёт новый менеджер тапплов
func NewTappleManager() *TappleManager {
// Инициализируем пустую карту
tapples := make(map[string]*types.Tapple)
return &TappleManager{
tapples: unsafe.Pointer(&tapples),
sliceManager: NewSliceManager(),
indexManager: NewIndexManager(),
}
}
// CreateTapple создаёт новый таппл с временной меткой
func (tm *TappleManager) CreateTapple(name string) (*types.Tapple, error) {
// Получаем текущую карту
oldPtr := atomic.LoadPointer(&tm.tapples)
oldTapples := *(*map[string]*types.Tapple)(oldPtr)
// Проверяем существование
if _, exists := oldTapples[name]; exists {
return nil, errors.New("tapple already exists")
}
// Создаём новый таппл с временной меткой
tapple := types.NewTapple(name)
tapple.CreatedAt = time.Now()
tapple.UpdatedAt = time.Now()
// Создаём новую карту
newTapples := make(map[string]*types.Tapple)
for k, v := range oldTapples {
newTapples[k] = v
}
newTapples[name] = tapple
// Атомарно обновляем указатель
atomic.StorePointer(&tm.tapples, unsafe.Pointer(&newTapples))
atomic.AddInt64(&tm.stats.created, 1)
logger := utils.GetLogger()
if logger != nil {
logger.Log("INFO", "Created tapple: "+name+" at "+tapple.CreatedAt.Format(time.RFC3339))
}
return tapple, nil
}
// GetTapple возвращает таппл по имени (wait-free)
func (tm *TappleManager) GetTapple(name string) (*types.Tapple, error) {
// Атомарно загружаем указатель
ptr := atomic.LoadPointer(&tm.tapples)
tapples := *(*map[string]*types.Tapple)(ptr)
tapple, exists := tapples[name]
if !exists {
return nil, errors.New("tapple not found")
}
return tapple, nil
}
// GetAllTapples возвращает копию всех тапплов (для Backup)
func (tm *TappleManager) GetAllTapples() map[string]*types.Tapple {
ptr := atomic.LoadPointer(&tm.tapples)
tapples := *(*map[string]*types.Tapple)(ptr)
// Создаём копию для безопасного использования
result := make(map[string]*types.Tapple)
for k, v := range tapples {
result[k] = v
}
return result
}
// DeleteTapple удаляет таппл
func (tm *TappleManager) DeleteTapple(name string) error {
// Получаем текущую карту
oldPtr := atomic.LoadPointer(&tm.tapples)
oldTapples := *(*map[string]*types.Tapple)(oldPtr)
// Проверяем существование
if _, exists := oldTapples[name]; !exists {
return errors.New("tapple not found")
}
// Создаём новую карту без удаляемого таппла
newTapples := make(map[string]*types.Tapple)
for k, v := range oldTapples {
if k != name {
newTapples[k] = v
}
}
// Атомарно обновляем указатель
atomic.StorePointer(&tm.tapples, unsafe.Pointer(&newTapples))
atomic.AddInt64(&tm.stats.deleted, 1)
logger := utils.GetLogger()
if logger != nil {
logger.Log("INFO", "Deleted tapple: "+name)
}
return nil
}
// ListTapples возвращает список всех тапплов (wait-free)
func (tm *TappleManager) ListTapples() []string {
ptr := atomic.LoadPointer(&tm.tapples)
tapples := *(*map[string]*types.Tapple)(ptr)
result := make([]string, 0, len(tapples))
for name := range tapples {
result = append(result, name)
}
return result
}
// GetSliceManager возвращает менеджер слайсов
func (tm *TappleManager) GetSliceManager() *SliceManager {
return tm.sliceManager
}
// GetIndexManager возвращает менеджер индексов
func (tm *TappleManager) GetIndexManager() *IndexManager {
return tm.indexManager
}