载入中...
搜索中...
未找到
RuntimeSnapshot.h
浏览该文件的文档.
1#pragma once
2
13#include "common/Snapshot.h"
15
16#include <charconv>
17#include <cstdint>
18#include <functional>
19#include <set>
20#include <string>
21#include <string_view>
22
23namespace eve::definition {
24
26template <class State>
27using RuntimeStateEncoder = std::function<eve::Result<eve::Value>(const State&)>;
28
30template <class State>
31using RuntimeStateDecoder = std::function<eve::Result<State>(const eve::Value&)>;
32
33namespace detail {
34
37 const auto text = value.getIf<std::string>();
38 if (text == nullptr || text->empty())
42 eve::Diagnostic::error(eve::DiagnosticCode::ParseError, "runtime snapshot integer must be a decimal string",
44 std::string(path), {}, "common.definitions.snapshot"));
45 std::uint64_t result = 0;
46 const auto [end, error] = std::from_chars(text->data(), text->data() + text->size(), result);
47 if (error != std::errc{} || end != text->data() + text->size())
51 eve::Diagnostic::error(eve::DiagnosticCode::ParseError, "runtime snapshot integer is out of range",
53 std::string(path), {}, "common.definitions.snapshot"));
56}
57
60 static const std::set<std::string> fields = {"active", "definition", "definitionGeneration", "instanceId", "state"};
61 for (const auto& [name, unused] : object) {
62 (void)unused;
63 if (!fields.contains(name))
66 eve::DiagnosticCode::ParseError, "runtime snapshot payload contains an unknown field", "state." + name,
67 {}, "common.definitions.snapshot"));
68 }
69 for (const auto& name : fields) {
70 if (!object.contains(name))
73 eve::DiagnosticCode::ParseError, "runtime snapshot payload is missing a required field",
74 "state." + name, {}, "common.definitions.snapshot"));
75 }
78}
79
80} // namespace detail
81
94template <class State>
97 const RuntimeInstance<State>& runtime, std::string type, eve::LogicalId schema, eve::SchemaVersion schemaVersion,
99 const RuntimeStateEncoder<State>& encode) {
100 if (!encode)
104 eve::Diagnostic::error(eve::DiagnosticCode::InvalidArgument, "runtime snapshot encoder is required",
105 "encode", {}, "common.definitions.snapshot"));
106 auto encoded = encode(runtime.state());
107 if (!encoded) return eve::Result<eve::SnapshotEnvelope>::failure(encoded.status());
109 payload.emplace("active", eve::Value(runtime.isActive()));
110 payload.emplace("definition", eve::Value(runtime.identity().definition.format()));
111 payload.emplace("definitionGeneration",
113 eve::Value(std::to_string(runtime.identity().definitionGeneration.value())));
114 payload.emplace("instanceId", eve::Value(runtime.identity().instanceId.format()));
115 payload.emplace("state", std::move(encoded).takeValue());
117 return eve::makeSnapshotEnvelope(std::move(type), std::move(schema), schemaVersion, runtime.identity().instanceId,
118 revision, tick, eve::Value(std::move(payload)), hashProvider);
119}
120
133template <class State>
136 RuntimeInstance<State>& runtime, const eve::SnapshotEnvelope& snapshot, std::string_view expectedType,
137 const eve::LogicalId& expectedSchema, eve::SchemaVersion expectedVersion,
138 const eve::SnapshotHashProvider& hashProvider, const RuntimeStateDecoder<State>& decode) {
139 if (snapshot.type != expectedType || snapshot.schema != expectedSchema)
142 "runtime snapshot type or schema does not match",
143 "schema", {}, "common.definitions.snapshot"));
144 if (snapshot.schemaVersion != expectedVersion)
147 snapshot.schemaVersion > expectedVersion ? eve::DiagnosticCode::UnknownVersion
149 "runtime snapshot schema version is not supported", "schemaVersion", {}, "common.definitions.snapshot"));
150 auto verified = eve::verifySnapshotEnvelope(snapshot, hashProvider);
151 if (!verified) return verified;
152 auto metadata = eve::validateSnapshotPayloadMetadata(snapshot.payload, snapshot.revision, snapshot.tick);
153 if (!metadata) return metadata;
154 const auto object = snapshot.payload.getIf<eve::Value::Object>();
155 if (object == nullptr) {
158 "runtime snapshot payload must be an object",
159 "payload", {}, "common.definitions.snapshot"));
160 }
161 auto shape = detail::runtimeSnapshotShape(*object);
162 if (!shape) return shape;
163
164 const auto active = object->at("active").getIf<bool>();
165 const auto definitionText = object->at("definition").getIf<std::string>();
166 const auto instanceText = object->at("instanceId").getIf<std::string>();
167 if (active == nullptr || definitionText == nullptr || instanceText == nullptr)
170 "runtime snapshot identity fields have invalid types",
171 "payload", {}, "common.definitions.snapshot"));
172 const auto instanceId = eve::PersistentId::parse(*instanceText);
173 if (!instanceId)
177 eve::Diagnostic::error(eve::DiagnosticCode::ParseError, "runtime snapshot instanceId is invalid",
178 "payload.instanceId", {}, "common.definitions.snapshot"));
179 auto definition = eve::DefinitionRef::parse(*definitionText);
180 if (!definition) return eve::Result<void>::failure(definition.status());
181 auto generation = detail::runtimeSnapshotUint(object->at("definitionGeneration"), "payload.definitionGeneration");
182 if (!generation) return eve::Result<void>::failure(generation.status());
183 const eve::definition::InstanceIdentity identity{*instanceId, std::move(definition).takeValue(),
185 eve::Generation(std::move(generation).takeValue())};
186 if (snapshot.instanceId != identity.instanceId || identity.instanceId != runtime.identity().instanceId)
189 eve::DiagnosticCode::Conflict, "runtime snapshot instanceId does not match the destination",
190 "payload.instanceId", {}, "common.definitions.snapshot"));
191 if (identity.definition != runtime.identity().definition)
194 eve::DiagnosticCode::Conflict, "runtime snapshot definition reference does not match", "payload.definition",
195 {}, "common.definitions.snapshot"));
196 if (identity.definitionGeneration != runtime.identity().definitionGeneration)
199 eve::DiagnosticCode::StaleHandle, "runtime snapshot definition generation does not match the destination",
200 "payload.definitionGeneration", {}, "common.definitions.snapshot"));
201 if (!decode)
204 "runtime snapshot decoder is required", "decode", {},
205 "common.definitions.snapshot"));
206 auto candidate = decode(object->at("state"));
207 if (!candidate) return eve::Result<void>::failure(candidate.status());
208 return runtime.restoreExact(identity, std::move(candidate).takeValue(), *active);
209}
210
211} // namespace eve::definition
double value
Value::Object payload
bool & active
Common identity and hot-reload contract for typed runtime instances.
ShaderImageInput shape
std::string text
std::string name
std::string error
Definition Package.cpp:60
std::uint64_t revision
std::string path
Definition PlayHost.cpp:110
std::vector< std::string > fields
Definition PlayHost.cpp:111
std::uint32_t generation
int detail
Versioned, integrity-checked persistence envelopes.
SimulationTick tick
Json object
static Result< DefinitionRef > parse(std::string_view text)
Parse a namespace:name logical definition identifier.
static Diagnostic error(DiagnosticCode code, std::string message, std::string path={}, DiagnosticDetails details={}, std::string source={})
Construct an error diagnostic with the standard error severity.
Definition Diagnostic.h:125
Human-readable, scoped identifier in the form namespace:name.
Definition Identity.h:411
Move-only operation result carrying either a value or Status.
Definition Result.h:155
static Result success(T value)
Construct a successful result owning value.
Definition Result.h:164
static Result failure(Status status)
Construct a failed result from a structured status.
Definition Result.h:175
The canonical owning dynamic value used by data-facing protocols.
Definition Value.h:31
std::map< std::string, Value > Object
Definition Value.h:34
const T * getIf() const noexcept
Return a typed pointer, or nullptr when the kind differs.
Definition Value.h:180
Owns one strongly typed runtime state and its definition identity.
static std::optional< Id128 > parse(std::string_view text) noexcept
Parses canonical UUID text.
Definition Identity.h:151
eve::Result< void > runtimeSnapshotShape(const eve::Value::Object &object)
Runtime snapshot shape.
eve::Result< std::uint64_t > runtimeSnapshotUint(const eve::Value &value, std::string_view path)
Runtime snapshot uint.
eve::Result< eve::SnapshotEnvelope > snapshotRuntimeInstance(const RuntimeInstance< State > &runtime, std::string type, eve::LogicalId schema, eve::SchemaVersion schemaVersion, eve::Revision revision, eve::SimulationTick tick, const eve::SnapshotHashProvider &hashProvider, const RuntimeStateEncoder< State > &encode)
Capture a typed runtime instance in the common snapshot envelope.
eve::Result< void > restoreRuntimeInstance(RuntimeInstance< State > &runtime, const eve::SnapshotEnvelope &snapshot, std::string_view expectedType, const eve::LogicalId &expectedSchema, eve::SchemaVersion expectedVersion, const eve::SnapshotHashProvider &hashProvider, const RuntimeStateDecoder< State > &decode)
Verify and atomically restore a typed runtime instance.
std::function< eve::Result< State >(const eve::Value &)> RuntimeStateDecoder
Decodes one domain-owned runtime state from an owning Value.
std::function< eve::Result< eve::Value >(const State &)> RuntimeStateEncoder
Converts one domain-owned runtime state into an owning Value.
detail::StrongUint64< detail::GenerationTag > Generation
Registry/object replacement generation used to reject stale handles.
Definition Generation.h:13
Result< void > validateSnapshotPayloadMetadata(const Value &payload, Revision revision, SimulationTick tick)
Validate optional payload copies of envelope revision and tick.
Definition Snapshot.cpp:80
Result< SnapshotEnvelope > makeSnapshotEnvelope(std::string type, LogicalId schema, SchemaVersion schemaVersion, PersistentId instanceId, Revision revision, SimulationTick tick, Value payload, const SnapshotHashProvider &hashProvider)
Construct and seal a snapshot envelope.
Definition Snapshot.cpp:103
Result< void > verifySnapshotEnvelope(const SnapshotEnvelope &snapshot, const SnapshotHashProvider &hashProvider)
Verify an envelope's content hash without modifying it.
Definition Snapshot.cpp:63
std::function< Result< ContentId >(std::string_view canonicalInput)> SnapshotHashProvider
Injected content-digest implementation used by snapshots.
Definition Snapshot.h:36
Stable outer format shared by persistence and cross-process snapshots.
Definition Snapshot.h:46
SchemaVersion schemaVersion
Definition Snapshot.h:49
std::string type
Definition Snapshot.h:47
PersistentId instanceId
Definition Snapshot.h:50
SimulationTick tick
Definition Snapshot.h:52
Canonical identity carried by every typed runtime instance.