Skip to content

Commit

Permalink
Post commit execution: part 2 (#4296)
Browse files Browse the repository at this point in the history
Add get_user_data and set_user_data functions to the RpcContext to enable passing data to the post local-commit handler without going through serialization and deserialization.
  • Loading branch information
Andrew Jeffery authored Oct 5, 2022
1 parent 45433fc commit a8f7b0f
Show file tree
Hide file tree
Showing 8 changed files with 40 additions and 37 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
### Added

- New "attestation" section in node JSON configuration to specify remote endpoint required to retrieve the endorsement certificates for SEV-SNP attestation report (#4277, #4302).
- The `ccf::RpcContext` now contains functionality for storing user data with `set_user_data` and retrieving it with `get_user_data` (#4291).
- There are now `make_endpoint_with_local_commit_handler` and `make_read_only_endpoint_with_local_commit_handler` functions to install endpoints with post local-commit logic (#4296).

### Fixed

Expand Down
2 changes: 1 addition & 1 deletion include/ccf/endpoint_registry.h
Original file line number Diff line number Diff line change
Expand Up @@ -260,4 +260,4 @@ namespace ccf::endpoints
virtual void increment_metrics_failures(const ccf::RpcContext& rpc_ctx);
virtual void increment_metrics_retries(const ccf::RpcContext& rpc_ctx);
};
}
}
6 changes: 6 additions & 0 deletions include/ccf/rpc_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,12 @@ namespace ccf
/// the same long-lived session.
virtual std::shared_ptr<SessionContext> get_session_context() const = 0;

// Set user data that will be available in the post-local-commit handler.
// This is useful to avoid the serialisation/deserialisation cost.
virtual void set_user_data(std::shared_ptr<void> data) = 0;
// Get the user data that was previously set.
virtual void* get_user_data() const = 0;

virtual const std::vector<uint8_t>& get_request_body() const = 0;
virtual const std::string& get_request_query() const = 0;
virtual const ccf::RESTVerb& get_request_verb() const = 0;
Expand Down
42 changes: 16 additions & 26 deletions samples/apps/logging/logging.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -317,20 +317,18 @@ namespace loggingapp
auto add_txid_in_body_put = [](auto& ctx, const auto& tx_id) {
static constexpr auto CCF_TX_ID = "x-ms-ccf-transaction-id";
ctx.rpc_ctx->set_response_header(CCF_TX_ID, tx_id.to_str());
ctx.rpc_ctx->set_response_status(HTTP_STATUS_OK);

const nlohmann::json body_j =
nlohmann::json::parse(ctx.rpc_ctx->get_response_body());

auto interm = body_j.get<LoggingPut::Intermediate>();
auto out = static_cast<LoggingPut::Out*>(ctx.rpc_ctx->get_user_data());

if (interm.fail)
if (out == nullptr)
{
throw std::runtime_error("oops, might have failed serialization");
throw std::runtime_error("didn't set user_data!");
}

interm.out.tx_id = tx_id.to_str();
out->tx_id = tx_id.to_str();

ctx.rpc_ctx->set_response_body(nlohmann::json(interm.out).dump());
ctx.rpc_ctx->set_response_body(nlohmann::json(*out).dump());
};

auto record_v2 = [this](auto& ctx, nlohmann::json&& params) {
Expand All @@ -354,27 +352,19 @@ namespace loggingapp

std::string error_reason;
std::string fail;
if (!http::get_query_value(parsed_query, "fail", fail, error_reason))
{
return ccf::make_error(
HTTP_STATUS_BAD_REQUEST,
ccf::errors::InvalidQueryParameterValue,
std::move(error_reason));
}
http::get_query_value(parsed_query, "fail", fail, error_reason);

LoggingPut::Out resp;
resp.success = true;
LoggingPut::Intermediate interm;
interm.out = resp;
if (fail == "true")
{
interm.fail = true;
}
else
auto out = std::make_shared<LoggingPut::Out>();
out->success = true;

if (fail != "true")
{
interm.fail = false;
ctx.rpc_ctx->set_user_data(out);
}
return ccf::make_success(interm);

// return a default value as we'll set the response in the post-commit
// handler
return ccf::make_success(nullptr);
};

make_endpoint_with_local_commit_handler(
Expand Down
7 changes: 0 additions & 7 deletions samples/apps/logging/logging_schema.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,6 @@ namespace loggingapp
bool success;
std::string tx_id;
};
struct Intermediate
{
Out out;
bool fail;
};
};

struct LoggingGetReceipt
Expand All @@ -69,8 +64,6 @@ namespace loggingapp

DECLARE_JSON_TYPE(LoggingPut::Out);
DECLARE_JSON_REQUIRED_FIELDS(LoggingPut::Out, success, tx_id);
DECLARE_JSON_TYPE(LoggingPut::Intermediate);
DECLARE_JSON_REQUIRED_FIELDS(LoggingPut::Intermediate, out, fail);

DECLARE_JSON_TYPE(LoggingGetReceipt::In);
DECLARE_JSON_REQUIRED_FIELDS(LoggingGetReceipt::In, id);
Expand Down
4 changes: 2 additions & 2 deletions src/endpoints/endpoint_registry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ namespace ccf::endpoints

endpoint.dispatch.verb = verb;
endpoint.func = f;
endpoint.locally_committed_func = &default_locally_committed_func;
endpoint.locally_committed_func = default_locally_committed_func;

endpoint.authn_policies = ap;
// By default, all write transactions are forwarded
Expand Down Expand Up @@ -554,4 +554,4 @@ namespace ccf::endpoints
rpc_ctx.get_method(), rpc_ctx.get_request_verb().c_str())
.retries++;
}
}
}
12 changes: 12 additions & 0 deletions src/node/rpc/rpc_context_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ namespace ccf
protected:
std::shared_ptr<SessionContext> session;

std::shared_ptr<void> user_data;

public:
RpcContextImpl(const std::shared_ptr<SessionContext>& s) : session(s) {}

Expand All @@ -24,6 +26,16 @@ namespace ccf
return session;
}

virtual void set_user_data(std::shared_ptr<void> data) override
{
user_data = data;
}

virtual void* get_user_data() const override
{
return user_data.get();
}

ccf::ClaimsDigest claims = ccf::empty_claims();
void set_claims_digest(ccf::ClaimsDigest::Digest&& digest) override
{
Expand Down
2 changes: 1 addition & 1 deletion tests/e2e_logging.py
Original file line number Diff line number Diff line change
Expand Up @@ -1527,7 +1527,7 @@ def test_post_local_commit_failure(network, args):
assert r.body.json() == {
"error": {
"code": "InternalError",
"message": "Failed to execute local commit handler func: oops, might have failed serialization",
"message": "Failed to execute local commit handler func: didn't set user_data!",
}
}, r.body.json()

Expand Down

0 comments on commit a8f7b0f

Please sign in to comment.