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

Introduce transform::manager #13270

Merged
merged 22 commits into from
Sep 14, 2023
Merged

Conversation

rockwotj
Copy link
Contributor

@rockwotj rockwotj commented Sep 5, 2023

Transform manager is the component for ensuring that the correct transform::processor is running for a given core.

It is a component that recieves notifications from the rest of the system and processes those notifications on a single fiber queue.

The queue makes handling shutdown a little simpler, as we can remove most of the logic for handling shutdown correctly into another class,
additionally using a single fiber means we don't need to worry about concurrent modifications of data structures or duplicate notifications
being scheduled.

We also template the manager based on the clock type. This is a similar pattern used in other places that allows us to use the seastar manual
clock for fully deterministic testing, but use the lowres clock for production usage.

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.2.x
  • v23.1.x
  • v22.3.x

Release Notes

  • none

@rockwotj
Copy link
Contributor Author

rockwotj commented Sep 6, 2023

CI Failures: #12659, #13181

@rockwotj rockwotj marked this pull request as ready for review September 6, 2023 01:23
@rockwotj rockwotj requested a review from oleiman September 12, 2023 03:09
Copy link
Member

@dotnwat dotnwat left a comment

Choose a reason for hiding this comment

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

looks great. several questions but i don't think there are any blockers.

src/v/ssx/work_queue.cc Show resolved Hide resolved
Comment on lines +18 to +23
void work_queue::submit(ss::noncopyable_function<ss::future<>()> fn) {
if (_as.abort_requested()) {
return;
Copy link
Member

Choose a reason for hiding this comment

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

i wonder if the signature here should be

ss::noncopyable_function<ss::future<>(seastar::abort_source*)> fn

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I thought about this - right now there isn't a use case because starting a wasm engine isn't interruptible at the moment and that's the main source of latency I'd assume. Do you think it's worth future proofing?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

By future proofing I mean adding now

Copy link
Member

Choose a reason for hiding this comment

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

Do you think it's worth future proofing?

nah

src/v/ssx/work_queue.cc Outdated Show resolved Hide resolved
@@ -121,4 +121,6 @@ ss::future<> processor::do_run_transform_loop() {

model::transform_id processor::id() const { return _id; }
const model::ntp& processor::ntp() const { return _ntp; }
const model::transform_metadata& processor::meta() const { return _meta; }
bool processor::is_running() const { return !_task.available(); }
Copy link
Member

Choose a reason for hiding this comment

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

i'll be interested to see later in the pr how is_running is used, but it feels like an odd property to expose. for example, if its false then the only move is to inspect if there was an exception, but that isn't exposed. it could be restarted, but that could be hidden--restart automatic policy. also, it's true before before start() and after stop() (ie contains ss::now()).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think you saw this :)

I'm happy for alternatives, but I'd like to colocate the processor with the backoff state and this feels like the easiest thing? I guess an optional (or nullptr) is another option too...

Copy link
Member

Choose a reason for hiding this comment

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

it makes sense to have this or something like it if the restart policy is extracted out of the processor itself. it just wasn't clear what was coming up in a commit-by-commit review, so it's a bit more of a stream of consciousness.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

stream of consciousness

love stream of consciousness reviews!

src/v/transform/transform_manager.cc Outdated Show resolved Hide resolved
src/v/transform/transform_manager.cc Outdated Show resolved Hide resolved
src/v/transform/transform_manager.h Show resolved Hide resolved
src/v/utils/human.h Show resolved Hide resolved
src/v/transform/transform_manager.cc Outdated Show resolved Hide resolved
// enqueued to ensure that task execution is deterministic. Because in
// debug mode seastar randomizes task order, so there is no way to wait
// for those tasks to be executed outside of draining the seastar queue.
ss::set_idle_cpu_handler([this](ss::work_waiting_on_reactor) {
Copy link
Member

Choose a reason for hiding this comment

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

I'm curious if you saw this technique in Redpanda source tree. I ask because we had to solve a similar problem at one point in the past and I don't recall that we had support from Seastar for that like you've managed to get with this code.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I did not. I studied the reactor source in seastar a lot until I stumbled upon this. AFAIK this is would be the first usage of ss::set_idle_cpu_handler in Redpanda.

Copy link
Member

Choose a reason for hiding this comment

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

So cool

@rockwotj
Copy link
Contributor Author

Force push rebase with dev

This is a small utility that manages running tasks sequentially on a
single fiber.

This is useful for simplifying control loops by executing everything on
a single fiber without need for locking/etc.

As a potenial future extension: for long running async work, this queue
could have the ability to manage spinning off background fibers to
handle work, then re-enqueuing the result of that work. The advantage of
having the work_queue track that is that the bookkeeping is
consolidated into a single place and we can cleanly handle shutdown.

Signed-off-by: Tyler Rockwood <rockwood@redpanda.com>
Signed-off-by: Tyler Rockwood <rockwood@redpanda.com>
Signed-off-by: Tyler Rockwood <rockwood@redpanda.com>
Signed-off-by: Tyler Rockwood <rockwood@redpanda.com>
Signed-off-by: Tyler Rockwood <rockwood@redpanda.com>
This is the main controller for processors. It ensures that there are
processors running on it's core for all of the leader ntp's that have
transforms attached as inputs.

In the case of failures we retry with backoff exponentially, this state
is tracked along side it's processor in a table that includes probes as
well (as these must be shared on a core if a core owns multiple
partitions for an input topic that has a transform).

The relationship of there being many transforms for many partitions
means that the logic here is non trivial of keeping track of all the
state, as well as tracking if a transform is running or not.

Signed-off-by: Tyler Rockwood <rockwood@redpanda.com>
This will help in the transform manager tests that we can plugin a
processor that reports its lifecycle state to the tests

Signed-off-by: Tyler Rockwood <rockwood@redpanda.com>
Signed-off-by: Tyler Rockwood <rockwood@redpanda.com>
Signed-off-by: Tyler Rockwood <rockwood@redpanda.com>
Useful so we don't need to remember which units latency should be in.

Signed-off-by: Tyler Rockwood <rockwood@redpanda.com>
Mostly just applying clang-tidy auto fixes (range loops and no c-style
arrays)

Signed-off-by: Tyler Rockwood <rockwood@redpanda.com>
Signed-off-by: Tyler Rockwood <rockwood@redpanda.com>
This will allow deterministic tests by using `ss::manual_clock` instead
of `ss::lowres_clock` which will requiring sleeping and all sorts of not
fun patterns.

Signed-off-by: Tyler Rockwood <rockwood@redpanda.com>
Signed-off-by: Tyler Rockwood <rockwood@redpanda.com>
Make sure tasks from ss::manual_clock are completed when the clock
is advanced, we do this by asking the reactor to tell us when there are
no more tasks before we explicitly add tasks from the queue in
transform_manager into seastar's queue. Otherwise seastar's queue task
order randomizer can cause tasks to not be enqueued as the tests expect.

Signed-off-by: Tyler Rockwood <rockwood@redpanda.com>
Signed-off-by: Tyler Rockwood <rockwood@redpanda.com>
When we start tasks to create processors in parallel, we will create
multiple probes in `create_processor`, so instead create the probe once
in the callers of those methods so that we don't get duplicate
registration.

Signed-off-by: Tyler Rockwood <rockwood@redpanda.com>
In release mode seastar can execute tasks inline (when created using `ss::future::then`) instead of
submitting the task to the scheduler, which cause these tests to fail,
as we require control over when the callbacks are executed.

Signed-off-by: Tyler Rockwood <rockwood@redpanda.com>
@rockwotj
Copy link
Contributor Author

Force push: fix #13270 (comment)

Use the standard seastar mechanism via a gate. Much simpler.

Signed-off-by: Tyler Rockwood <rockwood@redpanda.com>
The concurrency is premature and prevents easy reasoning about
concurrent data structure modification.

If there are futures that take a long time, we should not do them in
parallel but move them off the queue (and extend the work queue to
support tracking these too).

Signed-off-by: Tyler Rockwood <rockwood@redpanda.com>
@rockwotj
Copy link
Contributor Author

Force push: remove unused header

@rockwotj
Copy link
Contributor Author

Force push: remove unused variable

dotnwat
dotnwat previously approved these changes Sep 13, 2023
For predicable memory usage and performance.

Signed-off-by: Tyler Rockwood <rockwood@redpanda.com>
There is no real tuning happening here, but this should only happen if
there are network failures fetching the binary (mitigated by retries in
the implementation) or because compilation fails (which is not
recoverable). So we can probably afford to delay longer.

Signed-off-by: Tyler Rockwood <rockwood@redpanda.com>
@rockwotj
Copy link
Contributor Author

Force push: fix oss build

@rockwotj
Copy link
Contributor Author

CI Failures: #13220, #12659

#13220 is reopening an issue that hadn't happened in a long time. However this PR is not adding code that is linked into the final binary, so it cannot be any changes here.

@rockwotj rockwotj merged commit 02a3d9d into redpanda-data:dev Sep 14, 2023
9 checks passed
@rockwotj rockwotj deleted the transform-manager branch September 14, 2023 13:37
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.

2 participants