-
Notifications
You must be signed in to change notification settings - Fork 411
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
Support cancel in AsyncTasks #8581
Conversation
/run-all-tests |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
Signed-off-by: CalvinNeo <calvinneo1995@gmail.com>
/run-all-tests |
/run-all-tests |
auto maybe_elapsed = fap_ctx->tasks_trace->queryElapsed(region_id); | ||
if unlikely (!maybe_elapsed.has_value()) | ||
{ | ||
GET_METRIC(tiflash_fap_task_result, type_failed_cancel).Increment(); | ||
LOG_INFO(log, "FAP is canceled at beginning region_id={} new_peer_id={}", region_id, new_peer_id); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In what situation will we run into this branch?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When a cancel happens in addTaskWithCancel
between if (cancel_handle->canceled())
, and the inner invokable object of (*p)()
actually called(after the addTaskWithCancel
quitted and release the lock).
It is very slightly chance.
/run-unit-test |
Signed-off-by: CalvinNeo <calvinneo1995@gmail.com>
…improve-async-tasks
/// `throw_if_noexist` controls whether to throw. | ||
/// NOTE: The task element will be removed after calling this function. | ||
template <typename ResultDropper> | ||
TaskState asyncCancelTask(Key k, ResultDropper result_dropper, bool throw_if_noexist) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It could also return std::future<std::optional<R>>
to support await-like call pattern. However, we don't make it too complicated. If you want to wait until the worker thread quits, then just use blockedCancelRunningTask
/run-all-tests |
// Only one thread can block cancel and wait. | ||
RUNTIME_CHECK_MSG(!cancel_handle->canceled(), "Try block cancel running task twice"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why we need this limitation?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because the AsyncTasks
only supports one consumer, so why would this only consumer cancel twice? I think it must be a mistake.
By checking duplicated key in asyncTasks
and checking duplicated cancel in blockedCancelRunningTask
will also guard the "one consumer" assumption.
…improve-async-tasks
Signed-off-by: CalvinNeo <calvinneo1995@gmail.com>
Signed-off-by: CalvinNeo <calvinneo1995@gmail.com>
} | ||
|
||
bool isReady(Key key) const | ||
TaskState unsafeQueryState(Key key) const |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this should be private?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
seems the friends decl does not work here too
Signed-off-by: CalvinNeo <calvinneo1995@gmail.com>
/run-all-tests |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM with small comments
{ | ||
std::unique_lock<std::mutex> l(mtx); | ||
auto it = tasks.find(key); | ||
RUNTIME_CHECK(it != tasks.end()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
RUNTIME_CHECK(it != tasks.end()); | |
RUNTIME_CHECK(it != tasks.end(), key); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What if the key is can not be format?
https://en.cppreference.com/w/cpp/utility/format/formattable
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: JaySon-Huang, Lloyd-Pottiger The full list of commands accepted by this bot can be found here. The pull request process is described here
Needs approval from an approver in each of these files:
Approvers can indicate their approval by writing |
[LGTM Timeline notifier]Timeline:
|
void doCancel() | ||
{ | ||
// Use lock here to prevent losing signal. | ||
std::scoped_lock<std::mutex> lock(mut); | ||
inner.store(true); | ||
cv.notify_all(); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: Why not acquiring lock will lead to signal lost?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Co-authored-by: JaySon <tshent@qq.com>
/hold |
…improve-async-tasks
/unhold |
/run-all-tests |
What problem does this PR solve?
Issue Number: close #8382
Problem Summary:
The
AsyncTasks
is a very simple manager for running and fetching result from a non-work-stealing thread pool. It could only have one producer and one consumer per task.In order to support canceling the running or queueing tasks, we proposed this PR.
Added cancel for
AsyncTasks
. So the transition will beCallers should guarantee a task is no longer accessible once canceled or has its result fetched.
The
AsyncTasks
is designed to have one consumer. If a task is canceled, then it will be unregistered fromAsyncTasks
immediately, the caller has to keep track of the state, and avoid calling cancel or fetching result again for the same task.The
AsyncTasks
will panic if register another task with the same key. However, if the task is canceled asyncly, the worker thread may not find acanceled
checkpoint immediately. If a new task is added in the meantime, then there could be two tasks manipulating some shared resources. In order to avoid this situation, block wait for cancel.What is changed and how it works?
Check List
Tests
Side effects
Documentation
Release note