载入中...
搜索中...
未找到
ProductionAdvanced.cpp
浏览该文件的文档.
2
3#include <algorithm>
4#include <limits>
5
6namespace eve::production {
7namespace {
8
9template <class T>
10eve::Result<T> advancedFailure(eve::DiagnosticCode code, std::string message, std::string path = {}) {
12 eve::Diagnostic::error(code, message, path, {}, "production.advanced"));
13}
14
15eve::Result<std::int64_t> scaledRemaining(const ProductionTask& task) {
16 const auto remaining = task.duration.nanoseconds() - task.progress.nanoseconds();
17 const auto efficiency = static_cast<std::int64_t>(task.efficiencyPermille);
18 if (remaining <= 0) return eve::Result<std::int64_t>::success(0);
19 const auto whole = remaining / efficiency;
20 if (whole > std::numeric_limits<std::int64_t>::max() / 1000)
21 return advancedFailure<std::int64_t>(eve::DiagnosticCode::InvalidArgument,
22 "production remaining time is not representable");
23 const auto residualNumerator = (remaining % efficiency) * 1000 - task.workRemainderPermille;
24 const auto residual = residualNumerator <= 0 ? 0 : (residualNumerator + efficiency - 1) / efficiency;
25 const auto base = whole * 1000;
26 if (base > std::numeric_limits<std::int64_t>::max() - residual)
27 return advancedFailure<std::int64_t>(eve::DiagnosticCode::InvalidArgument,
28 "production remaining time is not representable");
29 return eve::Result<std::int64_t>::success(base + residual);
30}
31
32} // namespace
33
34SchedulerStrategy WorkQueue::schedulerStrategy(std::string_view owner) const {
35 const auto it = std::lower_bound(schedulerStrategies_.begin(), schedulerStrategies_.end(), owner,
36 [](const auto& entry, std::string_view key) { return entry.first < key; });
37 return it != schedulerStrategies_.end() && it->first == owner ? it->second : SchedulerStrategy::Priority;
38}
39
41 std::string_view owner, const eve::definition::DefinitionHandle& definition) const {
42 const auto key = std::tuple(std::string(owner), definition.reference.id().format(), definition.generation.value());
43 return std::binary_search(availableDefinitions_.begin(), availableDefinitions_.end(), key);
44}
45
46bool WorkQueue::tagAvailable(std::string_view owner, std::string_view tag) const {
47 return std::binary_search(availableTags_.begin(), availableTags_.end(),
48 std::pair(std::string(owner), std::string(tag)));
49}
50
52 std::string_view owner, const eve::definition::DefinitionHandle& definition, bool available) {
53 if (owner.empty() || !definition.isValid())
54 return advancedFailure<void>(eve::DiagnosticCode::InvalidArgument,
55 "definition availability needs an owner and valid handle");
56 const auto key = std::tuple(std::string(owner), definition.reference.id().format(), definition.generation.value());
57 auto it = std::lower_bound(availableDefinitions_.begin(), availableDefinitions_.end(), key);
58 const bool exists = it != availableDefinitions_.end() && *it == key;
59 if (available && !exists) availableDefinitions_.insert(it, key);
60 if (!available && exists) availableDefinitions_.erase(it);
61 schedule(owner);
64}
65
66eve::Result<void> WorkQueue::setTagAvailable(std::string_view owner, std::string_view tag, bool available) {
67 if (owner.empty() || tag.empty())
68 return advancedFailure<void>(eve::DiagnosticCode::InvalidArgument,
69 "tag availability needs an owner and tag");
70 const auto key = std::pair(std::string(owner), std::string(tag));
71 auto it = std::lower_bound(availableTags_.begin(), availableTags_.end(), key);
72 const bool exists = it != availableTags_.end() && *it == key;
73 if (available && !exists) availableTags_.insert(it, key);
74 if (!available && exists) availableTags_.erase(it);
75 schedule(owner);
78}
79
81 if (owner.empty())
82 return advancedFailure<void>(eve::DiagnosticCode::InvalidArgument, "scheduler owner is required", "owner");
83 auto it = std::lower_bound(schedulerStrategies_.begin(), schedulerStrategies_.end(), owner,
84 [](const auto& entry, std::string_view key) { return entry.first < key; });
85 if (it != schedulerStrategies_.end() && it->first == owner)
86 it->second = strategy;
87 else
88 schedulerStrategies_.insert(it, {std::string(owner), strategy});
89 schedule(owner);
91}
92
93void WorkQueue::continueAfterCycle(ProductionTask& task) {
94 ++task.completedCycles;
95 const bool repeats = task.repeat.continuous || task.completedCycles < task.repeat.totalCycles;
96 if (!repeats) return;
97 if (task.repeat.maintainStockTarget >= 0) {
98 const auto updated = static_cast<std::int64_t>(task.repeat.observedStock) + task.batchSize;
99 task.repeat.observedStock = static_cast<int>(std::min<std::int64_t>(updated, std::numeric_limits<int>::max()));
100 }
102 task.workRemainderPermille = 0;
103 task.reason.clear();
105 task.settlement = {};
109}
110
112 std::string_view taskId, std::string_view releaseId) {
113 auto* task = mutableFind(taskId);
114 if (task == nullptr)
115 return advancedFailure<ProductionReservationRelease>(eve::DiagnosticCode::NotFound,
116 "work task was not found", "taskId");
117 if (releaseId.empty())
118 return advancedFailure<ProductionReservationRelease>(eve::DiagnosticCode::InvalidArgument,
119 "reservation release id is required", "releaseId");
121 task->reservationRelease.releaseId == releaseId)
124 if (task->state != TaskState::Cancelled && task->state != TaskState::Failed)
125 return advancedFailure<ProductionReservationRelease>(eve::DiagnosticCode::Conflict,
126 "only cancelled or failed tasks can release reservations",
127 "taskId");
129 return advancedFailure<ProductionReservationRelease>(eve::DiagnosticCode::Conflict,
130 "task has no releasable reservation", "taskId");
131 task->reservationRelease = {std::string(releaseId), task->reservation, task->refundPermille};
135}
136
137eve::Result<void> WorkQueue::reportStock(std::string_view taskId, int observedStock) {
138 auto* task = mutableFind(taskId);
139 if (task == nullptr)
140 return advancedFailure<void>(eve::DiagnosticCode::NotFound, "work task was not found", "taskId");
141 if (task->repeat.maintainStockTarget < 0 || observedStock < 0)
142 return advancedFailure<void>(eve::DiagnosticCode::InvalidArgument,
143 "task has no maintain-stock policy or stock is negative", "observedStock");
144 task->repeat.observedStock = observedStock;
145 schedule(task->owner);
147}
148
150 std::uint32_t maxSteps) {
151 if (target < tick_ || fixedDelta.nanoseconds() <= 0 || maxSteps == 0)
152 return advancedFailure<std::uint32_t>(eve::DiagnosticCode::InvalidArgument,
153 "advanceTo needs a future target, positive delta and step budget");
154 const auto distance = target.value() - tick_.value();
155 if (distance > maxSteps)
156 return advancedFailure<std::uint32_t>(eve::DiagnosticCode::PreconditionViolation,
157 "advanceTo step budget is insufficient", "maxSteps");
158 std::uint32_t applied = 0;
159 while (tick_ < target) {
160 auto step = advance({eve::SimulationTick(tick_.value() + 1), fixedDelta});
161 if (!step) return eve::Result<std::uint32_t>::failure(step.status());
162 ++applied;
163 }
165}
166
168 const auto reference = find(taskId);
169 if (!reference)
170 return advancedFailure<ProductionPrediction>(eve::DiagnosticCode::NotFound,
171 "work task was not found", "taskId");
172 const auto& task = reference->get();
173 ProductionPrediction prediction;
174 auto reason = blockReason(taskId);
175 if (!reason) return eve::Result<ProductionPrediction>::failure(reason.status());
176 prediction.blockReason = reason.value();
177 auto own = scaledRemaining(task);
178 if (!own) return eve::Result<ProductionPrediction>::failure(own.status());
179 prediction.ownWorkRemaining = eve::Duration::fromNanoseconds(own.value());
180 if (task.state == TaskState::Running) {
181 prediction.estimatedCompletionAfter = prediction.ownWorkRemaining;
182 prediction.exact = true;
183 return eve::Result<ProductionPrediction>::success(std::move(prediction));
184 }
185 std::int64_t earliest = 0;
186 if (runningCount(task.owner) >= slotCount(task.owner)) {
187 earliest = std::numeric_limits<std::int64_t>::max();
188 for (const auto& candidate : tasks_)
189 if (candidate->owner == task.owner && candidate->state == TaskState::Running)
190 {
191 auto candidateRemaining = scaledRemaining(*candidate);
192 if (!candidateRemaining)
193 return eve::Result<ProductionPrediction>::failure(candidateRemaining.status());
194 earliest = std::min(earliest, candidateRemaining.value());
195 }
196 if (earliest == std::numeric_limits<std::int64_t>::max()) earliest = 0;
197 }
199 if (earliest > std::numeric_limits<std::int64_t>::max() - own.value())
200 return advancedFailure<ProductionPrediction>(eve::DiagnosticCode::InvalidArgument,
201 "production completion estimate is not representable");
202 prediction.estimatedCompletionAfter = eve::Duration::fromNanoseconds(earliest + own.value());
203 prediction.exact = prediction.blockReason.empty() && task.state == TaskState::Queued && earliest == 0;
204 return eve::Result<ProductionPrediction>::success(std::move(prediction));
205}
206
208 const auto reference = find(taskId);
209 if (!reference)
210 return advancedFailure<ProductionDiagnostic>(eve::DiagnosticCode::NotFound,
211 "work task was not found", "taskId");
212 const auto& task = reference->get();
213 auto reason = blockReason(taskId);
214 if (!reason) return eve::Result<ProductionDiagnostic>::failure(reason.status());
215 ProductionDiagnostic diagnostic;
216 diagnostic.correlationId = task.correlationId;
217 diagnostic.taskId = task.id;
218 diagnostic.tick = tick_;
219 diagnostic.code = reason.value().empty() ? std::string(taskStateName(task.state)) : reason.value();
220 diagnostic.message = reason.value().empty() ? "task state is " + std::string(taskStateName(task.state))
221 : "task is blocked: " + reason.value();
222 return eve::Result<ProductionDiagnostic>::success(std::move(diagnostic));
223}
224
225} // namespace eve::production
LogicalId target
AuthorityStoreHandleRef reference
Definition Authority.cpp:24
std::string message
DiagnosticCode code
std::uint32_t key
bool exists
float distance
const std::string * tag
std::array< std::uint64_t, kPixelChunkSize *kPixelChunkSize > updated
std::string path
Definition PlayHost.cpp:110
std::string taskId
std::vector< ecs::EntityHandle > schedule
The round's activation queue, resolved against the target battle.
float step
Definition TreeMesh.cpp:314
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
Signed, fixed-resolution simulation duration in nanoseconds.
Definition Time.h:43
constexpr std::int64_t nanoseconds() const noexcept
Return the exact signed nanosecond representation.
Definition Time.h:69
static constexpr Duration fromNanoseconds(std::int64_t nanoseconds) noexcept
Construct an exact duration from nanoseconds.
Definition Time.h:55
static constexpr Duration zero() noexcept
Return zero duration.
Definition Time.h:60
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
static Status success(StatusCode code=StatusCode::Ok)
Construct a successful status with an explicit non-error outcome.
Definition Status.h:81
constexpr std::uint64_t value() const noexcept
Returns the underlying value at an explicit protocol boundary.
eve::Result< std::string > blockReason(std::string_view taskId) const
Returns the deterministic reason a task cannot start, or an empty string when runnable.
bool definitionAvailable(std::string_view owner, const eve::definition::DefinitionHandle &definition) const
Reports whether an exact definition incarnation is available to an owner.
bool tagAvailable(std::string_view owner, std::string_view tag) const
Reports whether an exact tag is available to an owner.
eve::OptionalRef< const ProductionTask > find(std::string_view taskId)
Finds a retained task by stable ID.
eve::Result< std::uint32_t > advanceTo(eve::SimulationTick target, eve::Duration fixedDelta, std::uint32_t maxSteps)
Advances through bounded fixed steps to a target tick.
eve::Result< void > setSchedulerStrategy(std::string_view owner, SchedulerStrategy strategy)
Selects an owner's deterministic queue ordering strategy.
eve::Result< void > setDefinitionAvailable(std::string_view owner, const eve::definition::DefinitionHandle &definition, bool available)
Publishes or withdraws one generation-qualified definition fact for an owner.
eve::Result< ProductionPrediction > predict(std::string_view taskId) const
Predicts task timing without mutating queue state.
SchedulerStrategy schedulerStrategy(std::string_view owner) const
Returns an owner's queue ordering strategy, defaulting to Priority.
eve::Result< void > setTagAvailable(std::string_view owner, std::string_view tag, bool available)
Publishes or withdraws one exact tag fact for an owner.
eve::Result< ProductionReservationRelease > releaseReservation(std::string_view taskId, std::string_view releaseId)
Idempotently releases cancelled/failed reservation evidence for domain rollback.
eve::Result< void > reportStock(std::string_view taskId, int observedStock)
Reports current domain stock for a maintain-stock task and reschedules deterministically.
int runningCount(std::string_view owner) const
Returns the number of currently running tasks for an owner.
eve::Result< ProductionDiagnostic > diagnose(std::string_view taskId) const
Returns structured diagnostic state for a task.
eve::Result< void > advance(const eve::SimulationStep &step)
Applies one injected deterministic simulation step.
int slotCount(std::string_view owner) const
Returns an owner's slot count, defaulting to one.
SchedulerStrategy
Stable owner-local queue ordering strategy.
Definition Production.h:87
std::string_view taskStateName(TaskState state)
Returns the stable lowercase name of a task state.
DiagnosticCode
Stable machine-readable diagnostic codes.
Definition Diagnostic.h:47
detail::StrongUint64< detail::SimulationTickTag > SimulationTick
Deterministic simulation time step; it is not wall-clock time.
Definition Time.h:31
A generation-qualified reference to one definition incarnation.
Structured task diagnostic carrying stable correlation identity.
Definition Production.h:115
Side-effect-free estimate under an unchanged queue configuration.
Definition Production.h:106
A subject-agnostic continuous task retained for audit and save games.
Definition Production.h:158
ReservationState reservationState
Definition Production.h:169
ProductionRepeatPolicy repeat
Definition Production.h:177
std::uint32_t workRemainderPermille
Unapplied fixed-point work numerator in thousandths of one nanosecond.
Definition Production.h:183
ProductionSettlementReceipt settlement
Definition Production.h:171
ProductionReservationRelease reservationRelease
Definition Production.h:170