aboutsummaryrefslogtreecommitdiffstats
path: root/src/NamespaceReferenceManager.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/NamespaceReferenceManager.cpp127
1 files changed, 127 insertions, 0 deletions
diff --git a/src/NamespaceReferenceManager.cpp b/src/NamespaceReferenceManager.cpp
index 1d9baac..455d077 100644
--- a/src/NamespaceReferenceManager.cpp
+++ b/src/NamespaceReferenceManager.cpp
@@ -1,5 +1,132 @@
#include "NamespaceReferenceManager.h"
+#include "Merkle.h"
+
namespace nt
{
+ NamespaceReferenceManager::NamespaceReferenceManager(ObjectManager& objects,
+ IStorageBackend& storage)
+ : objects_(objects), storage_(storage)
+ {}
+
+ // Resolves the multigroup hash that `mg_name` currently maps to inside the
+ // branch-tree rooted at `branch_tree_root`. Returns the empty string when
+ // the branch is unborn (empty root) or the multigroup is absent.
+ static std::string lookup_mg_hash(IStorageBackend& storage,
+ const std::string& branch_tree_root,
+ const std::string& mg_name)
+ {
+ if (branch_tree_root.empty()) return "";
+ auto found = Merkle<std::string>::Get(storage, branch_tree_root, mg_name);
+ if (!found) return "";
+ // All-zero payload = "no snapshot bound" sentinel matching MultigroupCodec.
+ static const Hash32 zero{};
+ if (*found == zero) return "";
+ return bin_to_hex(*found);
+ }
+
+ std::vector<std::string> NamespaceReferenceManager::Resolve(
+ std::vector<std::string> path) const
+ {
+ constexpr int kMaxReparseDepth = 30;
+
+ for (int depth = 0; depth < kMaxReparseDepth; ++depth)
+ {
+ // /system/sessions/<X>/branches/<name>/multigroups/<mg>/<sub>...
+ // — per-session override takes precedence; absent override falls
+ // back to the global branch. Requires at minimum the literal
+ // "multigroups" qualifier and an mg name.
+ if (path.size() > 6
+ && path[0] == "system"
+ && path[1] == "sessions"
+ && path[3] == "branches"
+ && path[5] == "multigroups")
+ {
+ const std::vector<std::string> session_path{
+ "system", "sessions", path[2]
+ };
+ auto* session_entry = objects_.Find(session_path);
+
+ std::string branch_tree_root;
+ if (session_entry && session_entry->object)
+ {
+ auto* session = dynamic_cast<ObjectManager::Session*>(
+ session_entry->object.get());
+ if (session)
+ {
+ auto it = session->branch_overrides.find(path[4]);
+ if (it != session->branch_overrides.end())
+ branch_tree_root = it->second;
+ }
+ }
+
+ // No session-level override — defer to the global branch's HEAD.
+ if (branch_tree_root.empty())
+ {
+ const std::vector<std::string> branch_path{
+ "system", "branches", path[4]
+ };
+ auto* bentry = objects_.Find(branch_path);
+ if (bentry && bentry->object)
+ {
+ auto* branch = dynamic_cast<ObjectManager::Branch*>(
+ bentry->object.get());
+ if (branch) branch_tree_root = branch->target_hash;
+ }
+ }
+
+ const std::string mg_hash =
+ lookup_mg_hash(storage_, branch_tree_root, path[6]);
+ if (mg_hash.empty()) return path;
+
+ std::vector<std::string> rewritten{
+ "system", "snapshots", mg_hash
+ };
+ for (size_t i = 7; i < path.size(); ++i)
+ rewritten.push_back(path[i]);
+
+ path = std::move(rewritten);
+ continue;
+ }
+
+ // /system/branches/<name>/multigroups/<mg>/<sub>... →
+ // /system/snapshots/<mg_hash>/<sub>...
+ // Requires the literal "multigroups" qualifier and an mg name. A
+ // bare /system/branches/<name> path opens the branch object itself
+ // and is returned unchanged.
+ if (path.size() > 4
+ && path[0] == "system"
+ && path[1] == "branches"
+ && path[3] == "multigroups")
+ {
+ const std::vector<std::string> branch_path{
+ "system", "branches", path[2]
+ };
+ auto* entry = objects_.Find(branch_path);
+ if (!entry || !entry->object) return path;
+
+ auto* branch =
+ dynamic_cast<ObjectManager::Branch*>(entry->object.get());
+ if (!branch) return path;
+
+ const std::string mg_hash =
+ lookup_mg_hash(storage_, branch->target_hash, path[4]);
+ if (mg_hash.empty()) return path;
+
+ std::vector<std::string> rewritten{
+ "system", "snapshots", mg_hash
+ };
+ for (size_t i = 5; i < path.size(); ++i)
+ rewritten.push_back(path[i]);
+
+ path = std::move(rewritten);
+ continue;
+ }
+
+ return path;
+ }
+
+ // Cycle guard tripped — surface as a lookup miss.
+ return {};
+ }
}