CCF/include/ccf/tx_status.h

124 строки
3.6 KiB
C++

// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the Apache 2.0 License.
#pragma once
#include "ccf/ds/json.h"
#include "ccf/tx_id.h"
namespace ccf
{
/** Describes the status of a transaction, as seen by this node.
*/
enum class TxStatus
{
/** This node has not received this transaction, and knows nothing about it
*/
Unknown,
/** This node has this transaction locally, but has not yet heard that the
transaction has been committed by the distributed consensus */
Pending,
/** This node has seen that this transaction is committed, it is an
irrevocable and durable part of the service's transaction history */
Committed,
/** This node knows that the given transaction cannot be committed. This may
mean there has been a view change, and a previously pending transaction
has been lost (the original request should be resubmitted and will be
given a new Transaction ID). This also describes IDs which are known to
be impossible given the currently committed IDs */
Invalid,
};
constexpr char const* tx_status_to_str(TxStatus status)
{
switch (status)
{
case TxStatus::Unknown:
{
return "Unknown";
}
case TxStatus::Pending:
{
return "Pending";
}
case TxStatus::Committed:
{
return "Committed";
}
case TxStatus::Invalid:
{
return "Invalid";
}
default:
{
return "Unhandled value";
}
}
}
DECLARE_JSON_ENUM(
TxStatus,
{{TxStatus::Unknown, tx_status_to_str(TxStatus::Unknown)},
{TxStatus::Pending, tx_status_to_str(TxStatus::Pending)},
{TxStatus::Committed, tx_status_to_str(TxStatus::Committed)},
{TxStatus::Invalid, tx_status_to_str(TxStatus::Invalid)}});
[[maybe_unused]] static TxStatus evaluate_tx_status(
View target_view,
SeqNo target_seqno,
View local_view,
View committed_view,
SeqNo committed_seqno)
{
const bool is_committed = committed_seqno >= target_seqno;
const bool views_match = local_view == target_view;
const bool view_known = local_view != VIEW_UNKNOWN;
if (is_committed && !view_known)
{
throw std::logic_error(fmt::format(
"Should know local view for seqnos up to {}, but have no view for {}",
committed_seqno,
target_seqno));
}
if (is_committed)
{
// The requested seqno has been committed, so we know for certain whether
// the requested tx id is committed or not
if (views_match)
{
return TxStatus::Committed;
}
else
{
return TxStatus::Invalid;
}
}
else if (views_match)
{
// This node knows about the requested tx id, but it is not globally
// committed
return TxStatus::Pending;
}
else if (committed_view > target_view)
{
// This node has seen the seqno in a different view, and committed
// further, so the requested tx id is impossible
return TxStatus::Invalid;
}
else
{
// Otherwise, we cannot state anything about this tx id. The most common
// reason is that the local_view is unknown (this transaction has never
// existed, or has not reached this node yet). It is also possible that
// this node believes locally that this tx id is impossible, but does not
// have a global commit to back this up - it will eventually receive
// either a global commit confirming this belief, or an election and
// global commit making this tx id invalid
return TxStatus::Unknown;
}
}
}