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