10#include <unordered_map>
11#include <unordered_set>
15#include "../model.hpp"
18namespace morph::backend::detail {
28enum class Hydration : std::uint8_t {
49struct HydrationState {
51 std::atomic<Hydration> phase{Hydration::pending};
60 void settle(
bool succeeded)
noexcept {
61 Hydration expected = Hydration::pending;
62 phase.compare_exchange_strong(expected, succeeded ? Hydration::healthy : Hydration::poisoned);
67 [[nodiscard]]
bool poisoned() const noexcept {
return phase.load() == Hydration::poisoned; }
71using DirectoryKey = std::pair<std::string, std::string>;
80struct DirectoryKeyHash {
84 [[nodiscard]] std::size_t operator()(
const DirectoryKey& key)
const noexcept {
85 std::size_t seed = std::hash<std::string>{}(key.first);
87 seed ^= std::hash<std::string>{}(key.second) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
100 std::shared_ptr<::morph::model::detail::IModelHolder> holder;
114 std::size_t attachCount = 0;
117 std::optional<DirectoryKey> sharedKey;
130 std::shared_ptr<HydrationState> hydration;
150class InstanceDirectory {
153 enum class Release : std::uint8_t {
167 [[nodiscard]]
const Instance* find(::morph::exec::detail::ModelId mid)
const {
168 auto iter = _instances.find(mid);
169 return iter == _instances.end() ? nullptr : &iter->second;
174 [[nodiscard]] std::size_t size() const noexcept {
return _instances.size(); }
180 void insertPrivate(::morph::exec::detail::ModelId mid,
181 std::shared_ptr<::morph::model::detail::IModelHolder> holder, std::string owner = {}) {
182 _instances.insert_or_assign(mid, Instance{.holder = std::move(holder), .owner = std::move(owner)});
183 MORPH_PLOT(
"RemoteServer::liveModels", _instances.size());
195 void insertShared(::morph::exec::detail::ModelId mid, std::shared_ptr<::morph::model::detail::IModelHolder> holder,
196 DirectoryKey key, std::string owner = {}) {
198 _instances.insert_or_assign(mid, Instance{.holder = std::move(holder),
199 .owner = std::move(owner),
201 .sharedKey = std::move(key),
202 .hydration = std::make_shared<HydrationState>()});
203 MORPH_PLOT(
"RemoteServer::liveModels", _instances.size());
215 [[nodiscard]] std::optional<::morph::exec::detail::ModelId> attach(
const DirectoryKey& key) {
216 auto keyIter = _byKey.find(key);
217 if (keyIter == _byKey.end()) {
220 auto const mid = keyIter->second;
221 Instance& inst = _instances.at(mid);
222 if (inst.hydration && inst.hydration->poisoned()) {
224 inst.sharedKey.reset();
227 inst.attachCount += 1;
266 bool promote(::morph::exec::detail::ModelId mid, DirectoryKey key) {
267 auto instIter = _instances.find(mid);
268 if (instIter == _instances.end() || _byKey.contains(key)) {
272 if (inst.sharedKey.has_value() || inst.hydration) {
276 inst.sharedKey = std::move(key);
281 inst.attachCount = 1;
292 Release release(::morph::exec::detail::ModelId mid) {
293 auto instIter = _instances.find(mid);
294 if (instIter == _instances.end()) {
295 return Release::retained;
298 if (inst.attachCount > 0) {
299 inst.attachCount -= 1;
300 if (inst.attachCount > 0) {
301 return Release::retained;
303 if (inst.sharedKey) {
304 unindexKey(*inst.sharedKey);
307 _instances.erase(instIter);
308 MORPH_PLOT(
"RemoteServer::liveModels", _instances.size());
309 return Release::destroyed;
319 [[nodiscard]] std::vector<std::string> keysOfType(
const std::string& typeId)
const {
320 auto typeIter = _byType.find(typeId);
321 if (typeIter == _byType.end()) {
324 return {typeIter->second.begin(), typeIter->second.end()};
331 void indexKey(
const DirectoryKey& key, ::morph::exec::detail::ModelId mid) {
332 _byKey.emplace(key, mid);
333 _byType[key.first].insert(key.second);
338 void unindexKey(
const DirectoryKey& key) {
347 if (
auto typeIter = _byType.find(key.first); typeIter != _byType.end()) {
348 typeIter->second.erase(key.second);
349 if (typeIter->second.empty()) {
350 _byType.erase(typeIter);
356 std::unordered_map<::morph::exec::detail::ModelId, Instance, ::morph::exec::detail::ModelIdHash> _instances;
359 std::unordered_map<DirectoryKey, ::morph::exec::detail::ModelId, DirectoryKeyHash> _byKey;
362 std::unordered_map<std::string, std::unordered_set<std::string>> _byType;
Instance
How a model alias binds when no key expression is given (spec 5 §5).
Compile-time profiler instrumentation: Tracy zones, plots, messages and thread names,...
#define MORPH_PLOT(name, value)
Records value on the plot named name.