157 lines
4.9 KiB
Go
157 lines
4.9 KiB
Go
// /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
|
||
}
|