From af8759a9c1d965a3220024d1857aea219d62d898 Mon Sep 17 00:00:00 2001 From: Marcos Magueta Date: Mon, 18 May 2026 12:50:25 -0300 Subject: Branching and object registry rework (#11) --- include/LifecycleManager.h | 75 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 69 insertions(+), 6 deletions(-) (limited to 'include/LifecycleManager.h') diff --git a/include/LifecycleManager.h b/include/LifecycleManager.h index 8126820..5508bc6 100644 --- a/include/LifecycleManager.h +++ b/include/LifecycleManager.h @@ -1,6 +1,7 @@ #pragma once #include "Api.h" +#include "IStorageBackend.h" #include "ObjectManager.h" /** @@ -15,9 +16,9 @@ namespace nt * * 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. + * (structural dependencies such as cursors pinned to a snapshot or + * ephemeral relations referencing their 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. @@ -25,6 +26,18 @@ namespace nt class NT_API LifecycleManager { public: + /** + * @brief Constructs a LifecycleManager bound to a registry and store. + * + * Needs the registry to perform GC: Unmonitor and Unpin call + * ObjectManager::Unregister once both counters reach zero. Type-specific + * cleanup (e.g. cascading a Multigroup's pin to its child Relations, + * or a BranchTree's pin to its child Multigroups) runs inside the + * lifecycle manager before the entry is spliced out. The storage + * backend is needed by CascadeBranchTree to page the merkle nodes. + */ + LifecycleManager(ObjectManager& objects, IStorageBackend& storage); + /** * @brief Starts monitoring an object's lifecycle. * @@ -53,9 +66,9 @@ namespace nt * @brief Increments the structural dependency count on an object. * * 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. + * a cursor pins an immutable snapshot version, or when an ephemeral + * relation is registered against its base relations. Prevents GC of the + * target object while the dependency is live. * * @todo Implement. See docs/reactos-ob-comparison.md §1. * @@ -75,6 +88,15 @@ namespace nt */ void Unpin(ObjectManager::registry* object); + /** + * @brief Returns true when the object is GC-eligible right now. + * + * Eligibility is the joint condition handle_count == 0 && + * reference_count == 0. Decrement callers (Unmonitor / Unpin) consult + * this and, when true, run type-specific cleanup before unregistering. + */ + bool IsEligibleForGC(ObjectManager::registry* object) const; + /** * @brief Serializes contention for changes to mutable reference states. * @@ -97,5 +119,46 @@ namespace nt * @return True when the operation may proceed. */ const bool Contention(ObjectManager::registry* object); + + private: + /** + * @brief Joint-counters check + type-specific cascade + Unregister. + * + * Called by Unmonitor and Unpin after their decrement. No-op when the + * object is still referenced. When eligible: + * - MULTIGROUP entries first unpin every Relation registered as a + * direct child of their /system/snapshots/H subtree. + * - BRANCH_TREE entries first unpin every Multigroup their + * content-addressed tree references. + * - The entry is then removed from the registry; its IObject and + * registry_head are freed. + * + * Inline GC for now; the reaper-queue deferred-deletion pattern from + * docs/reactos-ob-comparison.md §7 is a later optimisation. + */ + void TryCollect(ObjectManager::registry* object); + + /** + * @brief Releases pins held by a MULTIGROUP entry on its child Relations. + * + * Iterates the registry once, collects every /system/snapshots// + * direct child, and calls Unpin on each. Triggered exclusively from + * TryCollect at the moment the parent snapshot becomes eligible for GC. + */ + void CascadeMultigroup(ObjectManager::registry* multigroup); + + /** + * @brief Releases pins held by a BRANCH_TREE entry on its child mgs. + * + * Pages the Merkle tree at the BranchTree's merkle_root, + * resolves each (mg_name, mg_hash) entry to its + * /system/snapshots/ Multigroup, and calls Unpin on it. + * Triggered exclusively from TryCollect at the moment the BranchTree + * itself becomes eligible for GC. + */ + void CascadeBranchTree(ObjectManager::registry* branch_tree); + + ObjectManager& objects_; + IStorageBackend& storage_; }; } -- cgit v1.2.3