diff options
| author | Marcos Magueta <maguetamarcos@gmail.com> | 2026-05-10 02:27:08 -0300 |
|---|---|---|
| committer | Marcos Magueta <maguetamarcos@gmail.com> | 2026-05-10 02:27:08 -0300 |
| commit | 7ffd4d99bbb8e358c6694c27c7ff859967872ece (patch) | |
| tree | 8af04f4032651de7e49d1cac01e6f20b2315b6cb /include | |
| parent | 5ee324f03f8a7e6f09dad7b8580a2d32172694f8 (diff) | |
| download | RNT-7ffd4d99bbb8e358c6694c27c7ff859967872ece.tar.gz RNT-7ffd4d99bbb8e358c6694c27c7ff859967872ece.zip | |
comparison to nt ob
Diffstat (limited to '')
| -rw-r--r-- | include/HandlerManager.h | 26 | ||||
| -rw-r--r-- | include/IdentityManager.h | 24 | ||||
| -rw-r--r-- | include/LifecycleManager.h | 93 | ||||
| -rw-r--r-- | include/NamespaceReferenceManager.h | 54 | ||||
| -rw-r--r-- | include/ObjectManager.h | 77 | ||||
| -rw-r--r-- | include/PermissionsManager.h | 16 |
6 files changed, 237 insertions, 53 deletions
diff --git a/include/HandlerManager.h b/include/HandlerManager.h index 4f63f17..f3d504e 100644 --- a/include/HandlerManager.h +++ b/include/HandlerManager.h @@ -2,7 +2,9 @@ #include "Api.h" #include "ObjectManager.h" +#include "Types.h" +#include <set> #include <string> #include <vector> @@ -36,15 +38,33 @@ namespace nt /** * @brief Represents authorized access to an object in the registry. * - * This increases the handle count in the object manager. We should - * consider adding a vector to the object manager with all handles that - * refer to an object. + * The access mask is evaluated once during Open and cached here for the + * lifetime of the handle. Subsequent operations check `granted_access` + * rather than re-evaluating the security descriptor on every call. This + * resolves the performance question in PermissionsManager about when to + * check permissions. + * + * Because storage is append-only, a WRITE claim does not mean mutating an + * existing tuple in-place. It means the session is authorized to commit a + * new snapshot version of the relation. Two sessions holding WRITE handles + * on the same relation always produce independent snapshots — there is no + * data-level conflict. + * + * @todo Populate `granted_access` inside HandlerManager::Open from + * PermissionsManager::Firewall / Access. See docs/reactos-ob-comparison.md §4. */ struct handle { /** Object referenced by this handle. */ ObjectManager::registry* object = nullptr; /** Connection metadata associated with the authorized access. */ void* connection_context = nullptr; + /** + * Access claims granted to this handle at open time. + * Cached here so that per-operation checks read from the handle + * rather than re-evaluating the security descriptor. + * @todo Populate in HandlerManager::Open. + */ + std::set<AUTH_CLAIM> granted_access; }; /** diff --git a/include/IdentityManager.h b/include/IdentityManager.h index 0e2d08f..5c8dd14 100644 --- a/include/IdentityManager.h +++ b/include/IdentityManager.h @@ -10,19 +10,37 @@ namespace nt { - /** @brief Checks whether an object supports identity-level operations. */ + /** + * @brief Checks whether an object supports identity-level operations. + * + * @todo Migrate to type callbacks. Once `object_type` holds `OpenProcedure` + * and `CloseProcedure` function pointers, CanOpen / CanClose become + * thin dispatchers that invoke the corresponding procedure — or this + * manager is absorbed into HandlerManager directly. The function pointer + * should be accompanied by a `const char* name` label on `object_type` + * so that error logs identify the type without dereferencing the pointer. + * See docs/reactos-ob-comparison.md §2. + */ class NT_API IdentityManager { public: /** - * @brief Looks into the methods of the object type and asserts if it can be opened. + * @brief Returns true when the object's type supports being opened. + * + * Currently checks that the object is non-null (stub). Should invoke + * `object_type::OpenProcedure` once callbacks are defined. + * * @param object Object to inspect. * @return True when the object can be opened. */ const bool CanOpen(ObjectManager::registry* object); /** - * @brief Checks whether an object can be closed. + * @brief Returns true when the object's type supports being closed. + * + * Currently checks that the object is non-null (stub). Should invoke + * `object_type::CloseProcedure` once callbacks are defined. + * * @param object Object to inspect. * @return True when the object can be closed. */ diff --git a/include/LifecycleManager.h b/include/LifecycleManager.h index 914ce0a..8126820 100644 --- a/include/LifecycleManager.h +++ b/include/LifecycleManager.h @@ -10,53 +10,92 @@ namespace nt { - /** @brief Manages runtime lifecycle concerns for registry objects. */ + /** + * @brief Manages runtime lifecycle concerns for registry objects. + * + * Object lifetime is governed by two independent counters in registry_head: + * `handle_count` (sessions holding an open handle) and `reference_count` + * (structural dependencies such as cursors pinned to a snapshot or views + * referencing base relations). An object is eligible for GC only when both + * reach zero. + * + * Monitor / Unmonitor manage `handle_count`. Pin / Unpin manage + * `reference_count`. See docs/reactos-ob-comparison.md §1. + */ class NT_API LifecycleManager { public: /** * @brief Starts monitoring an object's lifecycle. * - * If the object is not being monitored already, monitor the lifecycle - * by updating the handle count. Maybe also look at the reference count - * and kill some categories of disposable objects no longer referenced - * by other objects, like transactions. - * - * One use case is preventing compaction/pruning of history while - * cursors depend on old database snapshots, for example. Think of - * other use cases later. + * Increments `handle_count` on the object's registry_head. Should be + * called after all authorization checks pass inside HandlerManager::Open. * * @param object Object to monitor. */ void Monitor(ObjectManager::registry* object); /** - * @brief Serializes contention for changes to mutable references. + * @brief Stops monitoring an object. * - * This can be used for the HEAD of a branch to serialize access. If the - * object does not cause contention, such as a relation, then this can - * approve the operation because relations and multigroups are immutable - * snapshots. Transactions also do not cause contention. + * Decrements `handle_count`. When both `handle_count` and + * `reference_count` reach zero, the object becomes eligible for GC. * - * The objects that do cause contention are mutable reference states in - * shared sessions. Examples include the HEAD of a branch, namespace - * collisions, multi-branch atomic commits (which may damage isolation), - * and garbage collection of old state when old-enough history is removed - * to save space. + * @todo Gate GC on both counters reaching zero, not just handle_count. + * For deferred compaction, enqueue onto a background GC list rather + * than freeing inline. See docs/reactos-ob-comparison.md §1 and §7. * - * @param object Object to check for contention. - * @return True when the operation may proceed. + * @param object Object to stop monitoring. */ - const bool Contention(ObjectManager::registry* object); + void Unmonitor(ObjectManager::registry* object); /** - * @brief Stops monitoring an object. + * @brief Increments the structural dependency count on an object. * - * The inverse of Monitor. Maybe garbage collect here also if the - * counters go to zero. + * Call when one object takes a dependency on another — for example when + * a cursor pins an immutable snapshot version, or when a view is + * registered against its base relations. Prevents GC of the target object + * while the dependency is live. * - * @param object Object to stop monitoring. + * @todo Implement. See docs/reactos-ob-comparison.md §1. + * + * @param object Object being depended upon. */ - void Unmonitor(ObjectManager::registry* object); + void Pin(ObjectManager::registry* object); + + /** + * @brief Decrements the structural dependency count on an object. + * + * The inverse of Pin. When both `reference_count` and `handle_count` + * reach zero the object becomes eligible for GC. + * + * @todo Implement. See docs/reactos-ob-comparison.md §1. + * + * @param object Object whose dependency is being released. + */ + void Unpin(ObjectManager::registry* object); + + /** + * @brief Serializes contention for changes to mutable reference states. + * + * Immutable objects — relation snapshots, multigroup snapshots, + * transactions — never raise contention. Two sessions opening the same + * immutable snapshot simultaneously is always safe; they will produce + * independent results without conflict. + * + * Contention applies only to mutable reference states: the HEAD of a + * branch and namespace entries targeted by atomic multi-reference updates. + * These are the sole mutable pointers in the system. When a session holds + * a write handle on a HEAD, a second write opener must block or fail. + * + * @todo Implement: read `object_type::exclusive`. Return false immediately + * for non-exclusive objects. For exclusive objects, return false + * (contention detected) when `handle_count > 0` for a write-mode + * opener. See docs/reactos-ob-comparison.md §6. + * + * @param object Object to check for contention. + * @return True when the operation may proceed. + */ + const bool Contention(ObjectManager::registry* object); }; } diff --git a/include/NamespaceReferenceManager.h b/include/NamespaceReferenceManager.h index 59068f7..0bf00bc 100644 --- a/include/NamespaceReferenceManager.h +++ b/include/NamespaceReferenceManager.h @@ -13,20 +13,50 @@ namespace nt * @class NamespaceReferenceManager * @brief Handles the logical mapping and isolation of human-readable references. * - * Design notes: - * - Namespace isolation: allow private branch shadowing, such as - * /user_a/refs/branch/abc. To preserve lookup clarity, protocol-level - * syntax must explicitly define scope and prevent non-deterministic - * shadowing during resolution. + * This manager is the reparse layer of the namespace. Its design mirrors the + * ReactOS ParseProcedure / STATUS_REPARSE mechanism: a namespace entry whose + * type carries a ParseProcedure can redirect name resolution to a different + * path, allowing branch references and views to appear as first-class objects + * in the namespace without exposing their physical storage paths directly. * - * - Multi-reference atomic updates: ensure updates to multiple references, - * such as pushing to master and audit_log simultaneously, are - * all-or-nothing. If any contention check fails, the whole batch is - * aborted to prevent partial commits and preserve audit consistency. + * **Branch references.** + * A path such as `/refs/branch/main` is a namespace entry backed by a + * reference object. Its ParseProcedure rewrites the path to the physical + * snapshot path (e.g. `/snapshots/abc123`). The caller's handle lands on the + * snapshot. To advance the HEAD, the caller must explicitly open the reference + * object itself with WRITE access, which is the sole contention point for that + * branch. * - * Audit needs global access, which means it should be dissociated from a - * branch scope. Since branches are the only contention points for - * references, it makes sense to model audit as an independent branch too. + * **View resolution.** + * A view is an ephemeral RELATION whose ParseProcedure reparses to its base + * relations internally on behalf of the runtime. The caller's handle and access + * mask remain bound to the view. The base relations are accessed only via the + * view's own type callbacks; the caller never receives a handle on them and + * does not need explicit permission on them. Capability security is enforced at + * the view boundary, not the base relation boundary. + * + * **Atomic multi-reference updates.** + * Updating multiple references simultaneously (e.g. advancing both `main` and + * `audit_log`) must be all-or-nothing. The implementation should acquire + * exclusive locks on all target namespace entries before modifying any. If + * LifecycleManager::Contention fails on any entry, all locks are released and + * the batch is aborted. This preserves audit consistency. + * + * **Cycle guard.** + * View definitions may reference other views, and branch aliases may chain. + * Name resolution must track reparse depth and return an error after a bounded + * number of iterations to prevent infinite cycles. + * + * **Audit branch.** + * Audit requires global access dissociated from any data branch. It should be + * modelled as an independent branch; its HEAD is the only contention point for + * audit-affecting operations. + * + * @todo Implement `Resolve(path)` with a reparse loop and cycle depth guard. + * @todo Define the reference object type with `object_type::exclusive = true` + * and a ParseProcedure that rewrites the resolution path. + * @todo Define the batch-update API with all-or-nothing contention semantics. + * See docs/reactos-ob-comparison.md §8. */ class NT_API NamespaceReferenceManager { diff --git a/include/ObjectManager.h b/include/ObjectManager.h index aab3a6f..4b537f7 100644 --- a/include/ObjectManager.h +++ b/include/ObjectManager.h @@ -39,21 +39,75 @@ namespace nt /** @brief Abstract registry object representing a transaction. */ class Transaction : public IObject {}; - /** @brief Describes the behavior and capabilities of an object category. */ + /** + * @brief Describes the behavior and capabilities of an object category. + * + * @todo Replace `methods` with typed callback fields: `OpenProcedure`, + * `CloseProcedure`, `DeleteProcedure`, and `ParseProcedure`. + * Store a `const char* name` label alongside each callback so that + * logs and assertions can identify which type fired without having + * to dereference a pointer. `IdentityManager::CanOpen` / `CanClose` + * then become thin dispatchers that invoke the corresponding + * procedure, or are absorbed into `HandlerManager` directly. + * See docs/reactos-ob-comparison.md §2. + * + * @todo Add an `exclusive` flag for mutable reference objects (branch + * HEADs, namespace entries). Non-exclusive objects — immutable + * snapshots, transactions — must skip contention checks entirely. + * See docs/reactos-ob-comparison.md §6. + */ struct object_type { /** Object category label. */ OBJECT_TYPE label; /** True when the object is not durable. For example: TRANSACTION. */ bool disposable; - /** Methods supported by this object type. */ + /** + * Methods supported by this object type. + * @todo Replace with typed callback function pointers. See class-level todo. + */ std::set<METHOD> methods; + /** + * When true, only one write-mode handle may be open at a time. + * Applies to mutable reference states such as branch HEADs. + * Immutable snapshot objects must leave this false. + * @todo Wire into LifecycleManager::Contention. + */ + bool exclusive = false; }; - /** @brief Shared metadata stored at the head of a registry entry. */ + /** + * @brief Shared metadata stored at the head of a registry entry. + * + * Two independent reference counters govern object lifetime. + * An object is eligible for garbage collection only when both reach zero: + * + * - `handle_count` — open sessions holding a cursor or handle on this object. + * Managed exclusively by LifecycleManager::Monitor / Unmonitor. + * - `reference_count` — structural dependencies such as a view referencing its + * base relations, or a cursor pinned to an immutable snapshot version. + * Managed by LifecycleManager::Pin / Unpin (not yet implemented). + * + * All snapshot versions are immutable. An insertion or deletion produces a new + * snapshot rather than mutating an existing one. A snapshot's `reference_count` + * is non-zero while any cursor is pinned to it and drops to zero only when all + * such cursors are released. + * + * @todo Implement `reference_count` tracking. Add LifecycleManager::Pin / + * Unpin. Update LifecycleManager::Unmonitor to gate GC on both counters + * reaching zero. See docs/reactos-ob-comparison.md §1. + * + * @todo Define and attach a security_descriptor. When added, store it as a + * pointer into a shared, content-addressed SD cache rather than inline. + * Permissions are strictly capability-based and must never be inherited + * from a parent namespace entry. See docs/reactos-ob-comparison.md §5. + */ struct registry_head { - // TODO: Increment reference_count when one registry object depends on another - // (e.g. an ephemeral view that references base relations). Decrement when the - // dependency is removed. Used to block cleanup of objects still referenced by others. + /** + * Structural dependency count. Non-zero while another registry object + * references this one (e.g. a view depending on a base relation, or a + * cursor pinned to a snapshot version). + * @todo Implement via LifecycleManager::Pin / Unpin. + */ uint32_t reference_count = 0; /** Number of open handles. Maintained by LifecycleManager::Monitor/Unmonitor. */ uint32_t handle_count = 0; @@ -61,7 +115,6 @@ namespace nt std::unique_ptr<object_type> type; /** Logical object path inside the namespace. */ std::vector<std::string> path; - /** security_descriptor to be added later, maybe also a set of labels */ }; /** @brief Node in the object registry. */ @@ -70,7 +123,15 @@ namespace nt std::unique_ptr<registry_head> head; /** Abstract object payload. Owned by this entry. */ std::unique_ptr<IObject> object; - /** TODO: Treat as a list for now, but ideally it is a tree. */ + /** + * Next entry in the registry. Currently a flat linked list. + * @todo Replace with a trie whose nodes are per-path-segment hash maps. + * Each directory level holds a hash map from segment string to + * child registry*. Find() and Register() walk the trie + * component-by-component instead of scanning a flat list. + * Consider pulling a well-tested radix-tree via vcpkg rather than + * implementing from scratch. See docs/reactos-ob-comparison.md §3. + */ std::unique_ptr<registry> next; }; diff --git a/include/PermissionsManager.h b/include/PermissionsManager.h index 65c00e5..2db1784 100644 --- a/include/PermissionsManager.h +++ b/include/PermissionsManager.h @@ -20,6 +20,22 @@ namespace nt * Permission checks are intentionally separated from lookup. The object * manager can retrieve a candidate object, while this manager decides * whether the caller is allowed to use it. + * + * Permissions are strictly capability-based and must be explicitly granted. + * There is no implicit flow of access rights from a parent namespace entry to + * its children (no SD inheritance). A caller who holds READ on a multigroup + * does not thereby hold READ on its constituent relations — that is a separate, + * explicit capability. + * + * @todo Define a security_descriptor structure. Store instances in a shared, + * content-addressed cache (keyed by descriptor content, not by namespace + * ancestry) so that identical ACLs are not duplicated across relations. + * See docs/reactos-ob-comparison.md §5 and §7. + * + * @todo Cache the result of Access() in HandlerManager::handle::granted_access + * at open time. Per-operation checks should then read from the handle + * rather than re-evaluating the descriptor on every call. + * See docs/reactos-ob-comparison.md §4. */ class NT_API PermissionsManager { |
