aboutsummaryrefslogtreecommitdiffstats
path: root/include/EphemeralRelation.h
diff options
context:
space:
mode:
Diffstat (limited to 'include/EphemeralRelation.h')
-rw-r--r--include/EphemeralRelation.h143
1 files changed, 143 insertions, 0 deletions
diff --git a/include/EphemeralRelation.h b/include/EphemeralRelation.h
new file mode 100644
index 0000000..9834337
--- /dev/null
+++ b/include/EphemeralRelation.h
@@ -0,0 +1,143 @@
+#pragma once
+
+#include "LifecycleManager.h"
+#include "ObjectManager.h"
+
+#include <string>
+#include <utility>
+#include <vector>
+
+/**
+ * @file EphemeralRelation.h
+ * @brief Writer path and lifetime helpers for ephemeral relations.
+ *
+ * An ephemeral relation has no tuple storage of its own; its tuples are
+ * produced on demand by a generator (see ObjectManager.h). Relational-algebra
+ * operations (select, project, join) all yield one. The functions here register
+ * such a relation into the object manager, hash its identity, pin the base
+ * relations it is defined atop, and release session-owned entries at session
+ * close.
+ *
+ * They are free functions over an ObjectManager and a LifecycleManager, not a
+ * stateful manager object.
+ *
+ * See docs/ephemeral-relations.org for the lifetime model.
+ */
+
+namespace nt::Ephemeral {
+ /**
+ * @brief Lifetime class of a freshly produced ephemeral relation.
+ *
+ * Naming is what makes a result outlive its cursor: an anonymous result is
+ * owned by nobody.
+ *
+ * - Scratch: an anonymous per-statement intermediate. Registered under
+ * /system/sessions/<session>/scratch/<root> and not session-pinned, so it
+ * is collected by reference counting once its consuming cursor closes.
+ * - Named: a view-like binding. Registered under
+ * /system/sessions/<session>/ephemeral/<name> with one session-ownership
+ * Pin, so it survives between commands and can be re-requested. Released
+ * at rnt_session_close or (later) by the idle reaper.
+ */
+ enum class Tier { Scratch, Named };
+
+ /**
+ * @brief Splits a slash-joined logical path into registry components.
+ *
+ * Drops a leading slash and any empty segments, matching split_path in the
+ * C API layer. Used by the writer path here and by
+ * LifecycleManager::CascadeEphemeral when re-splitting stored dependency
+ * paths at GC time.
+ */
+ std::vector<std::string> SplitPath(const std::string& path);
+
+ /**
+ * @brief Deterministic merkle_root for an ephemeral relation.
+ *
+ * Hashes SHA256 over the generator identity, the schema, and the
+ * merkle_roots of the declared base relations. Two ephemerals with the same
+ * operator, schema, and base roots hash identically, so a repeated query
+ * reuses one registry entry instead of creating duplicates; rebinding a base
+ * produces a new root that propagates like a tuple insertion in a stored
+ * relation.
+ *
+ * Schema entries and base roots are sorted internally, so input order does
+ * not affect the result.
+ *
+ * @param generator_identity Stable label of the producing operator/builtin
+ * (e.g. "join", "select:age", "eq").
+ * @param schema (attribute_name, attribute_type) pairs.
+ * @param base_roots merkle_roots of the base relations, any order.
+ * @return 64-char lowercase-hex SHA256 digest.
+ */
+ std::string ComposeRoot(const std::string& generator_identity,
+ const std::vector<std::pair<std::string, std::string>>& schema,
+ const std::vector<std::string>& base_roots);
+
+ /**
+ * @brief Registers an ephemeral relation produced by a relational operation.
+ *
+ * Resolves each dependency in the registry to read its current merkle_root
+ * (for the identity hash) and to take a structural Pin on it: a base
+ * relation cannot be GC'd while an ephemeral is defined atop it. Then
+ * registers an EphemeralRelation IObject with an ephemeral_object_type
+ * carrying the generator and cardinality. For Tier::Named, an extra
+ * session-ownership Pin is taken so the entry outlives its cursor.
+ *
+ * Idempotent: an existing entry at the target path (identical scratch root,
+ * or a live named binding) is returned without re-registering or
+ * double-pinning.
+ *
+ * The caller should Monitor the returned entry when it opens a cursor over
+ * it; a Scratch entry with no cursor and no session pin lingers until
+ * session close.
+ *
+ * @param objects Registry to register into.
+ * @param lifecycles Lifecycle manager for the dependency / ownership pins.
+ * @param session_hash Owning session's hash (the namespace parent).
+ * @param tier Scratch (anonymous) or Named (session-owned).
+ * @param name Leaf name for Tier::Named; ignored for Tier::Scratch
+ * (the composed root is used as the leaf instead).
+ * @param generator Tuple-producing generator for this relation.
+ * @param cardinality Finite / ConstrainedFinite / AlephZero / Continuum.
+ * @param generator_identity Stable operator label, see ComposeRoot.
+ * @param schema (attribute_name, attribute_type) pairs.
+ * @param dependencies Slash-joined logical paths (no leading slash) of the
+ * base relations this is defined atop, e.g.
+ * "system/snapshots/<h>/relations/<rel>". Stored verbatim
+ * on the object and re-split at GC time. Every path must
+ * resolve; an unresolvable dependency fails the whole
+ * registration, since a stored-but-unpinned path would
+ * make CascadeEphemeral Unpin a hold it never took.
+ * @return Borrowed pointer to the registered (or pre-existing) entry, or
+ * nullptr on error (empty session hash, empty name for Tier::Named,
+ * or any unresolvable dependency).
+ */
+ ObjectManager::registry* Register(
+ ObjectManager& objects, LifecycleManager& lifecycles, const std::string& session_hash,
+ Tier tier, const std::string& name,
+ ObjectManager::ephemeral_object_type::Generator generator,
+ ObjectManager::ephemeral_object_type::Cardinality cardinality,
+ const std::string& generator_identity,
+ const std::vector<std::pair<std::string, std::string>>& schema,
+ const std::vector<std::string>& dependencies);
+
+ /**
+ * @brief Releases all ephemeral relations owned by a session.
+ *
+ * Called by rnt_session_close before the session entry is removed. Named
+ * entries directly under the session's "ephemeral" subdir have their
+ * session-ownership Pin released (collecting them when no cursor or
+ * dependent still holds them, cascading their base-relation Unpins). Scratch
+ * entries under the session's "scratch" subdir were never session-pinned;
+ * any that linger with no open cursor are collected directly. Entries still
+ * held by an open cursor are left for the normal handle-release path.
+ *
+ * @param objects Registry to walk.
+ * @param lifecycles Lifecycle manager driving the releases.
+ * @param session_hash Session whose ephemerals to release.
+ * @return Number of entries released or collected.
+ */
+ std::size_t ReleaseSession(ObjectManager& objects, LifecycleManager& lifecycles,
+ const std::string& session_hash);
+} // namespace nt::Ephemeral