diff options
Diffstat (limited to '')
| -rw-r--r-- | include/CursorManager.h | 24 | ||||
| -rw-r--r-- | include/HandlerManager.h | 18 | ||||
| -rw-r--r-- | include/IStorageBackend.h | 10 | ||||
| -rw-r--r-- | include/IdentityManager.h | 10 | ||||
| -rw-r--r-- | include/InMemoryBackend.h | 12 | ||||
| -rw-r--r-- | include/LifecycleManager.h | 14 | ||||
| -rw-r--r-- | include/Merkle.h | 259 | ||||
| -rw-r--r-- | include/MultigroupCodec.h | 23 | ||||
| -rw-r--r-- | include/NT.h | 12 | ||||
| -rw-r--r-- | include/NamespaceReferenceManager.h | 17 | ||||
| -rw-r--r-- | include/ObjectManager.h | 38 | ||||
| -rw-r--r-- | include/PermissionsManager.h | 23 | ||||
| -rw-r--r-- | include/RNT_C_API.h | 82 | ||||
| -rw-r--r-- | include/Runtime.h | 10 | ||||
| -rw-r--r-- | include/SqliteBackend.h | 12 | ||||
| -rw-r--r-- | include/TupleCodec.h | 5 | ||||
| -rw-r--r-- | include/Types.h | 21 | ||||
| -rw-r--r-- | include/VM.h | 49 |
18 files changed, 313 insertions, 326 deletions
diff --git a/include/CursorManager.h b/include/CursorManager.h index 2743516..a4c82d7 100644 --- a/include/CursorManager.h +++ b/include/CursorManager.h @@ -16,8 +16,7 @@ * @brief Declares paging and cursor orchestration for query execution. */ -namespace nt -{ +namespace nt { /** * @class CursorManager * @brief Orchestrates paginated data retrieval from a storage backend. @@ -34,9 +33,8 @@ namespace nt * Merkle::Page(backend, merkle_root, fetch_offset, PAGE_SIZE) to retrieve * the next page of tuple hashes without loading sibling subtrees. */ - class CursorManager - { - public: + class CursorManager { + public: static constexpr std::size_t PAGE_SIZE = 1; /** @@ -49,8 +47,7 @@ namespace nt * resolved snapshot for the handle's relation and Pins it for the * cursor's lifetime, releasing the pin in Close. */ - explicit CursorManager(IStorageBackend& backend, - LifecycleManager* lifecycles = nullptr, + explicit CursorManager(IStorageBackend& backend, LifecycleManager* lifecycles = nullptr, ObjectManager* objects = nullptr); /** @@ -88,7 +85,7 @@ namespace nt std::vector<std::string> args; std::vector<Tuple> page; std::size_t page_position = 0; - std::size_t fetch_offset = 0; // next Merkle::Page() call starts here + std::size_t fetch_offset = 0; // next Merkle::Page() call starts here bool exhausted = false; /** * True for EPHEMERAL_RELATION cursors; selects the generator-driven @@ -124,8 +121,7 @@ namespace nt * @param merkle_root Hex hash of the relation's Merkle root at open * time. Ignored for EPHEMERAL_RELATION handles. */ - cursor* Open(HandlerManager::handle* handle, - const std::string& merkle_root = ""); + cursor* Open(HandlerManager::handle* handle, const std::string& merkle_root = ""); /** * @brief Pulls the next tuple from the cursor. @@ -141,10 +137,10 @@ namespace nt */ void Close(cursor* cursor); - private: - IStorageBackend& backend_; + private: + IStorageBackend& backend_; LifecycleManager* lifecycles_ = nullptr; - ObjectManager* objects_ = nullptr; + ObjectManager* objects_ = nullptr; /** * Fetches a page of hashes via Merkle::Page, resolves each from the @@ -154,4 +150,4 @@ namespace nt */ void LoadPage(cursor* c); }; -} +} // namespace nt diff --git a/include/HandlerManager.h b/include/HandlerManager.h index a9ce09d..b2beb5f 100644 --- a/include/HandlerManager.h +++ b/include/HandlerManager.h @@ -13,17 +13,15 @@ * @brief Declares handle allocation and release for authorized object access. */ -namespace nt -{ +namespace nt { class IdentityManager; class LifecycleManager; class NamespaceReferenceManager; class PermissionsManager; /** @brief Opens and closes authorized handles to registry objects. */ - class HandlerManager - { - public: + class HandlerManager { + public: /** * @brief Constructs a HandlerManager with shared runtime dependencies. * @@ -31,10 +29,8 @@ namespace nt * counters, permission policy) persists across calls rather than being * rebuilt per open/close. */ - HandlerManager(ObjectManager& objects, - PermissionsManager& permissions, - IdentityManager& identities, - LifecycleManager& lifecycles, + HandlerManager(ObjectManager& objects, PermissionsManager& permissions, + IdentityManager& identities, LifecycleManager& lifecycles, NamespaceReferenceManager& references); /** @@ -90,11 +86,11 @@ namespace nt */ bool Close(struct handle* handle); - private: + private: ObjectManager& objects_; PermissionsManager& permissions_; IdentityManager& identities_; LifecycleManager& lifecycles_; NamespaceReferenceManager& references_; }; -} +} // namespace nt diff --git a/include/IStorageBackend.h b/include/IStorageBackend.h index e408c95..a7cc782 100644 --- a/include/IStorageBackend.h +++ b/include/IStorageBackend.h @@ -15,8 +15,7 @@ * Merkle class, not by this interface. Only Put and Get are required. */ -namespace nt -{ +namespace nt { /** * @interface IStorageBackend * @brief Contract between CursorManager / Merkle and a physical storage engine. @@ -29,9 +28,8 @@ namespace nt * maintains insertion-order-independent relation membership on top of these * two primitives. */ - class IStorageBackend - { - public: + class IStorageBackend { + public: virtual ~IStorageBackend() = default; /** @@ -48,4 +46,4 @@ namespace nt */ virtual std::optional<std::vector<uint8_t>> Get(const std::string& hash) = 0; }; -} +} // namespace nt diff --git a/include/IdentityManager.h b/include/IdentityManager.h index 6b487a9..1dd75da 100644 --- a/include/IdentityManager.h +++ b/include/IdentityManager.h @@ -8,8 +8,7 @@ * @brief Declares object capability checks. */ -namespace nt -{ +namespace nt { /** * @brief Checks whether an object supports identity-level operations. * @@ -21,9 +20,8 @@ namespace nt * so that error logs identify the type without dereferencing the pointer. * See docs/reactos-ob-comparison.md §2. */ - class IdentityManager - { - public: + class IdentityManager { + public: /** * @brief Returns true when the object's type supports being opened. * @@ -46,4 +44,4 @@ namespace nt */ const bool CanClose(ObjectManager::registry* object); }; -} +} // namespace nt diff --git a/include/InMemoryBackend.h b/include/InMemoryBackend.h index 1a7d3a7..b66d355 100644 --- a/include/InMemoryBackend.h +++ b/include/InMemoryBackend.h @@ -19,15 +19,13 @@ * Relation membership is tracked by the Merkle class, not this backend. */ -namespace nt -{ - class InMemoryBackend : public IStorageBackend - { - public: +namespace nt { + class InMemoryBackend : public IStorageBackend { + public: std::string Put(std::vector<uint8_t> value) override; std::optional<std::vector<uint8_t>> Get(const std::string& hash) override; - private: + private: std::unordered_map<std::string, std::vector<uint8_t>> kv_; }; -} +} // namespace nt diff --git a/include/LifecycleManager.h b/include/LifecycleManager.h index e053cd2..c1e63d8 100644 --- a/include/LifecycleManager.h +++ b/include/LifecycleManager.h @@ -9,8 +9,7 @@ * @brief Declares monitoring, pinning, cleanup, and contention operations. */ -namespace nt -{ +namespace nt { /** * @brief Manages runtime lifecycle concerns for registry objects. * @@ -23,9 +22,8 @@ namespace nt * Monitor / Unmonitor manage `handle_count`. Pin / Unpin manage * `reference_count`. See docs/reactos-ob-comparison.md §1. */ - class LifecycleManager - { - public: + class LifecycleManager { + public: /** * @brief Constructs a LifecycleManager bound to a registry and store. * @@ -120,7 +118,7 @@ namespace nt */ const bool Contention(ObjectManager::registry* object); - private: + private: /** * @brief Joint-counters check + type-specific cascade + Unregister. * @@ -158,7 +156,7 @@ namespace nt */ void CascadeBranchTree(ObjectManager::registry* branch_tree); - ObjectManager& objects_; + ObjectManager& objects_; IStorageBackend& storage_; }; -} +} // namespace nt diff --git a/include/Merkle.h b/include/Merkle.h index ba8018a..6256ddc 100644 --- a/include/Merkle.h +++ b/include/Merkle.h @@ -58,143 +58,128 @@ namespace nt { -/** @brief 32-byte hash, the universal payload type for all merkle levels. */ -using Hash32 = std::array<uint8_t, 32>; - -/** @brief Decode a 64-character lowercase-hex SHA256 string into raw bytes. - * Throws std::invalid_argument when the string is not exactly 64 hex chars. */ -Hash32 hex_to_bin(const std::string& hex); - -/** @brief Encode raw 32 bytes back into a 64-character lowercase-hex string. */ -std::string bin_to_hex(const Hash32& bin); - -template<typename Key> -class Merkle { -public: - static constexpr size_t B = 64; - - /** - * @brief Insert or overwrite a `(key, payload)` mapping. - * @param store KV backend for node serialisation. - * @param root_hex Current root hash (empty string = empty tree). - * @param key Routing/identity key. - * @param payload Hash this key maps to (child root one level down, or - * the key itself at the relation level). - * @return New root hash. Equal to root_hex when an insertion of an - * identical (key, payload) pair would be a no-op. - */ - static std::string Insert(IStorageBackend& store, - const std::string& root_hex, - const Key& key, - const Hash32& payload); - - /** - * @brief Remove a key from the tree. - * @return New root hash. Empty string when the tree becomes empty. - * Equal to root_hex when the key is absent. - */ - static std::string Remove(IStorageBackend& store, - const std::string& root_hex, - const Key& key); - - /** - * @brief Look up the payload for a key. - * @return The payload when present, std::nullopt when absent. - */ - static std::optional<Hash32> Get(IStorageBackend& store, - const std::string& root_hex, - const Key& key); - - /** @brief One (key, payload) pair returned by Page(). */ - struct Entry { - Key key; - Hash32 payload; + /** @brief 32-byte hash, the universal payload type for all merkle levels. */ + using Hash32 = std::array<uint8_t, 32>; + + /** @brief Decode a 64-character lowercase-hex SHA256 string into raw bytes. + * Throws std::invalid_argument when the string is not exactly 64 hex chars. */ + Hash32 hex_to_bin(const std::string& hex); + + /** @brief Encode raw 32 bytes back into a 64-character lowercase-hex string. */ + std::string bin_to_hex(const Hash32& bin); + + template <typename Key> class Merkle { + public: + static constexpr size_t B = 64; + + /** + * @brief Insert or overwrite a `(key, payload)` mapping. + * @param store KV backend for node serialisation. + * @param root_hex Current root hash (empty string = empty tree). + * @param key Routing/identity key. + * @param payload Hash this key maps to (child root one level down, or + * the key itself at the relation level). + * @return New root hash. Equal to root_hex when an insertion of an + * identical (key, payload) pair would be a no-op. + */ + static std::string Insert(IStorageBackend& store, const std::string& root_hex, + const Key& key, const Hash32& payload); + + /** + * @brief Remove a key from the tree. + * @return New root hash. Empty string when the tree becomes empty. + * Equal to root_hex when the key is absent. + */ + static std::string Remove(IStorageBackend& store, const std::string& root_hex, + const Key& key); + + /** + * @brief Look up the payload for a key. + * @return The payload when present, std::nullopt when absent. + */ + static std::optional<Hash32> Get(IStorageBackend& store, const std::string& root_hex, + const Key& key); + + /** @brief One (key, payload) pair returned by Page(). */ + struct Entry { + Key key; + Hash32 payload; + }; + + /** + * @brief Page through entries in key-sorted order. + * + * Descends to the leaf at logical position @p offset using cumulative + * leaf_counts stored in internal nodes, then walks forward collecting at + * most @p limit entries. Only the nodes on the active path are loaded; + * sibling subtrees are never touched. + */ + static std::vector<Entry> Page(IStorageBackend& store, const std::string& root_hex, + size_t offset, size_t limit); + + private: + struct LeafEntry { + Key key; + Hash32 payload; + }; + + struct LeafNode { + std::vector<LeafEntry> entries; + }; + + struct ChildEntry { + uint64_t leaf_count; + Key min_key; + Hash32 child_hash; + }; + + struct InternalNode { + std::vector<ChildEntry> entries; + }; + + // Wire format + static std::vector<uint8_t> encode_leaf(const LeafNode& n); + static std::vector<uint8_t> encode_internal(const InternalNode& n); + static LeafNode decode_leaf(const std::vector<uint8_t>& bytes); + static InternalNode decode_internal(const std::vector<uint8_t>& bytes); + static bool is_leaf_bytes(const std::vector<uint8_t>& bytes); + + // Storage helpers + static std::vector<uint8_t> load_node(IStorageBackend& store, const std::string& hash_hex); + static std::string store_leaf(IStorageBackend& store, const LeafNode& n); + static std::string store_internal(IStorageBackend& store, const InternalNode& n); + + /** @brief Returns the smallest key in the subtree rooted at @p node_hex. */ + static Key subtree_min_key(IStorageBackend& store, const std::string& node_hex); + + /** @brief Routes a key to the rightmost child whose min_key ≤ target. */ + static size_t route(const InternalNode& node, const Key& target); + + struct InsertResult { + std::string new_hash; + uint64_t leaf_count = 0; + bool did_split = false; + uint64_t split_leaf_count = 0; + Key split_min_key{}; + std::string split_hash; + }; + + static InsertResult insert_into(IStorageBackend& store, const std::string& node_hex, + const Key& key, const Hash32& payload); + + struct RemoveResult { + std::string new_hash; + uint64_t leaf_count = 0; + }; + + static RemoveResult remove_from(IStorageBackend& store, const std::string& node_hex, + const Key& key); + + static void page_from(IStorageBackend& store, const std::string& node_hex, size_t& offset, + size_t limit, std::vector<Entry>& out); + + static std::optional<Hash32> get_from(IStorageBackend& store, const std::string& node_hex, + const Key& key); }; - /** - * @brief Page through entries in key-sorted order. - * - * Descends to the leaf at logical position @p offset using cumulative - * leaf_counts stored in internal nodes, then walks forward collecting at - * most @p limit entries. Only the nodes on the active path are loaded; - * sibling subtrees are never touched. - */ - static std::vector<Entry> Page(IStorageBackend& store, - const std::string& root_hex, - size_t offset, - size_t limit); - -private: - struct LeafEntry { - Key key; - Hash32 payload; - }; - - struct LeafNode { - std::vector<LeafEntry> entries; - }; - - struct ChildEntry { - uint64_t leaf_count; - Key min_key; - Hash32 child_hash; - }; - - struct InternalNode { - std::vector<ChildEntry> entries; - }; - - // Wire format - static std::vector<uint8_t> encode_leaf(const LeafNode& n); - static std::vector<uint8_t> encode_internal(const InternalNode& n); - static LeafNode decode_leaf(const std::vector<uint8_t>& bytes); - static InternalNode decode_internal(const std::vector<uint8_t>& bytes); - static bool is_leaf_bytes(const std::vector<uint8_t>& bytes); - - // Storage helpers - static std::vector<uint8_t> load_node(IStorageBackend& store, - const std::string& hash_hex); - static std::string store_leaf(IStorageBackend& store, const LeafNode& n); - static std::string store_internal(IStorageBackend& store, const InternalNode& n); - - /** @brief Returns the smallest key in the subtree rooted at @p node_hex. */ - static Key subtree_min_key(IStorageBackend& store, const std::string& node_hex); - - /** @brief Routes a key to the rightmost child whose min_key ≤ target. */ - static size_t route(const InternalNode& node, const Key& target); - - struct InsertResult { - std::string new_hash; - uint64_t leaf_count = 0; - bool did_split = false; - uint64_t split_leaf_count = 0; - Key split_min_key{}; - std::string split_hash; - }; - - static InsertResult insert_into(IStorageBackend& store, - const std::string& node_hex, - const Key& key, - const Hash32& payload); - - struct RemoveResult { - std::string new_hash; - uint64_t leaf_count = 0; - }; - - static RemoveResult remove_from(IStorageBackend& store, - const std::string& node_hex, - const Key& key); - - static void page_from(IStorageBackend& store, - const std::string& node_hex, - size_t& offset, - size_t limit, - std::vector<Entry>& out); - - static std::optional<Hash32> get_from(IStorageBackend& store, - const std::string& node_hex, - const Key& key); -}; - } // namespace nt diff --git a/include/MultigroupCodec.h b/include/MultigroupCodec.h index 50f7bb8..9d003ea 100644 --- a/include/MultigroupCodec.h +++ b/include/MultigroupCodec.h @@ -29,8 +29,7 @@ * payloads to `Merkle<std::string>`. */ -namespace nt::MultigroupCodec -{ +namespace nt::MultigroupCodec { /** @brief One entry in a multigroup snapshot: (relation_name, root_hex). */ using RelationEntry = std::pair<std::string, std::string>; @@ -45,8 +44,7 @@ namespace nt::MultigroupCodec * @param relations Entries to load. Duplicates collapse to the last value. * @return Root node hash (empty string when `relations` is empty). */ - std::string Build(IStorageBackend& store, - const std::vector<RelationEntry>& relations); + std::string Build(IStorageBackend& store, const std::vector<RelationEntry>& relations); /** * @brief Enumerate all (name, root_hex) pairs at a multigroup root. @@ -54,8 +52,7 @@ namespace nt::MultigroupCodec * Pages the entire tree (offset 0, no limit). Returned entries are in * key-sorted order. Empty input root yields an empty list. */ - std::vector<RelationEntry> List(IStorageBackend& store, - const std::string& root_hex); + std::vector<RelationEntry> List(IStorageBackend& store, const std::string& root_hex); /** * @brief Insert or overwrite one (relation_name → root_hex) entry. @@ -65,25 +62,21 @@ namespace nt::MultigroupCodec * mutations. Pass an empty `root_hex` for the prior-state argument to * start from an empty tree. */ - std::string InsertOne(IStorageBackend& store, - const std::string& root_hex, - const std::string& relation_name, - const std::string& relation_root_hex); + std::string InsertOne(IStorageBackend& store, const std::string& root_hex, + const std::string& relation_name, const std::string& relation_root_hex); /** * @brief Remove one relation entry from the multigroup tree. * * Returns the new root hash; empty when the tree becomes empty. */ - std::string RemoveOne(IStorageBackend& store, - const std::string& root_hex, + std::string RemoveOne(IStorageBackend& store, const std::string& root_hex, const std::string& relation_name); /** * @brief Look up one relation's root hex by name. * @return Hex root, or empty string when the name is absent. */ - std::string Lookup(IStorageBackend& store, - const std::string& root_hex, + std::string Lookup(IStorageBackend& store, const std::string& root_hex, const std::string& relation_name); -} +} // namespace nt::MultigroupCodec diff --git a/include/NT.h b/include/NT.h index 0fc5514..041c517 100644 --- a/include/NT.h +++ b/include/NT.h @@ -5,13 +5,13 @@ * @brief Includes for the Relational NT public API. */ -#include "Types.h" -#include "ObjectManager.h" -#include "PermissionsManager.h" -#include "NamespaceReferenceManager.h" #include "CursorManager.h" +#include "HandlerManager.h" #include "IdentityManager.h" #include "LifecycleManager.h" -#include "HandlerManager.h" -#include "VM.h" +#include "NamespaceReferenceManager.h" +#include "ObjectManager.h" +#include "PermissionsManager.h" #include "Runtime.h" +#include "Types.h" +#include "VM.h" diff --git a/include/NamespaceReferenceManager.h b/include/NamespaceReferenceManager.h index 3264271..d09f4d4 100644 --- a/include/NamespaceReferenceManager.h +++ b/include/NamespaceReferenceManager.h @@ -12,8 +12,7 @@ * @brief Declares logical reference mapping and namespace isolation. */ -namespace nt -{ +namespace nt { /** * @class NamespaceReferenceManager * @brief Handles the logical mapping and isolation of human-readable references. @@ -67,9 +66,8 @@ namespace nt * @todo Define the batch-update API with all-or-nothing contention semantics. * See docs/reactos-ob-comparison.md §8. */ - class NamespaceReferenceManager - { - public: + class NamespaceReferenceManager { + public: /** * @brief Constructs a NamespaceReferenceManager bound to a registry. * @param objects Registry used to look up reference objects (branches, @@ -78,8 +76,7 @@ namespace nt * nodes when resolving `/system/branches/<n>/<mg>/...` * paths through to their snapshot. */ - NamespaceReferenceManager(ObjectManager& objects, - IStorageBackend& storage); + NamespaceReferenceManager(ObjectManager& objects, IStorageBackend& storage); /** * @brief Rewrites a logical path through reference reparse rules. @@ -103,8 +100,8 @@ namespace nt */ std::vector<std::string> Resolve(std::vector<std::string> path) const; - private: - ObjectManager& objects_; + private: + ObjectManager& objects_; IStorageBackend& storage_; }; -} +} // namespace nt diff --git a/include/ObjectManager.h b/include/ObjectManager.h index 1391508..9ea49e6 100644 --- a/include/ObjectManager.h +++ b/include/ObjectManager.h @@ -16,8 +16,7 @@ * @brief Declares the registry responsible for runtime-managed database objects. */ -namespace nt -{ +namespace nt { /** * @brief Owns the registry used to locate and reference database objects. * @@ -25,12 +24,11 @@ namespace nt * the metadata needed to reason about object type, path, references, and * handles while the concrete storage model is still being designed. */ - class ObjectManager - { - public: + class ObjectManager { + public: /** @brief Base type for objects stored in the registry. */ class IObject { - public: + public: virtual ~IObject() = default; }; @@ -52,7 +50,7 @@ namespace nt * pins it, no pinned cursor still references it). */ class Multigroup : public IObject { - public: + public: std::string merkle_root; }; /** @@ -63,7 +61,7 @@ namespace nt * Updated atomically by rnt_link_tuple / rnt_unlink_tuple / rnt_clear_relation. */ class Relation : public IObject { - public: + public: std::string merkle_root; }; /** @@ -96,8 +94,8 @@ namespace nt * path this remains a documentation-only contract. */ class EphemeralRelation : public IObject { - public: - std::string merkle_root; + public: + std::string merkle_root; std::vector<std::string> dependencies; }; /** @brief Abstract registry object representing a transaction. */ @@ -125,7 +123,7 @@ namespace nt * the walk hot. */ class Session : public IObject { - public: + public: void* connection_context = nullptr; std::map<std::string, std::string> branch_overrides; }; @@ -147,7 +145,7 @@ namespace nt * Multigroups and operate on those. */ class Branch : public IObject { - public: + public: std::string name; std::string target_hash; }; @@ -165,7 +163,7 @@ namespace nt * each multigroup it references before unregistering the entry. */ class BranchTree : public IObject { - public: + public: std::string merkle_root; }; @@ -224,8 +222,7 @@ namespace nt * maps `offset` to the appropriate pair via a bijective enumeration scheme * (e.g. Cantor pairing); callers must bound such scans with a TAKE node. */ - struct ephemeral_object_type : object_type - { + struct ephemeral_object_type : object_type { enum class Cardinality { Finite, ConstrainedFinite, AlephZero, Continuum }; /** @@ -235,12 +232,10 @@ namespace nt * @param limit Maximum number of tuples to return. */ using Generator = std::function<std::vector<Tuple>( - const std::vector<std::string>& args, - std::size_t offset, - std::size_t limit)>; + const std::vector<std::string>& args, std::size_t offset, std::size_t limit)>; Cardinality cardinality; - Generator generator; + Generator generator; }; /** @@ -313,8 +308,7 @@ namespace nt * @param object Object payload. Ownership is transferred to the registry. * @param type Object type descriptor. Ownership is transferred to the registry. */ - void Register(std::vector<std::string> path, - std::unique_ptr<IObject> object, + void Register(std::vector<std::string> path, std::unique_ptr<IObject> object, std::unique_ptr<object_type> type); /** @@ -338,4 +332,4 @@ namespace nt */ bool Unregister(const std::vector<std::string>& object_path); }; -} +} // namespace nt diff --git a/include/PermissionsManager.h b/include/PermissionsManager.h index 3af75f6..af72154 100644 --- a/include/PermissionsManager.h +++ b/include/PermissionsManager.h @@ -11,8 +11,7 @@ * @brief Declares authentication and object-access checks. */ -namespace nt -{ +namespace nt { /** * @class Capability-based permission manager * @brief Evaluates connection claims and object permissions. @@ -37,9 +36,8 @@ namespace nt * rather than re-evaluating the descriptor on every call. * See docs/reactos-ob-comparison.md §4. */ - class PermissionsManager - { - public: + class PermissionsManager { + public: /** * @brief Validates a connection during login. * @param method Authentication method used by the connection. @@ -62,7 +60,7 @@ namespace nt * 3 other stored relations, while you can access the ephemeral relation, * you cannot directly access the other 3 relations. You need explicit * permission to create a handle on the others. - * + * * Here's an example tree: * /system * /multigroups @@ -70,22 +68,21 @@ namespace nt * /relations * /user {type : stored} * /order {type : stored} - * /user_and_order {type : ephemeral; deps = [/system/multigroups/coffee_shop/relations/users, /system/multigroups/coffee_shop/relations/orders]} - * /users - * /peter - * /permissions + * /user_and_order {type : ephemeral; deps = + * [/system/multigroups/coffee_shop/relations/users, + * /system/multigroups/coffee_shop/relations/orders]} /users /peter /permissions * /multigroups/coffee_shop/relations/user_and_order {descriptor : [read]} * /paul * /permissions * /multigroups/coffee_shop/relations/user {descriptor : [write, read]} - * + * * Meaning that `peter` has access to read the `user_and_order` ephemeral * relation, but cannot open a handle on `user` and `order`. - * + * * @param object Object being accessed. * @param connection_context Connection metadata for the caller. * @return True when access is allowed. */ const bool Access(const ObjectManager::registry* object, const void* connection_context); }; -} +} // namespace nt diff --git a/include/RNT_C_API.h b/include/RNT_C_API.h index 707c04a..1a59785 100644 --- a/include/RNT_C_API.h +++ b/include/RNT_C_API.h @@ -36,6 +36,7 @@ #include <stdint.h> #include "Api.h" +#include "VM.h" #ifdef __cplusplus extern "C" { @@ -133,8 +134,7 @@ NT_API int rnt_session_close(const char* session_hash); * @param target_hash Snapshot hash to bind, or "" to clear. * @return 0 on success, negative on error. */ -NT_API int rnt_session_set_branch(const char* session_hash, - const char* branch_name, +NT_API int rnt_session_set_branch(const char* session_hash, const char* branch_name, const char* target_hash); /* ------------------------------------------------------------------ */ @@ -292,9 +292,7 @@ NT_API int rnt_list_snapshot_relations(const char* snapshot_hash, char** out); * Release with rnt_free_string(). NULL on error. * @return 0 on success, negative on error. */ -NT_API int rnt_link_tuple(const char* relation_path, - const char* kv_attrs, - char** hash_out); +NT_API int rnt_link_tuple(const char* relation_path, const char* kv_attrs, char** hash_out); /** * @brief Removes a tuple from the relation's Merkle tree and tuple store. @@ -377,40 +375,78 @@ NT_API int rnt_cursor_close(rnt_cursor_t cursor); /* VM plan builder */ /* ------------------------------------------------------------------ */ -/** Opaque plan node tree, built incrementally via rnt_plan_* calls. */ +/** Opaque plan node tree, built via rnt_plan_assemble calls. */ typedef void* rnt_plan_t; /** - * @brief Creates a SCAN plan node that reads all tuples from a stored relation. + * SCAN context: reads all tuples from a stored relation. * - * Opens a RELATION handle and cursor internally. Both are transferred to the - * plan and released when the resulting VM cursor is closed. - * - * @param relation_path Absolute slash-separated path to the relation, e.g. + * @param relation_path Absolute slash-separated path, e.g. * "/system/branches/main/multigroups/warehouse/relations/public:users". - * @return Plan node, or NULL when the relation does not exist or cannot be opened. */ -NT_API rnt_plan_t rnt_plan_scan(const char* relation_path); +typedef struct { + const char* relation_path; +} PlanArgsScan; /** - * @brief Creates a nested-loop JOIN plan node. + * JOIN context: nested-loop join of two child plans. * - * Takes ownership of both @p left and @p right. On success the caller must not - * free either child; they are released when the returned plan is freed or - * executed. On failure (NULL return) both children are freed. + * Takes ownership of both children. They are released when the assembled plan + * is freed or executed; on failure both are freed. + */ +typedef struct { + rnt_plan_t left; + rnt_plan_t right; +} PlanArgsJoin; + +/** + * TAKE context: passes at most @p limit tuples from @p source, then stops. * - * @return Plan node, or NULL on error. + * Takes ownership of @p source; on failure @p source is freed. + */ +typedef struct { + rnt_plan_t source; + size_t limit; +} PlanArgsTake; + +/** + * PROJECT context: keeps only the named attributes of @p source. + * + * @p attrs is a NULL-terminated array of attribute names to retain, e.g. + * <tt>{ "name", "profession", NULL }</tt>. Takes ownership of @p source; on + * failure @p source is freed. + */ +typedef struct { + rnt_plan_t source; + const char** attrs; +} PlanArgsProject; + +/** + * A single plan-construction request. @p operation selects which context member + * is read; the others are ignored. The members are laid out side by side rather + * than overlapped in a union so the struct maps cleanly onto OCaml ctypes, which + * has no union support. Only the member matching @p operation need be populated. */ -NT_API rnt_plan_t rnt_plan_join(rnt_plan_t left, rnt_plan_t right); +typedef struct { + nt::Operation operation; + PlanArgsScan scan; + PlanArgsJoin join; + PlanArgsTake take; + PlanArgsProject project; +} PlanAction; /** - * @brief Creates a TAKE plan node that limits output to at most @p limit tuples. + * @brief Builds one plan node from @p action and returns the resulting subtree. * - * Takes ownership of @p source. On failure @p source is freed. + * Sole entry point for plan construction. Validates runtime state once, then + * dispatches on @p action.op. Child plans for JOIN/TAKE/PROJECT are themselves + * results of prior rnt_plan_assemble calls; ownership transfers per the + * per-operator rules documented on each PlanArgs* struct. * - * @return Plan node, or NULL on error. + * @return Plan node, or NULL when the runtime is uninitialised or construction + * fails (e.g. relation does not exist). */ -NT_API rnt_plan_t rnt_plan_take(rnt_plan_t source, size_t limit); +NT_API rnt_plan_t rnt_plan_assemble(PlanAction action); /** * @brief Releases a plan that was built but not yet executed. diff --git a/include/Runtime.h b/include/Runtime.h index 4abe8c7..0fb41a5 100644 --- a/include/Runtime.h +++ b/include/Runtime.h @@ -7,12 +7,10 @@ * @brief Declares the top-level Relational NT runtime facade. */ -namespace nt -{ +namespace nt { /** @brief Top-level runtime object used by applications and the console entry point. */ - class NT - { - public: + class NT { + public: /** * @brief Reports whether the runtime is active. * @return True when the runtime is running. @@ -22,4 +20,4 @@ namespace nt /** @brief Simulates an external entry call into the runtime. */ void SimulateEntryCall(); }; -} +} // namespace nt diff --git a/include/SqliteBackend.h b/include/SqliteBackend.h index e4cdf56..037d8e6 100644 --- a/include/SqliteBackend.h +++ b/include/SqliteBackend.h @@ -21,11 +21,9 @@ * via Merkle::Page which reads only the KV store. */ -namespace nt -{ - class SqliteBackend : public IStorageBackend - { - public: +namespace nt { + class SqliteBackend : public IStorageBackend { + public: /** * @brief Opens (or creates) a SQLite database at @p path. * @param path File path, or ":memory:" for an in-process database. @@ -37,7 +35,7 @@ namespace nt std::string Put(std::vector<uint8_t> value) override; std::optional<std::vector<uint8_t>> Get(const std::string& hash) override; - private: + private: sqlite3* db_ = nullptr; }; -} +} // namespace nt diff --git a/include/TupleCodec.h b/include/TupleCodec.h index 18294d4..6c74c1e 100644 --- a/include/TupleCodec.h +++ b/include/TupleCodec.h @@ -23,8 +23,7 @@ * [uint32_le name_len][name bytes][uint32_le value_len][value bytes] ... */ -namespace nt::TupleCodec -{ +namespace nt::TupleCodec { /** * @brief Computes the SHA256 hex digest of the serialized tuple. * @@ -49,4 +48,4 @@ namespace nt::TupleCodec * @return Reconstructed attribute list in serialization order. */ std::vector<Attribute> Deserialize(const std::vector<uint8_t>& bytes); -} +} // namespace nt::TupleCodec diff --git a/include/Types.h b/include/Types.h index edf4297..6956e09 100644 --- a/include/Types.h +++ b/include/Types.h @@ -118,8 +118,7 @@ enum AUTH_METHOD { PLAIN_TEXT }; -namespace nt -{ +namespace nt { /** @brief A single named value in a tuple, produced by the cursor layer. */ struct Attribute { std::string name; @@ -133,9 +132,9 @@ namespace nt * one attribute at a time. Returns nullptr when all attributes are exhausted. */ class Tuple { - public: - explicit Tuple(std::vector<Attribute> attributes) - : attributes_(std::move(attributes)) {} + public: + explicit Tuple(std::vector<Attribute> attributes) : attributes_(std::move(attributes)) { + } /** @brief Returns the next attribute, or nullptr when exhausted. */ const Attribute* Next() { @@ -144,13 +143,17 @@ namespace nt return nullptr; } - void Reset() { position_ = 0; } + void Reset() { + position_ = 0; + } /** @brief Direct read-only access to all attributes without affecting position. */ - const std::vector<Attribute>& attrs() const { return attributes_; } + const std::vector<Attribute>& attrs() const { + return attributes_; + } - private: + private: std::vector<Attribute> attributes_; size_t position_ = 0; }; -} +} // namespace nt diff --git a/include/VM.h b/include/VM.h index 3bfe521..3d97779 100644 --- a/include/VM.h +++ b/include/VM.h @@ -14,8 +14,7 @@ * @brief Declares the logic execution boundary for relational and higher-order workloads. */ -namespace nt -{ +namespace nt { /** * @class VM * @brief Hosts the first-order logic (FOL) and second-order logic (SOL) cores. @@ -64,15 +63,25 @@ namespace nt * (for EPHEMERAL_RELATION cursors) or ignored (for stored RELATION cursors, * which need no per-probe parameterization). */ - struct PathArg - { + struct PathArg { enum class Kind { Var, Const }; - Kind kind; + Kind kind; std::string name; /**< Attribute name to look up (Var), or literal value (Const). */ - static PathArg Var(std::string attr) { return { Kind::Var, std::move(attr) }; } - static PathArg Const(std::string val) { return { Kind::Const, std::move(val) }; } + static PathArg Var(std::string attr) { + return {Kind::Var, std::move(attr)}; + } + static PathArg Const(std::string val) { + return {Kind::Const, std::move(val)}; + } + }; + + enum Operation { + FOL_OPERATION_SCAN = 1, + FOL_OPERATION_JOIN, + FOL_OPERATION_TAKE, + FOL_OPERATION_PROJECT }; /** @@ -91,12 +100,9 @@ namespace nt * this to bound scans over AlephZero ephemeral relations. * - PROJECT: filters each input tuple to the named attributes in project_attrs. */ - struct PlanNode - { - enum class Op { SCAN, JOIN, TAKE, PROJECT }; - - Op op; - PlanNode* left = nullptr; + struct PlanNode { + Operation op; + PlanNode* left = nullptr; PlanNode* right = nullptr; /** @@ -134,13 +140,12 @@ namespace nt * successful join. Callers must consume the returned pointer before * calling Next() again — same contract as a cursor page pointer. */ - Tuple* join_left = nullptr; + Tuple* join_left = nullptr; std::optional<Tuple> join_buffer; }; - class VM - { - public: + class VM { + public: // TODO: CursorManager should be injected as a shared runtime instance, // matching the pattern flagged for HandlerManager and LifecycleManager. // @@ -167,21 +172,19 @@ namespace nt */ Tuple* Next(PlanNode* node); - private: + private: CursorManager& cursors_; /** * Resolves a scan_args template against an outer tuple, producing the * concrete args vector to write into the inner cursor before probing. */ - static std::vector<std::string> ResolveArgs(const std::vector<PathArg>& tmpl, - Tuple* from); + static std::vector<std::string> ResolveArgs(const std::vector<PathArg>& tmpl, Tuple* from); /** Resets the inner cursor state and writes resolved args into it. */ - static void ResetInner(CursorManager::cursor* c, - std::vector<std::string> args); + static void ResetInner(CursorManager::cursor* c, std::vector<std::string> args); /** Merges left and right tuple attributes into node->join_buffer. */ static Tuple* MergeInto(PlanNode* node, Tuple* left, Tuple* right); }; -} +} // namespace nt |
