norian: (Default)
[personal profile] norian
Гибридная Графовая База Данных (отвертка с моторчиком для моделирования моделей)

День 4. API для работы с узлами, контейнеры, локальные файлы.

Основные операции с данными - добавление новых, изменение и удаление. Также данные сохраняются в локальном или удалённом хранилище и загружаются для использования в приложении. Практически всё то же самое, что и в табличных базах данных. Плюс поддержка сериализации объектов (на примере с++).

Для операций со всеми узлами данных/графа используется c++ класс EgDataNodesType.

Чтобы добавить гибкости использования, имя типа-класса-блюпринта устанавливается не при создании объекта, а функцией Connect(). Поскольку все типы-классы-блюпринты узлов должны регистрироваться в метаданных, сюда вставлена заглушка класса функциональности центральной базы.

source egDataNodesType.h

#pragma once
#include "egDataNodesContainer.h"

typedef void (*serialLoadFunctionType)  (EgDataNode& dataNode);
typedef void (*serialStoreFunctionType) (EgDataNode& dataNode);

class EgLinksType;      // arrow links
class EgDatabaseType;   // peer database 

class EgDataNodesType { // "type" means c++ type, data metatype called "blueprint"
public:
    bool                        isConnected         {  false  };    // checked blueprint file and central egDb metadata
    bool                        isDataLoaded        {  false  };
    bool                        isDataUpdated       {  false  };

    std::string                 dataNodesName;
    EgDatabaseType*             metaInfoDatabase    { nullptr };    // nodes and links layout == blueprint == class == type info
    EgDataNodeBlueprintType*    dataNodeBlueprint   { nullptr };    // layout == blueprint == class == type of these data nodes
    EgDataNodesContainerType*   nodesContainer      { nullptr };    // data storage of all these nodes
    EgDataNodesMapType&         dataMap;                            // shortcut to container nodes map,  for (auto iter : dataMap)

    serialLoadFunctionType      serialLoadFunction  { nullptr };    // function for automated data load from node to void* localDataPtr
    serialStoreFunctionType     serialStoreFunction { nullptr };    // function for automated data store to node form void* localDataPtr

    EgDataNodesType();
    ~EgDataNodesType() { clear(); delete dataNodeBlueprint; delete nodesContainer; }

    void clear();
    int  ConnectSystemNodeType(std::string a_dataNodesName); // for local testing or internal database storages
    int  OpenLocalBlueprint();    

    int  Connect(const std::string& nodesNameStr, EgDatabaseType& myDB);

    int  AddDataNode(EgDataNode* newNode);
    int  AddDataNode(EgDataNode& newNode) { return AddDataNode(&newNode); }

    EgDataNodesType& operator << (EgDataNode* newNode) { AddDataNode(newNode); return *this; }
    EgDataNodesType& operator << (EgDataNode& newNode) { AddDataNode(newNode); return *this; }
    EgDataNodeIDType getAddedNodeID() { return nodesContainer->lastNodeID; }

    int  MarkUpdatedDataNode(EgDataNodeIDType nodeID);
    int  MarkUpdatedDataNode(EgDataNode& updNode) { return MarkUpdatedDataNode(updNode.dataNodeID); }
    void DeleteDataNode(EgDataNodeIDType delID);
    void DeleteDataNode(EgDataNode& delNode) { return DeleteDataNode(delNode.dataNodeID); }

    int  Store();
    int  LoadAllNodes();
    bool LoadNodesEQ(const std::string& indexName, EgByteArrayAbstractType& fieldValue);

    // Projects.LoadIndexedNodes(IC<int>("owner", EQ, 2) &&  IC<int>("status", EQ, 3));
    // int  LoadNodesByOffsets() { return nodesContainer-> LoadLocalNodesByOffsets(indexOffsets); }
    
    EgDataNode& operator[](EgDataNodeIDType nodeID);
};



Каждый отдельный узел представляет класс EgDataNode, в котором для хранения данных узла служит EgPtrArrayType<EgByteArrayAbstractType*>*, объединяющий вышеупомянутые вспомогательные классы c++.

Чтобы динамически связывать узлы данных после загрузки линков, добавлены структуры in/outLinks и функции для работы с ними.

При апдейте индексов могут потребоваться данные до их изменения, они сохраняются в indexedFieldsOldValues.

Для удобства использования некоторые функции сделаны в виде операторов ( [], <<, >> ).

source egDataNode.h

#pragma once

#include "egDataNodeBlueprint.h"
#include "../service/egPtrArray.h"

class EgDataNode {
public:
    EgDataNodeIDType         dataNodeID         { 0 };
    EgFileOffsetType         dataFileOffset     { 0 };          // stored offset for local file operations speedup
    EgDataNodeBlueprintType* dataNodeBlueprint  { nullptr };    // blueprint == class == type of data nodes
    void*                    serialDataPtr      { nullptr };    // link to ext data for serialization

    EgPtrArrayType<EgByteArrayAbstractType*>* dataFieldsPtrs;
    int insertIndex {0}; // stored index for AddNextDataFieldFromType() FIXME check reset

    std::unordered_map < std::string, EgByteArraySlicerType* >  indexedFieldsOldValues; // store old value for index update

    std::unordered_map < EgBlueprintIDType, EgLinkDataPtrsNodePtrsMapType >  inLinks;   // links IDs resolving to ptrs
    std::unordered_map < EgBlueprintIDType, EgLinkDataPtrsNodePtrsMapType >  outLinks;    

    EgDataNode() = delete; // {} // for debug only

    EgDataNode(EgDataNodeBlueprintType* a_dataNodeBlueprint, bool initMe = true);
    EgDataNode(EgDataNodeBlueprintType* a_dataNodeBlueprint, void* a_serialDataPtr);
    ~EgDataNode() { /*std::cout << "EgDataNodeType destructor, ID = " << dataNodeID << std::endl; clear(); */ }

    void clear();
    void init();

    EgLinkDataPtrsNodePtrsMapType* getInLinksMap(EgBlueprintIDType linkBlueprintID);
    EgLinkDataPtrsNodePtrsMapType* getOutLinksMap(EgBlueprintIDType linkBlueprintID);

    void* getNextInLinkSerialPtr (EgBlueprintIDType linkBlueprintID, EgDataNode* prevLinkDataPtr); // link data, not linked node
    void* getNextOutLinkSerialPtr(EgBlueprintIDType linkBlueprintID, EgDataNode* prevLinkDataPtr);

    void deleteInLink (EgBlueprintIDType linkBlueprintID, EgDataNode* delLinkNodePtr); // link data, not linked node
    void deleteOutLink(EgBlueprintIDType linkBlueprintID, EgDataNode* delLinkNodePtr);

    EgDataNode* getInLinkedNode(EgBlueprintIDType linkBlueprintID, EgDataNode* linkNodePtr); // node, not link
    EgDataNode* getOutLinkedNode(EgBlueprintIDType linkBlueprintID, EgDataNode* linkNodePtr);     

    // EgDataNodeType* getNextInLinkedNode(EgBlueprintIDType linkBlueprintID, EgDataNodeType* prevLinkDataPtr); // node, not link
    // EgDataNodeType* getNextOutLinkedNode(EgBlueprintIDType linkBlueprintID, EgDataNodeType* prevLinkDataPtr);     

    void InsertDataFieldFromCharStr(const char* str);
    void InsertDataFieldFromByteArray(EgByteArrayAbstractType& ba);
    void InsertRawByteArrayPtr(EgByteArraySlicerType* baPtr);

    EgByteArrayAbstractType& operator[](const std::string& fieldStrName);  // field data by name

    EgDataNode& operator << (const char* str) { InsertDataFieldFromCharStr(str); return *this; }
    EgDataNode& operator << (std::string& s)  { InsertDataFieldFromCharStr(s.c_str()); return *this; }
    EgDataNode& operator << (const std::string& s)  { InsertDataFieldFromCharStr(s.c_str()); return *this; }
    EgDataNode& operator << (EgByteArrayAbstractType& ba) { InsertDataFieldFromByteArray(ba); return *this; }

    template <typename T> EgDataNode& operator << (const T& value) {
        if (insertIndex < dataNodeBlueprint->fieldsCount) {
            EgByteArraySlicerType *byteArray = new EgByteArraySlicerType(dataNodeBlueprint->theHamSlicer, sizeof(value)); // use ham slicer allocator
            memcpy((void *)byteArray-> dataChunk, (void *)&value, sizeof(value));
            dataFieldsPtrs->ptrsArray[insertIndex++] = byteArray;
        } else
            std::cout << "ERROR: AddNextDataFieldFromType() fields count overflow: " << dataNodeBlueprint-> blueprintName << std::endl;
        return *this;
    }

    void makeIndexedFieldsCopy(); // store old value for index update

    void writeDataFieldsToFile (EgFileType& theFile);  // EgDataFieldsType& df,  local file operations
    void readDataFieldsFromFile(EgFileType& theFile);
};

// ========= Byte Array Length Convertors  ===============
uint8_t egConvertStaticToFlex(StaticLengthType staticVal, ByteType* flexibleVal); // convert fixed length dataset size to variable length
uint8_t egConvertFlexToStatic(ByteType* flexibleVal, StaticLengthType& staticVal); // reverse convert variable length dataset size to fixed length

// ======================== Debug ========================
// void PrintEgDataNodeOffsets(const EgDataNodeType& dataNode);
void PrintEgDataNodeFields (const EgDataNode& dataNode);



Поскольку в egDataNodesType много функциональности, часть внутреннего кода лучше перенести в другие классы. Так данные узлов хранятся в контейнерах класса EgDataNodesContainerType, который в свою очередь использует EgDataNodesLocalFileType для файловых операций.

source egDataNodesContainer.h

#pragma once
#include "egDataNodesLocalFile.h"

class EgDataNodesContainerType {
public:
    EgDataNodeIDType    nodesCount  {0};
    EgDataNodeIDType    lastNodeID  {0}; 
    EgDataNodeBlueprintType*    dataNodeBlueprint   { nullptr };    // blueprint == class == type of data nodes
    EgDataNodesLocalFileType*   LocalNodesFile      { nullptr };    // data files *.gdn load/store support
        // data nodes content and changes tracking
    EgDataNodesMapType dataNodes;        // active nodes container
    EgDataNodesOrdMapType addedDataNodes;
    EgDataNodesMapType updatedDataNodes;
    EgDataNodesMapType deletedDataNodes; // TODO : clear all addons on node delete

    EgDataNodesContainerType():
            LocalNodesFile (new EgDataNodesLocalFileType()) {}
    void init(EgDataNodeBlueprintType* a_dataNodeBlueprint); // get blueprint from upper layer TODO init indexes by blueprint
    ~EgDataNodesContainerType() { clear(); /* delete dataNodeBlueprint;*/ delete LocalNodesFile; } // FIXME check dynamic blueprint

    void clear();
    int  GetLastID();
    int  LoadLocalBlueprint();
    EgDataNode* GetNodePtrByID(EgDataNodeIDType nodeID);

    int  AddDataNode(EgDataNode* newNode);
    int  MarkUpdatedDataNode(EgDataNodeIDType nodeID);
    void DeleteDataNode(const EgDataNodeIDType delID);

    EgDataNodesContainerType& operator << (EgDataNode* newNode);

    int  StoreToLocalFile();
    int  LoadAllLocalFileNodes();

    bool LoadLocalNodesEQ(const std::string& indexName, EgByteArrayAbstractType& fieldValue);

    int  LoadLocalNodesByOffsets(std::set<EgFileOffsetType>& index_offsets);
        // ======================== Debug ========================
    void PrintDataNodesContainer();
    void PrintNodesChain();
};

Profile

norian: (Default)
Norian

January 2026

S M T W T F S
    1 2 3
456 78 910
11121314 151617
18 19 20 21 222324
25262728293031

Most Popular Tags

Style Credit

Expand Cut Tags

No cut tags
Page generated Jan. 23rd, 2026 04:11 am
Powered by Dreamwidth Studios