Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

admin_server/get_partition: Avoid oversized allocation #11824

Conversation

BenPope
Copy link
Member

@BenPope BenPope commented Jun 30, 2023

Avoid oversized allocation by:

  • Collecting summaries into a fragmented_vector
  • Streaming the vector to an ss::output_stream

The overload of ss::json::json_return_type that provides an ss::output_stream requires a std::function, which is required to be copyable, so wrap the fragmented_vector in a simple container wrapper that holds the container by ss::lw_shared_ptr.

Another optimisation is moving rather than copying during accumulation.

Fixes #11674

Backports Required

  • none - not a bug fix
  • none - this is a backport
  • none - issue does not exist in previous branches
  • none - papercut/not impactful enough to backport
  • v23.1.x
  • v22.3.x
  • v22.2.x

Release Notes

Improvements

  • admin_server/get_partition: Avoid oversized allocation

Avoid oversized allocation by:
* Collecting summaries into a fragmented_vector
* Streaming the vector to an output_stream

The overload of `ss::json::json_return_type` that provides an
`ss::output_stream` requires a `std::function`, which is required to
be copyable, so wrap the `fragmented_vector` in a simple container
wrapper that holds the container by `ss::lw_shared_ptr`.

Another optimisation is moving rather than copying during accumulation.

Fixes redpanda-data#11674

Signed-off-by: Ben Pope <[email protected]>
@BenPope
Copy link
Member Author

BenPope commented Jul 3, 2023

/cdt
tests/rptest/scale_tests/large_controller_snapshot_test.py

@BenPope
Copy link
Member Author

BenPope commented Jul 3, 2023

/cdt tests/rptest/scale_tests/large_controller_snapshot_test.py

The oversized allocs in this test run are:

There's another one:

WARN  2023-07-03 13:05:05,900 [shard 1] seastar_memory - oversized allocation: 393216 bytes. This is non-fatal, but could lead to latency and/or fragmentation issues. Please report: at 0x6ea5ef3 0x6b212fb 0x6b32eed 0x23df55e 0x23dd740 0x23dc8db 0x23e3072 0x6bec99f 0x6bf0057 0x6c496c5 0x6b7afcf /opt/redpanda/lib/libc.so.6+0x91016 /opt/redpanda/lib/libc.so.6+0x1166cf
   --------
   seastar::lambda_task<auto seastar::with_scheduling_group<raft::service<cluster::partition_manager, cluster::shard_table>::dispatch_hbeats_to_core(unsigned int, seastar::foreign_ptr<std::__1::unique_ptr<seastar::chunked_fifo<raft::append_entries_request, 128ul>, std::__1::default_delete<seastar::chunked_fifo<raft::append_entries_request, 128ul>>>>)::'lambda'()>(seastar::scheduling_group, raft::service<cluster::partition_manager, cluster::shard_table>::dispatch_hbeats_to_core(unsigned int, seastar::foreign_ptr<std::__1::unique_ptr<seastar::chunked_fifo<raft::append_entries_request, 128ul>, std::__1::default_delete<seastar::chunked_fifo<raft::append_entries_request, 128ul>>>>)::'lambda'())::'lambda'()>
   --------
   seastar::continuation<seastar::internal::promise_base_with_type<std::__1::vector<std::__1::vector<raft::append_entries_reply, std::__1::allocator<raft::append_entries_reply>>, std::__1::allocator<std::__1::vector<raft::append_entries_reply, std::__1::allocator<raft::append_entries_reply>>>>>, seastar::internal::extract_values_from_futures_vector<seastar::future<std::__1::vector<raft::append_entries_reply, std::__1::allocator<raft::append_entries_reply>>>>::future_type seastar::internal::complete_when_all<seastar::internal::extract_values_from_futures_vector<seastar::future<std::__1::vector<raft::append_entries_reply, std::__1::allocator<raft::append_entries_reply>>>>, seastar::future<std::__1::vector<raft::append_entries_reply, std::__1::allocator<raft::append_entries_reply>>>>(std::__1::vector<seastar::future<std::__1::vector<raft::append_entries_reply, std::__1::allocator<raft::append_entries_reply>>>, std::__1::allocator<seastar::future<std::__1::vector<raft::append_entries_reply, std::__1::allocator<raft::append_entries_reply>>>>>&&, std::__1::vector<seastar::future<std::__1::vector<raft::append_entries_reply, std::__1::allocator<raft::append_entries_reply>>>, std::__1::allocator<seastar::future<std::__1::vector<raft::append_entries_reply, std::__1::allocator<raft::append_entries_reply>>>>>::iterator)::'lambda'(seastar::internal::extract_values_from_futures_vector<seastar::future<std::__1::vector<raft::append_entries_reply, std::__1::allocator<raft::append_entries_reply>>>>), seastar::futurize<seastar::internal::extract_values_from_futures_vector<seastar::future<std::__1::vector<raft::append_entries_reply, std::__1::allocator<raft::append_entries_reply>>>>>::type seastar::future<std::__1::vector<raft::append_entries_reply, std::__1::allocator<raft::append_entries_reply>>>::then_wrapped_nrvo<seastar::future<std::__1::vector<std::__1::vector<raft::append_entries_reply, std::__1::allocator<raft::append_entries_reply>>, std::__1::allocator<std::__1::vector<raft::append_entries_reply, std::__1::allocator<raft::append_entries_reply>>>>>, seastar::internal::extract_values_from_futures_vector<seastar::future<std::__1::vector<raft::append_entries_reply, std::__1::allocator<raft::append_entries_reply>>>>::future_type seastar::internal::complete_when_all<seastar::internal::extract_values_from_futures_vector<seastar::future<std::__1::vector<raft::append_entries_reply, std::__1::allocator<raft::append_entries_reply>>>>, seastar::future<std::__1::vector<raft::append_entries_reply, std::__1::allocator<raft::append_entries_reply>>>>(std::__1::vector<seastar::future<std::__1::vector<raft::append_entries_reply, std::__1::allocator<raft::append_entries_reply>>>, std::__1::allocator<seastar::future<std::__1::vector<raft::append_entries_reply, std::__1::allocator<raft::append_entries_reply>>>>>&&, std::__1::vector<seastar::future<std::__1::vector<raft::append_entries_reply, std::__1::allocator<raft::append_entries_reply>>>, std::__1::allocator<seastar::future<std::__1::vector<raft::append_entries_reply, std::__1::allocator<raft::append_entries_reply>>>>>::iterator)::'lambda'(seastar::internal::extract_values_from_futures_vector<seastar::future<std::__1::vector<raft::append_entries_reply, std::__1::allocator<raft::append_entries_reply>>>>)>(seastar::future<std::__1::vector<raft::append_entries_reply, std::__1::allocator<raft::append_entries_reply>>>&&)::'lambda'(seastar::internal::promise_base_with_type<std::__1::vector<std::__1::vector<raft::append_entries_reply, std::__1::allocator<raft::append_entries_reply>>, std::__1::allocator<std::__1::vector<raft::append_entries_reply, std::__1::allocator<raft::append_entries_reply>>>>>&&, seastar::internal::extract_values_from_futures_vector<seastar::future<std::__1::vector<raft::append_entries_reply, std::__1::allocator<raft::append_entries_reply>>>>::future_type seastar::internal::complete_when_all<seastar::internal::extract_values_from_futures_vector<seastar::future<std::__1::vector<raft::append_entries_reply, std::__1::allocator<raft::append_entries_reply>>>>, seastar::future<std::__1::vector<raft::append_entries_reply, std::__1::allocator<raft::append_entries_reply>>>>(std::__1::vector<seastar::future<std::__1::vector<raft::append_entries_reply, std::__1::allocator<raft::append_entries_reply>>>, std::__1::allocator<seastar::future<std::__1::vector<raft::append_entries_reply, std::__1::allocator<raft::append_entries_reply>>>>>&&, std::__1::vector<seastar::future<std::__1::vector<raft::append_entries_reply, std::__1::allocator<raft::append_entries_reply>>>, std::__1::allocator<seastar::future<std::__1::vector<raft::append_entries_reply, std::__1::allocator<raft::append_entries_reply>>>>>::iterator)::'lambda'(seastar::internal::extract_values_from_futures_vector<seastar::future<std::__1::vector<raft::append_entries_reply, std::__1::allocator<raft::append_entries_reply>>>>)&, seastar::future_state<std::__1::vector<raft::append_entries_reply, std::__1::allocator<raft::append_entries_reply>>>&&), std::__1::vector<raft::append_entries_reply, std::__1::allocator<raft::append_entries_reply>>>
   --------
   seastar::continuation<seastar::internal::promise_base_with_type<raft::heartbeat_reply>, raft::service<cluster::partition_manager, cluster::shard_table>::heartbeat(raft::heartbeat_request&&, rpc::streaming_context&)::'lambda'(std::__1::vector<std::__1::vector<raft::append_entries_reply, std::__1::allocator<raft::append_entries_reply>>, std::__1::allocator<std::__1::vector<raft::append_entries_reply, std::__1::allocator<raft::append_entries_reply>>>>), seastar::future<raft::heartbeat_reply> seastar::future<std::__1::vector<std::__1::vector<raft::append_entries_reply, std::__1::allocator<raft::append_entries_reply>>, std::__1::allocator<std::__1::vector<raft::append_entries_reply, std::__1::allocator<raft::append_entries_reply>>>>>::then_impl_nrvo<raft::service<cluster::partition_manager, cluster::shard_table>::heartbeat(raft::heartbeat_request&&, rpc::streaming_context&)::'lambda'(std::__1::vector<std::__1::vector<raft::append_entries_reply, std::__1::allocator<raft::append_entries_reply>>, std::__1::allocator<std::__1::vector<raft::append_entries_reply, std::__1::allocator<raft::append_entries_reply>>>>), seastar::future<raft::heartbeat_reply>>(raft::service<cluster::partition_manager, cluster::shard_table>::heartbeat(raft::heartbeat_request&&, rpc::streaming_context&)::'lambda'(std::__1::vector<std::__1::vector<raft::append_entries_reply, std::__1::allocator<raft::append_entries_reply>>, std::__1::allocator<std::__1::vector<raft::append_entries_reply, std::__1::allocator<raft::append_entries_reply>>>>)&&)::'lambda'(seastar::internal::promise_base_with_type<raft::heartbeat_reply>&&, raft::service<cluster::partition_manager, cluster::shard_table>::heartbeat(raft::heartbeat_request&&, rpc::streaming_context&)::'lambda'(std::__1::vector<std::__1::vector<raft::append_entries_reply, std::__1::allocator<raft::append_entries_reply>>, std::__1::allocator<std::__1::vector<raft::append_entries_reply, std::__1::allocator<raft::append_entries_reply>>>>)&, seastar::future_state<std::__1::vector<std::__1::vector<raft::append_entries_reply, std::__1::allocator<raft::append_entries_reply>>, std::__1::allocator<std::__1::vector<raft::append_entries_reply, std::__1::allocator<raft::append_entries_reply>>>>>&&), std::__1::vector<std::__1::vector<raft::append_entries_reply, std::__1::allocator<raft::append_entries_reply>>, std::__1::allocator<std::__1::vector<raft::append_entries_reply, std::__1::allocator<raft::append_entries_reply>>>>>

@piyushredpanda
Copy link
Contributor

On a roll, @BenPope -- thank you!

@dotnwat
Copy link
Member

dotnwat commented Jul 5, 2023

There's another one:

@BenPope does this comment mean the PR isn't ready for review, or is the new over sized allocation something you turned into a different ticket to look into?

@BenPope
Copy link
Member Author

BenPope commented Jul 6, 2023

There's another one:

@BenPope does this comment mean the PR isn't ready for review, or is the new over sized allocation something you turned into a different ticket to look into?

No, I'm just noting an oversized alloc iin the test that hasn't got a ticket yet.

Copy link
Contributor

@michael-redpanda michael-redpanda left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice

Comment on lines +146 to +160
template<typename C>
class lw_shared_container {
public:
using iterator = C::iterator;
using value_type = C::value_type;

explicit lw_shared_container(C&& c)
: c_{ss::make_lw_shared<C>(std::move(c))} {}

iterator begin() const { return c_->begin(); }
iterator end() const { return c_->end(); }

private:
ss::lw_shared_ptr<C> c_;
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: should this be in some utility folder somewhere? Could this be useful for other refactoring situations?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was wondering that; I haven't seen anything similar anywhere. I expect it will be useful again in this file, but perhaps also pandaproxy/rest. It can be moved later, I guess.

@piyushredpanda piyushredpanda merged commit 68fe9f9 into redpanda-data:dev Jul 6, 2023
@vbotbuildovich
Copy link
Collaborator

/backport v23.1.x

@vbotbuildovich
Copy link
Collaborator

Failed to run cherry-pick command. I executed the commands below:

git checkout -b backport-pr-11824-v23.1.x-865 remotes/upstream/v23.1.x
git cherry-pick -x d32b2509ee5eec6d7517d31ed758c4090f4135ae

Workflow run logs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Oversized allocation: 1232896 bytes in admin_server::register_partition_routes
5 participants