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(),
|
|||
|
|
}
|
|||
|
|
}
|