189 lines
5.2 KiB
Go
189 lines
5.2 KiB
Go
// /futriis/pkg/types/types.go
|
||
// Пакет types определяет основные структуры данных СУБД Futriis.
|
||
// Содержит определения для тапплов (баз данных), слайсов (таблиц) и кортежей (записей).
|
||
// Использует wait-free подход с атомарными операциями вместо мьютексов.
|
||
|
||
package types
|
||
|
||
import (
|
||
"sync/atomic"
|
||
"time"
|
||
"unsafe"
|
||
)
|
||
|
||
// Tapple представляет базу данных (контейнер верхнего уровня) с wait-free доступом
|
||
type Tapple struct {
|
||
Name string
|
||
slices unsafe.Pointer // Атомарный указатель на map[string]*Slice
|
||
CreatedAt time.Time
|
||
UpdatedAt time.Time
|
||
}
|
||
|
||
// NewTapple создаёт новый таппл с wait-free доступом
|
||
func NewTapple(name string) *Tapple {
|
||
slices := make(map[string]*Slice)
|
||
return &Tapple{
|
||
Name: name,
|
||
slices: unsafe.Pointer(&slices),
|
||
CreatedAt: time.Now(),
|
||
UpdatedAt: time.Now(),
|
||
}
|
||
}
|
||
|
||
// GetSlices атомарно получает карту слайсов
|
||
func (t *Tapple) GetSlices() map[string]*Slice {
|
||
ptr := atomic.LoadPointer(&t.slices)
|
||
return *(*map[string]*Slice)(ptr)
|
||
}
|
||
|
||
// GetSlice атомарно получает слайс по имени
|
||
func (t *Tapple) GetSlice(name string) (*Slice, bool) {
|
||
slices := t.GetSlices()
|
||
slice, exists := slices[name]
|
||
return slice, exists
|
||
}
|
||
|
||
// PutSlice атомарно добавляет или обновляет слайс
|
||
func (t *Tapple) PutSlice(name string, slice *Slice) {
|
||
for {
|
||
oldPtr := atomic.LoadPointer(&t.slices)
|
||
oldSlices := *(*map[string]*Slice)(oldPtr)
|
||
|
||
// Создаём новую карту
|
||
newSlices := make(map[string]*Slice)
|
||
for k, v := range oldSlices {
|
||
newSlices[k] = v
|
||
}
|
||
newSlices[name] = slice
|
||
|
||
// Пытаемся атомарно обновить
|
||
if atomic.CompareAndSwapPointer(&t.slices, oldPtr, unsafe.Pointer(&newSlices)) {
|
||
t.UpdatedAt = time.Now()
|
||
break
|
||
}
|
||
}
|
||
}
|
||
|
||
// DeleteSlice атомарно удаляет слайс
|
||
func (t *Tapple) DeleteSlice(name string) bool {
|
||
for {
|
||
oldPtr := atomic.LoadPointer(&t.slices)
|
||
oldSlices := *(*map[string]*Slice)(oldPtr)
|
||
|
||
if _, exists := oldSlices[name]; !exists {
|
||
return false
|
||
}
|
||
|
||
// Создаём новую карту без удаляемого слайса
|
||
newSlices := make(map[string]*Slice)
|
||
for k, v := range oldSlices {
|
||
if k != name {
|
||
newSlices[k] = v
|
||
}
|
||
}
|
||
|
||
// Пытаемся атомарно обновить
|
||
if atomic.CompareAndSwapPointer(&t.slices, oldPtr, unsafe.Pointer(&newSlices)) {
|
||
t.UpdatedAt = time.Now()
|
||
return true
|
||
}
|
||
}
|
||
}
|
||
|
||
// Slice представляет таблицу (контейнер для кортежей) с wait-free доступом
|
||
type Slice struct {
|
||
Name string
|
||
tuples unsafe.Pointer // Атомарный указатель на map[string]*Tuple
|
||
CreatedAt time.Time
|
||
UpdatedAt time.Time
|
||
}
|
||
|
||
// NewSlice создаёт новый слайс с wait-free доступом
|
||
func NewSlice(name string) *Slice {
|
||
tuples := make(map[string]*Tuple)
|
||
return &Slice{
|
||
Name: name,
|
||
tuples: unsafe.Pointer(&tuples),
|
||
CreatedAt: time.Now(),
|
||
UpdatedAt: time.Now(),
|
||
}
|
||
}
|
||
|
||
// GetTuples атомарно получает карту кортежей
|
||
func (s *Slice) GetTuples() map[string]*Tuple {
|
||
ptr := atomic.LoadPointer(&s.tuples)
|
||
return *(*map[string]*Tuple)(ptr)
|
||
}
|
||
|
||
// GetTuple атомарно получает кортеж по ID
|
||
func (s *Slice) GetTuple(id string) (*Tuple, bool) {
|
||
tuples := s.GetTuples()
|
||
tuple, exists := tuples[id]
|
||
return tuple, exists
|
||
}
|
||
|
||
// PutTuple атомарно добавляет или обновляет кортеж
|
||
func (s *Slice) PutTuple(id string, tuple *Tuple) {
|
||
for {
|
||
oldPtr := atomic.LoadPointer(&s.tuples)
|
||
oldTuples := *(*map[string]*Tuple)(oldPtr)
|
||
|
||
// Создаём новую карту
|
||
newTuples := make(map[string]*Tuple)
|
||
for k, v := range oldTuples {
|
||
newTuples[k] = v
|
||
}
|
||
newTuples[id] = tuple
|
||
|
||
// Пытаемся атомарно обновить
|
||
if atomic.CompareAndSwapPointer(&s.tuples, oldPtr, unsafe.Pointer(&newTuples)) {
|
||
s.UpdatedAt = time.Now()
|
||
break
|
||
}
|
||
}
|
||
}
|
||
|
||
// DeleteTuple атомарно удаляет кортеж
|
||
func (s *Slice) DeleteTuple(id string) bool {
|
||
for {
|
||
oldPtr := atomic.LoadPointer(&s.tuples)
|
||
oldTuples := *(*map[string]*Tuple)(oldPtr)
|
||
|
||
if _, exists := oldTuples[id]; !exists {
|
||
return false
|
||
}
|
||
|
||
// Создаём новую карту без удаляемого кортежа
|
||
newTuples := make(map[string]*Tuple)
|
||
for k, v := range oldTuples {
|
||
if k != id {
|
||
newTuples[k] = v
|
||
}
|
||
}
|
||
|
||
// Пытаемся атомарно обновить
|
||
if atomic.CompareAndSwapPointer(&s.tuples, oldPtr, unsafe.Pointer(&newTuples)) {
|
||
s.UpdatedAt = time.Now()
|
||
return true
|
||
}
|
||
}
|
||
}
|
||
|
||
// Tuple представляет кортеж (запись)
|
||
type Tuple struct {
|
||
ID string
|
||
Fields map[string]interface{}
|
||
CreatedAt time.Time
|
||
UpdatedAt time.Time
|
||
}
|
||
|
||
// NewTuple создаёт новый кортеж
|
||
func NewTuple(id string) *Tuple {
|
||
return &Tuple{
|
||
ID: id,
|
||
Fields: make(map[string]interface{}),
|
||
CreatedAt: time.Now(),
|
||
UpdatedAt: time.Now(),
|
||
}
|
||
}
|