载入中...
搜索中...
未找到
Transaction.cpp
浏览该文件的文档.
135eve::Result<void> invokeParticipant(Call&& call, std::string_view phase, const ITransactionParticipant& participant) {
141 std::string(phase) + " threw for participant " + std::string(participant.name()) + ": " + exception.what(),
146 std::string(phase) + " threw an unknown exception for participant " + std::string(participant.name()),
151void appendFailure(std::vector<eve::Diagnostic>& diagnostics, const eve::Status& status, std::string_view phase,
156 eve::DiagnosticCode::Failed, std::string(phase) + " failed for participant " + std::string(participant.name()),
160eve::Result<TransactionReceipt> coordinatorFailure(eve::StatusCode code, std::vector<eve::Diagnostic> diagnostics) {
163 eve::Diagnostic::error(eve::DiagnosticCode::Failed, "transaction participant lifecycle failed"));
169Ledger::Ledger(eve::PersistentId instanceId, eve::UuidEntropySource transactionEntropy, eve::UuidClock transactionClock)
211 auto result = invokeParticipant([&] { return participants[i]->prepare(context); }, "prepare", *participants[i]);
217 auto rollback = invokeParticipant([&] { return participants[*it]->rollback(context); }, "rollback",
224 return coordinatorFailure(cleanupFailed ? eve::StatusCode::Failed : result.code(), std::move(diagnostics));
233 auto result = invokeParticipant([&] { return participants[i]->commit(context); }, "commit", *participants[i]);
244 auto rollback = invokeParticipant([&] { return participants[*it]->rollback(context); }, "rollback",
259 return coordinatorFailure(cleanupFailed ? eve::StatusCode::Failed : result.code(), std::move(diagnostics));
266 return eve::Result<TransactionReceipt>::success(std::move(receipt), eve::Status::success(eve::StatusCode::Applied));
303 auto result = invokeParticipant([&] { return participants[index]->compensate(context); }, "compensation",
316 return eve::Result<TransactionReceipt>::success(std::move(receipt), eve::Status::success(eve::StatusCode::Applied));
330Plan::Plan(std::string id, std::string correlation, std::string causation, eve::TransactionId identity,
332 : id_(std::move(id)), identity_(identity), correlation_(std::move(correlation)), causation_(std::move(causation)) {
333 if (operationEntropy) operationIdGenerator_.emplace(std::move(operationEntropy), std::move(operationClock));
343void Plan::emit(const std::string& type, const std::string& operationId, const std::string& detail) {
351 if (const auto parsed = eve::OperationId::parse(operationId)) event.operationIdentity = *parsed;
361 if (state_ != State::Open) return failure(eve::DiagnosticCode::Conflict, "transaction plan is frozen");
362 if (kind.empty()) return failure(eve::DiagnosticCode::InvalidArgument, "operation kind must not be empty");
364 if (!document.valid()) return failure(eve::DiagnosticCode::ParseError, "payload must be valid JSON");
373 if (!generated) return failure(eve::DiagnosticCode::Failed, "canonical operation identity generation failed");
377 return failure(eve::DiagnosticCode::Conflict, "operation identity already exists in this plan");
388 return eve::Result<eve::OperationId>::success(operationId, eve::Status::success(eve::StatusCode::Applied));
392 auto it = std::find_if(operations.begin(), operations.end(), [&id](const Operation& op) { return op.id == id; });
403 if (state_ != State::Open) return eve::Result<void>::failure(eve::Diagnostic::error(eve::DiagnosticCode::Conflict, "transaction is not open", {}, {}, "transaction"));
405 if (!operation) return eve::Result<void>::failure(eve::Diagnostic::error(eve::DiagnosticCode::NotFound, "operation was not found", {}, {}, "transaction"));
414 if (state_ != State::Open) return eve::Result<void>::failure(eve::Diagnostic::error(eve::DiagnosticCode::Conflict, "transaction is not open", {}, {}, "transaction"));
416 if (!operation) return eve::Result<void>::failure(eve::Diagnostic::error(eve::DiagnosticCode::NotFound, "operation was not found", {}, {}, "transaction"));
425 if (state_ != State::Open) return eve::Result<void>::failure(eve::Diagnostic::error(eve::DiagnosticCode::Conflict, "transaction is not open", {}, {}, "transaction"));
427 if (!operation) return eve::Result<void>::failure(eve::Diagnostic::error(eve::DiagnosticCode::NotFound, "operation was not found", {}, {}, "transaction"));
436 if (state_ != State::Open) return eve::Result<void>::failure(eve::Diagnostic::error(eve::DiagnosticCode::Conflict, "transaction is not open", {}, {}, "transaction"));
438 if (!operation) return eve::Result<void>::failure(eve::Diagnostic::error(eve::DiagnosticCode::NotFound, "operation was not found", {}, {}, "transaction"));
448 if (state_ != State::Open) return eve::Result<void>::failure(eve::Diagnostic::error(eve::DiagnosticCode::Conflict, "transaction is not open", {}, {}, "transaction"));
452 return eve::Result<void>::failure(eve::Diagnostic::error(eve::DiagnosticCode::InvalidArgument, error_, {}, {}, "transaction"));
458 return eve::Result<void>::failure(eve::Diagnostic::error(eve::DiagnosticCode::InvalidArgument, error_, {}, {}, "transaction"));
467 if (state_ != State::Validated) return eve::Result<void>::failure(eve::Diagnostic::error(eve::DiagnosticCode::Conflict, "transaction is not validated", {}, {}, "transaction"));
475 return eve::Result<void>::failure(eve::Diagnostic::error(eve::DiagnosticCode::Conflict, "transaction cannot be rolled back in its current state", {}, {}, "transaction"));
484 return eve::Result<void>::failure(eve::Diagnostic::error(eve::DiagnosticCode::Conflict, "transaction is already terminal", {}, {}, "transaction"));
526 out << ",\"kind\":" << quote(op.kind) << ",\"target\":" << quote(op.target) << ",\"payload\":" << op.payload
527 << ",\"checked\":" << (op.checked ? "true" : "false") << ",\"valid\":" << (op.valid ? "true" : "false")
535 << ",\"transactionId\":" << quote(event.transactionId) << ",\"operationId\":" << quote(event.operationId)
551 if (!generated) return failure(eve::DiagnosticCode::Failed, "canonical transaction identity generation failed");
554 if (find(identity)) return failure(eve::DiagnosticCode::Conflict, "transaction identity already exists");
556 new Plan(identity.format(), correlation, causation, identity, transactionEntropy_, transactionClock_)));
557 return eve::Result<Plan*>::success(plans_.back().get(), eve::Status::success(eve::StatusCode::Applied));
579 out << "{\"version\":1,\"nextTransaction\":" << quote(std::to_string(nextTransaction_)) << ",\"plans\":[";
595 !parseU64(root.get("nextTransaction"), restoredNext) || restoredNext == 0 || !root.get("plans").isArray()) {
608 !parseU64(value.get("nextEvent"), nextEvent) || nextEvent == 0 || !value.get("operations").isArray() ||
610 return failure(eve::DiagnosticCode::ParseError, "invalid transaction plan at index " + std::to_string(i));
638 return failure(eve::DiagnosticCode::ParseError, "invalid transaction id at index " + std::to_string(i));
641 if (id.empty() || std::find(restoredPlanIds.begin(), restoredPlanIds.end(), id) != restoredPlanIds.end()) {
642 return failure(eve::DiagnosticCode::Conflict, "duplicate transaction id at index " + std::to_string(i));
645 auto plan = std::unique_ptr<Plan>(new Plan(id, value.getString("correlation"), value.getString("causation"),
655 if (!opValue.isObject() || opValue.getString("id").empty() || opValue.getString("kind").empty() ||
656 !opValue.get("payload") || !opValue.get("checked").isBool() || !opValue.get("valid").isBool()) {
665 return failure(eve::DiagnosticCode::ParseError, "invalid canonical operation id in plan " + id);
699 if (const auto parsed = eve::OperationId::parse(event.operationId)) event.operationIdentity = *parsed;
716eve::Result<eve::SnapshotEnvelope> Ledger::snapshot(const eve::SnapshotHashProvider& hashProvider) const {
719 return eve::makeSnapshotEnvelope("transaction.ledger", transactionSchema(), eve::SchemaVersion(1), instanceId_,
735 auto metadata = eve::validateSnapshotPayloadMetadata(candidateEnvelope.payload, candidateEnvelope.revision,
751eve::Result<std::string> Ledger::snapshotEnvelopeJson(const eve::SnapshotHashProvider& hashProvider) const {
758eve::Result<void> Ledger::restoreSnapshotJson(std::string_view json, const eve::SnapshotHashProvider& hashProvider) {
775 table.addClass<Operation>("TransactionOperation", std::function<Operation*()>([] { return nullptr; }), false);
784 auto event = table.addClass<Event>("TransactionEvent", std::function<Event*()>([] { return nullptr; }), false);
785 event.addFunc("getSequence", [](Event* e) { return e ? static_cast<int64_t>(e->sequence) : int64_t{0}; });
786 event.addFunc("getTransactionId", [](Event* e) { return e ? e->transactionId : std::string{}; });
791 auto plan = table.addClass<Plan>("TransactionPlan", std::function<Plan*()>([] { return nullptr; }), false);
844 [](Plan* p, int i) -> Operation* { return p ? const_cast<Operation*>(p->operationAt(i)) : nullptr; });
849 plan.addFunc("eventAt", [](Plan* p, int i) -> Event* { return p ? const_cast<Event*>(p->eventAt(i)) : nullptr; });
856 eve::Result<eve::OperationId>::failure(eve::Diagnostic::error(eve::DiagnosticCode::InvalidArgument,
877 auto ledger = table.addClass<Ledger>("TransactionLedger", std::function<Ledger*()>([] { return nullptr; }), false);
881 [](Ledger* ledger, const std::string& id) -> Plan* { return ledger ? ledger->find(id) : nullptr; });
893 ledger.addFunc("create", [vm](Ledger* value, const std::string& correlation, const std::string& causation,
The single Squirrel projection for common Result, Status and Value.
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
static std::optional< LogicalId > parse(std::string_view text)
Parses a scoped logical name.
Definition Identity.cpp:36
static Result failure(Status status)
Construct a failed result from a structured status.
Definition Result.h:175
Result< void > add(LogicalId schema, SchemaVersion from, SchemaVersion to, Migration migration)
Register one schema-local migration edge.
Definition Snapshot.cpp:196
static Status success(StatusCode code=StatusCode::Ok)
Construct a successful status with an explicit non-error outcome.
Definition Status.h:81
static Result< Value > fromJson(std::string_view json)
Parse one strict JSON value into an owning Value.
Definition Value.cpp:57
std::string format() const
Formats the ID in lower-case canonical UUID text.
Definition Identity.h:173
constexpr bool isNil() const noexcept
Returns whether this value is the all-zero nil ID.
Definition Identity.h:176
static std::optional< Id128 > parse(std::string_view text) noexcept
Parses canonical UUID text.
Definition Identity.h:151
static constexpr Id128 fromUuid(const Id128< OtherTag > &value) noexcept
Re-tags an existing UUID at an explicit domain boundary.
Definition Identity.h:136
static Document parse(const std::string &text, std::string *error=nullptr)
Parse.
Definition Json.cpp:581
Result< TransactionReceipt > execute(const TransactionContext &context, std::span< ITransactionParticipant * > participants) const
Atomically execute borrowed participants for one context.
Definition Transaction.cpp:176
Result< TransactionReceipt > compensate(const TransactionContext &context, std::span< ITransactionParticipant * > participants) const
Compensate already committed participants in reverse dependency order.
Definition Transaction.cpp:269
Deterministic owner and identifier allocator for transaction plans.
Definition Transaction.h:345
Ledger(eve::PersistentId instanceId={}, eve::UuidEntropySource transactionEntropy={}, eve::UuidClock transactionClock={})
Creates an empty ledger with an optional persistent identity.
Definition Transaction.cpp:169
eve::Result< void > restore(std::string_view json)
Transactionally restores a raw ledger snapshot.
Definition Transaction.cpp:587
Immutable-after-validation operation plan for script-coordinated work.
Definition Transaction.h:241
Immutable context shared by every participant of one transaction.
Definition Transaction.h:30
Script module factory for generic transaction ledgers.
Definition Transaction.h:423
@ Operation
std::string stateName(OrderState state)
Returns the stable lowercase name of a state.
Definition CommandQueue.cpp:158
ssq::Table projectResult(HSQUIRRELVM vm, Result< void > &&result)
Consume and project a void native Result using the common schema.
Definition SquirrelBinding.cpp:470
Definition AtomicResourcePayment.cpp:8
std::string stateName(State state)
Returns the stable lowercase name of a transaction state.
Definition Transaction.cpp:319
@ Validated
@ Failed
@ RolledBack
@ Committed
Operation * findMutable(std::deque< Operation > &operations, const std::string &id)
Definition Transaction.cpp:391
@ CompensationFailed
@ Compensated
@ InvalidArgument
@ NotFound
@ Unsupported
@ Failed
@ ParseError
@ Conflict
Result< void > validateSnapshotPayloadMetadata(const Value &payload, Revision revision, SimulationTick tick)
Validate optional payload copies of envelope revision and tick.
Definition Snapshot.cpp:80
@ Applied
@ Rejected
@ Failed
std::function< std::chrono::system_clock::time_point()> UuidClock
Clock callback used by the injectable UUIDv7 generator.
Definition Identity.h:469
Result< SnapshotEnvelope > parseSnapshotEnvelope(std::string_view json, const SnapshotHashProvider &hashProvider)
Parse and verify an envelope from canonical or compatible JSON text.
Definition Snapshot.cpp:190
Result< std::string > serializeSnapshotEnvelope(const SnapshotEnvelope &snapshot)
Serialize an envelope as deterministic compact JSON.
Definition Snapshot.cpp:184
std::function< bool(std::span< std::uint8_t > bytes)> UuidEntropySource
Entropy callback used by UUIDv7 generation.
Definition Identity.h:466
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
std::function< Result< ContentId >(std::string_view canonicalInput)> SnapshotHashProvider
Injected content-digest implementation used by snapshots.
Definition Snapshot.h:36
Definition Container.h:602
Stable outer format shared by persistence and cross-process snapshots.
Definition Snapshot.h:46
Deterministically ordered transaction lifecycle event.
Definition Transaction.h:223
One inert, script-interpreted operation in a transaction plan.
Definition Transaction.h:210
eve::OperationId identity
Canonical operation identity; nil for legacy string-only plans.
Definition Transaction.h:219
Observable summary returned after an atomic participant commit.
Definition Transaction.h:97
std::size_t preparedCount
Definition Transaction.h:105
std::size_t committedCount
Definition Transaction.h:106
std::size_t compensatedCount
Definition Transaction.h:108
std::size_t participantCount
Definition Transaction.h:104
eve::TransactionId identity
Canonical transaction identity; nil for legacy string contexts.
Definition Transaction.h:99
std::string transactionId
Definition Transaction.h:100
std::string correlationId
Definition Transaction.h:101
std::string causationId
Definition Transaction.h:102