diff --git a/internal/storage/engine.go b/internal/storage/engine.go deleted file mode 100644 index 164b1a2..0000000 --- a/internal/storage/engine.go +++ /dev/null @@ -1,319 +0,0 @@ -/* - * Copyright 2026 Safronov Grigorii - * - * Licensed under the CDDL, Version 1.0 (the "License"); - * you may not use this file except in compliance with the License. - * - * You may obtain a copy of the License at - * https://opensource.org/licenses/CDDL-1.0 - */ - -// Файл: internal/storage/engine.go -// Назначение: In-memory движок хранения документов с поддержкой коллекций, -// слайсов (аналог БД), тапплов (аналог таблиц), полей и кортежей. -// Полностью wait-free с использованием sync.Map и атомарных операций. - -package storage - -import ( - "fmt" - "sync" - "sync/atomic" - - "futriis/internal/log" - "futriis/internal/serializer" -) - -// Storage представляет основное хранилище баз данных -type Storage struct { - databases sync.Map // map[string]*Database - pageSize int64 - logger *log.Logger - totalDocs atomic.Int64 -} - -// Database представляет базу данных (аналог слайса в реляционных СУБД) -type Database struct { - name string - collections sync.Map // map[string]*Collection -} - -// NewStorage создаёт новый экземпляр хранилища -func NewStorage(pageSizeMB int, logger *log.Logger) *Storage { - return &Storage{ - pageSize: int64(pageSizeMB) * 1024 * 1024, - logger: logger, - } -} - -// CreateDatabase создаёт новую базу данных -func (s *Storage) CreateDatabase(name string) error { - if _, exists := s.databases.LoadOrStore(name, &Database{name: name}); exists { - return fmt.Errorf("database already exists") - } - AuditDatabaseOperation("CREATE", name) - s.logger.Info("Database created: " + name) - return nil -} - -// GetDatabase возвращает базу данных по имени -func (s *Storage) GetDatabase(name string) (*Database, error) { - if val, ok := s.databases.Load(name); ok { - return val.(*Database), nil - } - return nil, fmt.Errorf("database not found") -} - -// DropDatabase удаляет базу данных -func (s *Storage) DropDatabase(name string) error { - if _, ok := s.databases.LoadAndDelete(name); !ok { - return fmt.Errorf("database not found") - } - AuditDatabaseOperation("DROP", name) - s.logger.Info("Database dropped: " + name) - return nil -} - -// ListDatabases возвращает список всех баз данных -func (s *Storage) ListDatabases() []string { - databases := make([]string, 0) - s.databases.Range(func(key, value interface{}) bool { - databases = append(databases, key.(string)) - return true - }) - return databases -} - -// Name возвращает имя базы данных -func (db *Database) Name() string { - return db.name -} - -// CreateCollection создаёт новую коллекцию в базе данных -func (db *Database) CreateCollection(name string) error { - // Исправлено: добавлен параметр dbName - if _, exists := db.collections.LoadOrStore(name, NewCollection(db.name, name, nil)); exists { - return fmt.Errorf("collection already exists") - } - AuditCollectionOperation("CREATE", db.name, name, nil) - return nil -} - -// CreateCollectionWithSettings создаёт коллекцию с настройками -func (db *Database) CreateCollectionWithSettings(name string, settings *CollectionSettings) error { - // Исправлено: добавлен параметр dbName - if _, exists := db.collections.LoadOrStore(name, NewCollection(db.name, name, settings)); exists { - return fmt.Errorf("collection already exists") - } - AuditCollectionOperation("CREATE", db.name, name, settings) - return nil -} - -// GetCollection возвращает коллекцию по имени -func (db *Database) GetCollection(name string) (*Collection, error) { - if val, ok := db.collections.Load(name); ok { - return val.(*Collection), nil - } - return nil, fmt.Errorf("collection not found") -} - -// DropCollection удаляет коллекцию -func (db *Database) DropCollection(name string) error { - if _, ok := db.collections.LoadAndDelete(name); !ok { - return fmt.Errorf("collection not found") - } - AuditCollectionOperation("DROP", db.name, name, nil) - return nil -} - -// ListCollections возвращает список всех коллекций в базе данных -func (db *Database) ListCollections() []string { - collections := make([]string, 0) - db.collections.Range(func(key, value interface{}) bool { - collections = append(collections, key.(string)) - return true - }) - return collections -} - -// GetTotalDocuments возвращает общее количество документов во всех коллекциях -func (s *Storage) GetTotalDocuments() int64 { - return s.totalDocs.Load() -} - -// GetPageSize возвращает размер страницы памяти -func (s *Storage) GetPageSize() int64 { - return s.pageSize -} - -// SerializeDatabase сериализует всю базу данных в MessagePack -func (db *Database) SerializeDatabase() ([]byte, error) { - dbData := make(map[string]interface{}) - - db.collections.Range(func(key, value interface{}) bool { - coll := value.(*Collection) - collData := make(map[string]interface{}) - - // Собираем все документы коллекции - docs := coll.GetAllDocuments() - collDocs := make([]*Document, 0, len(docs)) - for _, doc := range docs { - collDocs = append(collDocs, doc) - } - collData["documents"] = collDocs - collData["metadata"] = coll.GetMetadata() - - dbData[key.(string)] = collData - return true - }) - - return serializer.Marshal(dbData) -} - -// DeserializeDatabase десериализует базу данных из MessagePack -func (db *Database) DeserializeDatabase(data []byte) error { - var dbData map[string]interface{} - if err := serializer.Unmarshal(data, &dbData); err != nil { - return err - } - - for collName, collDataRaw := range dbData { - collData, ok := collDataRaw.(map[string]interface{}) - if !ok { - continue - } - - // Создаём коллекцию - settings := &CollectionSettings{ - MaxDocuments: 0, - ValidateSchema: false, - AutoIndexID: true, - TTLSeconds: 0, - } - - if metaRaw, ok := collData["metadata"]; ok { - // Пробуем разные варианты десериализации метаданных - if meta, ok := metaRaw.(map[string]interface{}); ok { - if settingsRaw, ok := meta["settings"]; ok { - if settingsMap, ok := settingsRaw.(map[string]interface{}); ok { - if maxDocs, ok := settingsMap["max_documents"]; ok { - if v, ok := maxDocs.(int); ok { - settings.MaxDocuments = v - } else if v, ok := maxDocs.(int64); ok { - settings.MaxDocuments = int(v) - } else if v, ok := maxDocs.(float64); ok { - settings.MaxDocuments = int(v) - } - } - if validateSchema, ok := settingsMap["validate_schema"]; ok { - if v, ok := validateSchema.(bool); ok { - settings.ValidateSchema = v - } - } - if autoIndexID, ok := settingsMap["auto_index_id"]; ok { - if v, ok := autoIndexID.(bool); ok { - settings.AutoIndexID = v - } - } - if ttlSeconds, ok := settingsMap["ttl_seconds"]; ok { - if v, ok := ttlSeconds.(int); ok { - settings.TTLSeconds = v - } else if v, ok := ttlSeconds.(int64); ok { - settings.TTLSeconds = int(v) - } else if v, ok := ttlSeconds.(float64); ok { - settings.TTLSeconds = int(v) - } - } - } - } - } else if meta, ok := metaRaw.(*CollectionMetadata); ok { - if meta.Settings != nil { - settings = meta.Settings - } - } - } - - // Исправлено: добавлен параметр dbName - coll := NewCollection(db.name, collName, settings) - - // Восстанавливаем документы - if docsRaw, ok := collData["documents"]; ok { - if docs, ok := docsRaw.([]interface{}); ok { - for _, docRaw := range docs { - if doc, ok := docRaw.(*Document); ok { - coll.Insert(doc) - } else if docMap, ok := docRaw.(map[string]interface{}); ok { - // Создаём документ из map - doc := NewDocument() - if id, ok := docMap["ID"].(string); ok { - doc.ID = id - } else if id, ok := docMap["id"].(string); ok { - doc.ID = id - } - if fields, ok := docMap["fields"]; ok { - if fieldsMap, ok := fields.(map[string]interface{}); ok { - for k, v := range fieldsMap { - doc.SetField(k, v) - } - } - } - if createdAt, ok := docMap["created_at"]; ok { - if v, ok := createdAt.(int64); ok { - doc.CreatedAt = v - } else if v, ok := createdAt.(float64); ok { - doc.CreatedAt = int64(v) - } - } - if updatedAt, ok := docMap["updated_at"]; ok { - if v, ok := updatedAt.(int64); ok { - doc.UpdatedAt = v - } else if v, ok := updatedAt.(float64); ok { - doc.UpdatedAt = int64(v) - } - } - if version, ok := docMap["version"]; ok { - if v, ok := version.(uint64); ok { - doc.Version = v - } else if v, ok := version.(int64); ok { - doc.Version = uint64(v) - } else if v, ok := version.(float64); ok { - doc.Version = uint64(v) - } - } - coll.Insert(doc) - } - } - } else if docs, ok := docsRaw.([]*Document); ok { - for _, doc := range docs { - coll.Insert(doc) - } - } - } - - db.collections.Store(collName, coll) - AuditCollectionOperation("RESTORE", db.name, collName, settings) - } - - return nil -} - -// GetDatabaseNames возвращает имена всех баз данных -func (s *Storage) GetDatabaseNames() []string { - return s.ListDatabases() -} - -// ExistsDatabase проверяет существование базы данных -func (s *Storage) ExistsDatabase(name string) bool { - _, ok := s.databases.Load(name) - return ok -} - -// GetDatabaseCount возвращает количество баз данных -func (s *Storage) GetDatabaseCount() int { - count := 0 - s.databases.Range(func(key, value interface{}) bool { - count++ - return true - }) - return count -}