step 5
This commit is contained in:
@@ -48,6 +48,9 @@ RuntimeUpdateController::RuntimeUpdateController(
|
|||||||
mRuntimeEventDispatcher.Subscribe(
|
mRuntimeEventDispatcher.Subscribe(
|
||||||
RuntimeEventType::RuntimeReloadRequested,
|
RuntimeEventType::RuntimeReloadRequested,
|
||||||
[this](const RuntimeEvent& event) { HandleRuntimeReloadRequested(event); });
|
[this](const RuntimeEvent& event) { HandleRuntimeReloadRequested(event); });
|
||||||
|
mRuntimeEventDispatcher.Subscribe(
|
||||||
|
RuntimeEventType::RuntimePersistenceRequested,
|
||||||
|
[this](const RuntimeEvent& event) { HandleRuntimePersistenceRequested(event); });
|
||||||
mRuntimeEventDispatcher.Subscribe(
|
mRuntimeEventDispatcher.Subscribe(
|
||||||
RuntimeEventType::ShaderBuildRequested,
|
RuntimeEventType::ShaderBuildRequested,
|
||||||
[this](const RuntimeEvent& event) { HandleShaderBuildRequested(event); });
|
[this](const RuntimeEvent& event) { HandleShaderBuildRequested(event); });
|
||||||
@@ -158,6 +161,16 @@ void RuntimeUpdateController::HandleRuntimeReloadRequested(const RuntimeEvent& e
|
|||||||
mRuntimeStore.ClearReloadRequest();
|
mRuntimeStore.ClearReloadRequest();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RuntimeUpdateController::HandleRuntimePersistenceRequested(const RuntimeEvent& event)
|
||||||
|
{
|
||||||
|
const RuntimePersistenceRequestedEvent* payload = std::get_if<RuntimePersistenceRequestedEvent>(&event.payload);
|
||||||
|
if (!payload)
|
||||||
|
return;
|
||||||
|
|
||||||
|
std::string error;
|
||||||
|
mRuntimeStore.RequestPersistence(payload->request, error);
|
||||||
|
}
|
||||||
|
|
||||||
void RuntimeUpdateController::HandleShaderBuildRequested(const RuntimeEvent& event)
|
void RuntimeUpdateController::HandleShaderBuildRequested(const RuntimeEvent& event)
|
||||||
{
|
{
|
||||||
const ShaderBuildEvent* payload = std::get_if<ShaderBuildEvent>(&event.payload);
|
const ShaderBuildEvent* payload = std::get_if<ShaderBuildEvent>(&event.payload);
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
void HandleRuntimeStateBroadcastRequested(const RuntimeEvent& event);
|
void HandleRuntimeStateBroadcastRequested(const RuntimeEvent& event);
|
||||||
void HandleRuntimeReloadRequested(const RuntimeEvent& event);
|
void HandleRuntimeReloadRequested(const RuntimeEvent& event);
|
||||||
|
void HandleRuntimePersistenceRequested(const RuntimeEvent& event);
|
||||||
void HandleShaderBuildRequested(const RuntimeEvent& event);
|
void HandleShaderBuildRequested(const RuntimeEvent& event);
|
||||||
void HandleShaderBuildPrepared(const RuntimeEvent& event);
|
void HandleShaderBuildPrepared(const RuntimeEvent& event);
|
||||||
void HandleShaderBuildFailed(const RuntimeEvent& event);
|
void HandleShaderBuildFailed(const RuntimeEvent& event);
|
||||||
|
|||||||
@@ -43,7 +43,6 @@ std::string PersistenceTargetKindName(PersistenceTargetKind targetKind)
|
|||||||
|
|
||||||
RuntimeStore::RuntimeStore() :
|
RuntimeStore::RuntimeStore() :
|
||||||
mRenderSnapshotBuilder(*this),
|
mRenderSnapshotBuilder(*this),
|
||||||
mHealthTelemetry(),
|
|
||||||
mReloadRequested(false),
|
mReloadRequested(false),
|
||||||
mCompileSucceeded(false),
|
mCompileSucceeded(false),
|
||||||
mStartupRandom(GenerateStartupRandom()),
|
mStartupRandom(GenerateStartupRandom()),
|
||||||
@@ -128,6 +127,35 @@ PersistenceSnapshot RuntimeStore::BuildRuntimeStatePersistenceSnapshot(const Per
|
|||||||
return BuildRuntimeStatePersistenceSnapshotLocked(request);
|
return BuildRuntimeStatePersistenceSnapshotLocked(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool RuntimeStore::RequestPersistence(const PersistenceRequest& request, std::string& error)
|
||||||
|
{
|
||||||
|
if (request.targetKind != PersistenceTargetKind::RuntimeState)
|
||||||
|
{
|
||||||
|
error = "Unsupported persistence request target: " + PersistenceTargetKindName(request.targetKind);
|
||||||
|
mHealthTelemetry.RecordPersistenceWriteResult(
|
||||||
|
false,
|
||||||
|
PersistenceTargetKindName(request.targetKind),
|
||||||
|
std::string(),
|
||||||
|
request.reason,
|
||||||
|
error,
|
||||||
|
false);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const PersistenceSnapshot snapshot = BuildRuntimeStatePersistenceSnapshot(request);
|
||||||
|
if (mPersistenceWriter.EnqueueSnapshot(snapshot, error))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
mHealthTelemetry.RecordPersistenceWriteResult(
|
||||||
|
false,
|
||||||
|
PersistenceTargetKindName(request.targetKind),
|
||||||
|
snapshot.targetPath.string(),
|
||||||
|
request.reason,
|
||||||
|
error,
|
||||||
|
false);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
PersistenceSnapshot RuntimeStore::BuildRuntimeStatePersistenceSnapshotLocked(const PersistenceRequest& request) const
|
PersistenceSnapshot RuntimeStore::BuildRuntimeStatePersistenceSnapshotLocked(const PersistenceRequest& request) const
|
||||||
{
|
{
|
||||||
PersistenceSnapshot snapshot;
|
PersistenceSnapshot snapshot;
|
||||||
@@ -211,7 +239,7 @@ bool RuntimeStore::CreateStoredLayer(const std::string& shaderId, std::string& e
|
|||||||
|
|
||||||
mReloadRequested = true;
|
mReloadRequested = true;
|
||||||
MarkRenderStateDirtyLocked();
|
MarkRenderStateDirtyLocked();
|
||||||
return SavePersistentState(error);
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RuntimeStore::DeleteStoredLayer(const std::string& layerId, std::string& error)
|
bool RuntimeStore::DeleteStoredLayer(const std::string& layerId, std::string& error)
|
||||||
@@ -222,7 +250,7 @@ bool RuntimeStore::DeleteStoredLayer(const std::string& layerId, std::string& er
|
|||||||
|
|
||||||
mReloadRequested = true;
|
mReloadRequested = true;
|
||||||
MarkRenderStateDirtyLocked();
|
MarkRenderStateDirtyLocked();
|
||||||
return SavePersistentState(error);
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RuntimeStore::MoveStoredLayer(const std::string& layerId, int direction, std::string& error)
|
bool RuntimeStore::MoveStoredLayer(const std::string& layerId, int direction, std::string& error)
|
||||||
@@ -239,7 +267,7 @@ bool RuntimeStore::MoveStoredLayer(const std::string& layerId, int direction, st
|
|||||||
|
|
||||||
mReloadRequested = true;
|
mReloadRequested = true;
|
||||||
MarkRenderStateDirtyLocked();
|
MarkRenderStateDirtyLocked();
|
||||||
return SavePersistentState(error);
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RuntimeStore::MoveStoredLayerToIndex(const std::string& layerId, std::size_t targetIndex, std::string& error)
|
bool RuntimeStore::MoveStoredLayerToIndex(const std::string& layerId, std::size_t targetIndex, std::string& error)
|
||||||
@@ -256,7 +284,7 @@ bool RuntimeStore::MoveStoredLayerToIndex(const std::string& layerId, std::size_
|
|||||||
|
|
||||||
mReloadRequested = true;
|
mReloadRequested = true;
|
||||||
MarkRenderStateDirtyLocked();
|
MarkRenderStateDirtyLocked();
|
||||||
return SavePersistentState(error);
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RuntimeStore::SetStoredLayerBypassState(const std::string& layerId, bool bypassed, std::string& error)
|
bool RuntimeStore::SetStoredLayerBypassState(const std::string& layerId, bool bypassed, std::string& error)
|
||||||
@@ -267,7 +295,7 @@ bool RuntimeStore::SetStoredLayerBypassState(const std::string& layerId, bool by
|
|||||||
|
|
||||||
mReloadRequested = true;
|
mReloadRequested = true;
|
||||||
MarkParameterStateDirtyLocked();
|
MarkParameterStateDirtyLocked();
|
||||||
return SavePersistentState(error);
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RuntimeStore::SetStoredLayerShaderSelection(const std::string& layerId, const std::string& shaderId, std::string& error)
|
bool RuntimeStore::SetStoredLayerShaderSelection(const std::string& layerId, const std::string& shaderId, std::string& error)
|
||||||
@@ -278,18 +306,19 @@ bool RuntimeStore::SetStoredLayerShaderSelection(const std::string& layerId, con
|
|||||||
|
|
||||||
mReloadRequested = true;
|
mReloadRequested = true;
|
||||||
MarkRenderStateDirtyLocked();
|
MarkRenderStateDirtyLocked();
|
||||||
return SavePersistentState(error);
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RuntimeStore::SetStoredParameterValue(const std::string& layerId, const std::string& parameterId, const ShaderParameterValue& value, bool persistState, std::string& error)
|
bool RuntimeStore::SetStoredParameterValue(const std::string& layerId, const std::string& parameterId, const ShaderParameterValue& value, bool persistState, std::string& error)
|
||||||
{
|
{
|
||||||
|
(void)persistState;
|
||||||
std::lock_guard<std::mutex> lock(mMutex);
|
std::lock_guard<std::mutex> lock(mMutex);
|
||||||
|
|
||||||
if (!mCommittedLiveState.SetParameterValue(layerId, parameterId, value, error))
|
if (!mCommittedLiveState.SetParameterValue(layerId, parameterId, value, error))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
MarkParameterStateDirtyLocked();
|
MarkParameterStateDirtyLocked();
|
||||||
return !persistState || SavePersistentState(error);
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RuntimeStore::ResetStoredLayerParameterValues(const std::string& layerId, std::string& error)
|
bool RuntimeStore::ResetStoredLayerParameterValues(const std::string& layerId, std::string& error)
|
||||||
@@ -300,7 +329,7 @@ bool RuntimeStore::ResetStoredLayerParameterValues(const std::string& layerId, s
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
MarkParameterStateDirtyLocked();
|
MarkParameterStateDirtyLocked();
|
||||||
return SavePersistentState(error);
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RuntimeStore::SaveStackPresetSnapshot(const std::string& presetName, std::string& error) const
|
bool RuntimeStore::SaveStackPresetSnapshot(const std::string& presetName, std::string& error) const
|
||||||
@@ -340,7 +369,7 @@ bool RuntimeStore::LoadStackPresetSnapshot(const std::string& presetName, std::s
|
|||||||
|
|
||||||
mReloadRequested = true;
|
mReloadRequested = true;
|
||||||
MarkRenderStateDirtyLocked();
|
MarkRenderStateDirtyLocked();
|
||||||
return SavePersistentState(error);
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RuntimeStore::HasStoredLayer(const std::string& layerId) const
|
bool RuntimeStore::HasStoredLayer(const std::string& layerId) const
|
||||||
@@ -503,11 +532,6 @@ bool RuntimeStore::LoadPersistentState(std::string& error)
|
|||||||
return mCommittedLiveState.LoadPersistentStateValue(root);
|
return mCommittedLiveState.LoadPersistentStateValue(root);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RuntimeStore::SavePersistentState(std::string& error) const
|
|
||||||
{
|
|
||||||
return mPersistenceWriter.EnqueueSnapshot(BuildRuntimeStatePersistenceSnapshotLocked(PersistenceRequest::RuntimeStateRequest("SavePersistentState")), error);
|
|
||||||
}
|
|
||||||
|
|
||||||
PersistenceSnapshot RuntimeStore::BuildStackPresetPersistenceSnapshot(const std::string& presetName) const
|
PersistenceSnapshot RuntimeStore::BuildStackPresetPersistenceSnapshot(const std::string& presetName) const
|
||||||
{
|
{
|
||||||
const std::string safeStem = LayerStackStore::MakeSafePresetFileStem(presetName);
|
const std::string safeStem = LayerStackStore::MakeSafePresetFileStem(presetName);
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ public:
|
|||||||
bool InitializeStore(std::string& error);
|
bool InitializeStore(std::string& error);
|
||||||
std::string BuildPersistentStateJson() const;
|
std::string BuildPersistentStateJson() const;
|
||||||
PersistenceSnapshot BuildRuntimeStatePersistenceSnapshot(const PersistenceRequest& request) const;
|
PersistenceSnapshot BuildRuntimeStatePersistenceSnapshot(const PersistenceRequest& request) const;
|
||||||
|
bool RequestPersistence(const PersistenceRequest& request, std::string& error);
|
||||||
bool PollStoredFileChanges(bool& registryChanged, bool& reloadRequested, std::string& error);
|
bool PollStoredFileChanges(bool& registryChanged, bool& reloadRequested, std::string& error);
|
||||||
|
|
||||||
bool CreateStoredLayer(const std::string& shaderId, std::string& error);
|
bool CreateStoredLayer(const std::string& shaderId, std::string& error);
|
||||||
@@ -83,7 +84,6 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
bool LoadPersistentState(std::string& error);
|
bool LoadPersistentState(std::string& error);
|
||||||
bool SavePersistentState(std::string& error) const;
|
|
||||||
PersistenceSnapshot BuildRuntimeStatePersistenceSnapshotLocked(const PersistenceRequest& request) const;
|
PersistenceSnapshot BuildRuntimeStatePersistenceSnapshotLocked(const PersistenceRequest& request) const;
|
||||||
PersistenceSnapshot BuildStackPresetPersistenceSnapshot(const std::string& presetName) const;
|
PersistenceSnapshot BuildStackPresetPersistenceSnapshot(const std::string& presetName) const;
|
||||||
bool ScanShaderPackages(std::string& error);
|
bool ScanShaderPackages(std::string& error);
|
||||||
@@ -93,11 +93,11 @@ private:
|
|||||||
void MarkParameterStateDirtyLocked();
|
void MarkParameterStateDirtyLocked();
|
||||||
|
|
||||||
RenderSnapshotBuilder mRenderSnapshotBuilder;
|
RenderSnapshotBuilder mRenderSnapshotBuilder;
|
||||||
mutable PersistenceWriter mPersistenceWriter;
|
|
||||||
RuntimeConfigStore mConfigStore;
|
RuntimeConfigStore mConfigStore;
|
||||||
ShaderPackageCatalog mShaderCatalog;
|
ShaderPackageCatalog mShaderCatalog;
|
||||||
CommittedLiveState mCommittedLiveState;
|
CommittedLiveState mCommittedLiveState;
|
||||||
HealthTelemetry mHealthTelemetry;
|
HealthTelemetry mHealthTelemetry;
|
||||||
|
mutable PersistenceWriter mPersistenceWriter;
|
||||||
mutable std::mutex mMutex;
|
mutable std::mutex mMutex;
|
||||||
bool mReloadRequested;
|
bool mReloadRequested;
|
||||||
bool mCompileSucceeded;
|
bool mCompileSucceeded;
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ Phases 1-5 separate durable state, coordination policy, render-facing snapshots,
|
|||||||
## Status
|
## Status
|
||||||
|
|
||||||
- Phase 6 design package: proposed.
|
- Phase 6 design package: proposed.
|
||||||
- Phase 6 implementation: Step 4 complete.
|
- Phase 6 implementation: Step 5 complete.
|
||||||
- Current alignment: `RuntimeStore` owns durable serialization, config, package metadata, preset IO, and persistence requests; `CommittedLiveState` owns the current committed/session layer state; and `RuntimeCoordinator` publishes typed persistence requests for persisted mutations. The remaining issue is that actual disk writes are still synchronous store work rather than queued, debounced, atomic background writes.
|
- Current alignment: `RuntimeStore` owns durable serialization, config, package metadata, preset IO, and persistence request execution; `CommittedLiveState` owns the current committed/session layer state; and `RuntimeCoordinator` publishes typed persistence requests for persisted mutations. Runtime-state persistence is now requested through the coordinator/event path and executed by the background writer.
|
||||||
|
|
||||||
Current persistence footholds:
|
Current persistence footholds:
|
||||||
|
|
||||||
@@ -252,9 +252,17 @@ Route `RuntimePersistenceRequested` or coordinator persistence outcomes into the
|
|||||||
|
|
||||||
Initial target:
|
Initial target:
|
||||||
|
|
||||||
- accepted durable mutations request persistence
|
- [x] accepted durable mutations request persistence
|
||||||
- transient-only mutations do not
|
- [x] transient-only mutations do not
|
||||||
- runtime reload/preset policies remain explicit
|
- [x] runtime reload/preset policies remain explicit
|
||||||
|
|
||||||
|
Current implementation:
|
||||||
|
|
||||||
|
- Store mutation methods update committed durable/session state and mark render state dirty, but no longer enqueue runtime-state writes directly.
|
||||||
|
- `RuntimeCoordinator` remains the owner of the persistence decision and publishes `RuntimePersistenceRequested` only for accepted durable mutations.
|
||||||
|
- `RuntimeUpdateController` handles `RuntimePersistenceRequested` and calls `RuntimeStore::RequestPersistence(...)`.
|
||||||
|
- `RuntimeStore::RequestPersistence(...)` validates the request target, builds the runtime-state snapshot, enqueues it on `PersistenceWriter`, and records enqueue failures in `HealthTelemetry`.
|
||||||
|
- Stack preset save remains a synchronous preset-file write; preset load updates state and relies on the coordinator persistence request for runtime-state persistence.
|
||||||
|
|
||||||
### Step 6. Define Shutdown Flush
|
### Step 6. Define Shutdown Flush
|
||||||
|
|
||||||
@@ -307,14 +315,14 @@ Operator-triggered preset save often feels like it should complete before report
|
|||||||
|
|
||||||
Phase 6 can be considered complete once the project can say:
|
Phase 6 can be considered complete once the project can say:
|
||||||
|
|
||||||
- [ ] durable mutations enqueue persistence instead of directly writing from mutation paths
|
- [x] durable mutations enqueue persistence instead of directly writing from mutation paths
|
||||||
- [ ] runtime-state writes are debounced/coalesced
|
- [x] runtime-state writes are debounced/coalesced
|
||||||
- [ ] writes use temp-file/replace or equivalent atomic policy
|
- [x] writes use temp-file/replace or equivalent atomic policy
|
||||||
- [ ] persistence failures are reported through structured health/events
|
- [x] persistence failures are reported through structured health/events
|
||||||
- [ ] transient/live-only mutations do not request persistence
|
- [x] transient/live-only mutations do not request persistence
|
||||||
- [ ] shutdown flush behavior is explicit and tested
|
- [ ] shutdown flush behavior is explicit and tested
|
||||||
- [ ] `RuntimeStore` remains durable-state/serialization owner, not worker policy owner
|
- [x] `RuntimeStore` remains durable-state/serialization owner, not worker policy owner
|
||||||
- [ ] persistence behavior has focused non-render tests
|
- [x] persistence behavior has focused non-render tests
|
||||||
|
|
||||||
## Open Questions
|
## Open Questions
|
||||||
|
|
||||||
|
|||||||
@@ -242,6 +242,12 @@ void TestRuntimeCoordinatorPersistenceEvents()
|
|||||||
Expect(snapshot.reason == "unit-test", "runtime-state persistence snapshot preserves request reason");
|
Expect(snapshot.reason == "unit-test", "runtime-state persistence snapshot preserves request reason");
|
||||||
Expect(snapshot.targetPath.filename().string() == "runtime_state.json", "runtime-state persistence snapshot targets the runtime state file");
|
Expect(snapshot.targetPath.filename().string() == "runtime_state.json", "runtime-state persistence snapshot targets the runtime state file");
|
||||||
Expect(snapshot.contents.find("\"layers\"") != std::string::npos, "runtime-state persistence snapshot contains serialized layer state");
|
Expect(snapshot.contents.find("\"layers\"") != std::string::npos, "runtime-state persistence snapshot contains serialized layer state");
|
||||||
|
Expect(store.RequestPersistence(PersistenceRequest::RuntimeStateRequest("unit-test-request"), error),
|
||||||
|
"runtime store accepts runtime-state persistence requests");
|
||||||
|
PersistenceRequest unsupportedRequest;
|
||||||
|
unsupportedRequest.targetKind = PersistenceTargetKind::StackPreset;
|
||||||
|
unsupportedRequest.reason = "unsupported-unit-test";
|
||||||
|
Expect(!store.RequestPersistence(unsupportedRequest, error), "runtime store rejects unsupported persistence request targets");
|
||||||
|
|
||||||
RuntimeEventDispatcher dispatcher(64);
|
RuntimeEventDispatcher dispatcher(64);
|
||||||
std::vector<RuntimeEvent> seenEvents;
|
std::vector<RuntimeEvent> seenEvents;
|
||||||
|
|||||||
Reference in New Issue
Block a user