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

storage, lock_manager: Use the new lock waiting queue instead of WaiterManager to handle pessimistic lock waking up #13447

Merged
merged 78 commits into from Oct 26, 2022

Conversation

MyonKeminta
Copy link
Contributor

@MyonKeminta MyonKeminta commented Sep 9, 2022

What is changed and how it works?

Issue Number: ref #13298

What's Changed:

This PR refactors the implementation of lock waiting and waking up by introducing a new lock waiting queue, without changing the current lock-waiting behavior. This will be part of the work of introducing the new lock waiting model (#13298)

Note that this PR doesn't introduce any optimization to the lock-waiting model. It's a refectory which is the basis of the optimization.

Requires:

  1. WriteResultLockInfo (returned by AcquirePessimisticLock::process_write) carries parameters, which can be used for resuming the request in the future.
  2. WriteResultLockInfo will be converted into LockWaitContext and LockWaitEntry, and then send to both LockManager and the new LockWaitQueues.
  3. When a storage command releases some locks, will return the released locks to Scheduler::process_write, which will then call on_release_locks to pop lock waiting entries from the queues and wake up them asynchronously (to avoid increasing too much latency of the current command).
  4. The LockManager (and its inner module WaiterManager) no longer has the responsibility for waking up waiters, but keeps its functionality of handling timeout and performing deadlock detection. Instead, it has a new remove_lock_wait method to remove a waiter from it.
  5. Waiters in WaiterManager can now be uniquely identified by a LockWaitToken, and the data structure in WaiterManager is therefore changed. Accessing by lock hash and transaction ts is still necessary to handle the result of deadlock detection.
Updates the write path of acquiring lock and releasing lock to make use of the new `LockWaitQueue`. Some important points are:

1. `WriteResultLockInfo` (returned by `AcquirePessimisticLock::process_write`) carries parameters, which can be used for resuming the request in the future.
2. `WriteResultLockInfo` will be converted into `LockWaitContext` and `LockWaitEntry`, and then send to both `LockManager` and the new `LockWaitQueues`.
3. When a storage command releases some locks, will return the released locks to `Scheduler::process_write`, which will then call `on_release_locks` to pop lock waiting entries from the queues and wake up them asynchronously (to avoid increasing too much latency of the current command).
4. The `LockManager` (and its inner module `WaiterManager`) no longer has the responsibility for waking up waiters, but keeps its functionality of handling timeout and performing deadlock detection. Instead, it has a new `remove_lock_wait` method to remove a waiter from it.
5. Waiters in `WaiterManager` can now be uniquely identified by a `LockWaitToken`, and the data structure in `WaiterManager` is therefore changed. Accessing by lock hash and transaction ts is still necessary to handle the result of deadlock detection.

Related changes

  • PR to update pingcap/docs/pingcap/docs-cn:
  • Need to cherry-pick to the release branch

Check List

Tests (WIP)

  • Unit test
  • Integration test
  • Manual test (add detailed scripts or steps below)

Side effects

  • Performance regression
    • Consumes more CPU
    • Consumes more MEM

Release note

None

Signed-off-by: MyonKeminta <MyonKeminta@users.noreply.github.com>
Signed-off-by: MyonKeminta <MyonKeminta@users.noreply.github.com>
Signed-off-by: MyonKeminta <MyonKeminta@users.noreply.github.com>
Signed-off-by: MyonKeminta <MyonKeminta@users.noreply.github.com>
@ti-chi-bot
Copy link
Member

ti-chi-bot commented Sep 9, 2022

[REVIEW NOTIFICATION]

This pull request has been approved by:

  • cfzjywxk
  • sticnarf

To complete the pull request process, please ask the reviewers in the list to review by filling /cc @reviewer in the comment.
After your PR has acquired the required number of LGTMs, you can assign this pull request to the committer in the list by filling /assign @committer in the comment to help you merge this pull request.

The full list of commands accepted by this bot can be found here.

Reviewer can indicate their review by submitting an approval review.
Reviewer can cancel approval by submitting a request changes review.

@MyonKeminta
Copy link
Contributor Author

/release

Signed-off-by: MyonKeminta <MyonKeminta@users.noreply.github.com>
@MyonKeminta
Copy link
Contributor Author

/release

Signed-off-by: MyonKeminta <MyonKeminta@users.noreply.github.com>
@MyonKeminta
Copy link
Contributor Author

/release

Signed-off-by: MyonKeminta <MyonKeminta@users.noreply.github.com>
@MyonKeminta
Copy link
Contributor Author

/release

Signed-off-by: MyonKeminta <MyonKeminta@users.noreply.github.com>
Signed-off-by: MyonKeminta <MyonKeminta@users.noreply.github.com>
Signed-off-by: MyonKeminta <MyonKeminta@users.noreply.github.com>
…ager into a directory

Signed-off-by: MyonKeminta <MyonKeminta@users.noreply.github.com>
Signed-off-by: MyonKeminta <MyonKeminta@users.noreply.github.com>
@MyonKeminta
Copy link
Contributor Author

MyonKeminta commented Sep 19, 2022

Some test results:

Hot update

branch threads qps min avg 95 max -
this 1 410.96 5.00 7.30 8.58 213.08
this 16 427.75 4.96 112.19 484.44 1258.74
this 64 424.94 5.22 451.48 1561.52 2231.76
this 128 426.06 4.83 899.94 3511.19 4320.65
this 512 410.84 4.94 3715.17 16819.24 20016.79
master 1 402.02 5.45 7.46 8.74 37.34
master 16 401.51 5.51 119.52 475.79 919.10
master 64 405.23 4.80 473.39 1506.29 2981.45
master 128 414.36 5.05 925.11 3040.14 4031.46
master 512 412.20 4.62 3702.80 12163.09 19075.38

Sysbench common

branch scenario threads qps avg 99 999
this oltp_read_write 200 82390 2.17 14.6 28.8
master oltp_read_write 200 83619 2.12 14.2 27.7
this oltp_read_write 400 86140 4.09 27.8 48.8
master oltp_read_write 400 86207 4.03 27.3 47.4
this oltp_read_write 800 84894 8.22 54.3 88.6
master oltp_read_write 800 84330 8.23 52.6 73.5
this oltp_insert 200 46839 4.16 13.9 22.3
master oltp_insert 200 45583 4.28 14.2 21.8
this oltp_insert 400 49513 7.91 25.6 38.2
master oltp_insert 400 47189 8.34 40.4 47.0
this oltp_insert 800 53247 14.8 47.1 57.2
master oltp_insert 800 49555 15.9 57.1 80.3
this oltp_update_non_index 200 52848 3.67 12.3 26.1
master oltp_update_non_index 200 52431 3.71 11.3 24.7
this oltp_update_non_index 400 62729 6.25 25.0 32.9
master oltp_update_non_index 400 60274 6.51 26.3 34.6
this oltp_update_non_index 800 64708 12.2 42.9 64.4
master oltp_update_non_index 800 65010 12.1 46.2 69.4

TPCC

branch threads tps qps avg 99 999
this 800 4686 72893 10.7 187 399
master 800 4322 67236 11.7 178 419

(WIP...)

Signed-off-by: MyonKeminta <MyonKeminta@users.noreply.github.com>
Signed-off-by: MyonKeminta <MyonKeminta@users.noreply.github.com>
}

fn is_empty(&self) -> bool {
self.wait_table.is_empty()
self.waiter_pool.is_empty()
}

/// Returns the duplicated `Waiter` if there is.
Copy link
Contributor

Choose a reason for hiding this comment

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

The comment is stale. And the return value of this function is confusing now.

Copy link
Contributor

@sticnarf sticnarf left a comment

Choose a reason for hiding this comment

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

The rest looks okay to me.

As it's so large a pull request, I'm not confident that code review could find most of the problems. We probably need to rely on further integration tests in this aspect.

@cfzjywxk cfzjywxk requested a review from you06 October 20, 2022 09:00
Signed-off-by: MyonKeminta <MyonKeminta@users.noreply.github.com>
Signed-off-by: MyonKeminta <MyonKeminta@users.noreply.github.com>
@ti-chi-bot ti-chi-bot added the status/LGT1 Status: PR - There is already 1 approval label Oct 21, 2022
@MyonKeminta
Copy link
Contributor Author

@ekexium @you06 Please help me review this PR if you have time, thanks! Ask me if you have any question.

Copy link
Collaborator

@cfzjywxk cfzjywxk left a comment

Choose a reason for hiding this comment

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

LGTM

@@ -60,13 +61,6 @@ lazy_static! {
exponential_buckets(0.0001, 2.0, 20).unwrap() // 0.1ms ~ 104s
)
.unwrap();
pub static ref WAIT_TABLE_STATUS_GAUGE: WaitTableStatusGauge = register_static_int_gauge_vec!(
Copy link
Collaborator

Choose a reason for hiding this comment

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

Do any related panels need to be removed accordingly?

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 didn't remove that panel, but I put LOCK_WAIT_QUEUE_ENTRIES_GAUGE_VEC to the same panel.

@ti-chi-bot ti-chi-bot added status/LGT2 Status: PR - There are already 2 approvals and removed status/LGT1 Status: PR - There is already 1 approval labels Oct 24, 2022
}
}
DetectType::CleanUpWaitFor => {
detect_table.clean_up_wait_for(txn_ts, lock.ts, lock.hash)
let wait_info = wait_info.unwrap();
detect_table.clean_up_wait_for(txn_ts, wait_info.lock_digest)
Copy link
Contributor

Choose a reason for hiding this comment

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

How about merge them into one line?

@@ -12,6 +12,7 @@ make_auto_flush_static_metric! {
detect,
clean_up_wait_for,
clean_up,
update_wait_for,
Copy link
Contributor

Choose a reason for hiding this comment

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

Is it intentionally unused?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, it's unused currently, so does the update_wait_for method of LockManager.

pub(crate) fn unlock_key(&mut self, key: Key, pessimistic: bool) -> Option<ReleasedLock> {
let released = ReleasedLock::new(&key, pessimistic);
/// Append a modify that unlocks the key. If the lock is removed due to
/// committing, a non-zero `commit_ts` need to be provided; otherwise if
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
/// committing, a non-zero `commit_ts` need to be provided; otherwise if
/// committing, a non-zero `commit_ts` needs to be provided; otherwise if

// requests to detect deadlock, clean up its wait-for entries in the
// deadlock detector.
if is_pessimistic_txn && self.remove_from_detected(lock_ts) {
self.detector_scheduler.clean_up(lock_ts);
Copy link
Contributor

@ekexium ekexium Oct 24, 2022

Choose a reason for hiding this comment

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

Is there an equivalent part of the clean up logic 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.

Here the old logic wakes up all waiters waiting for the lock with lock_ts on the specified key, and cleans all edges that waits for the lock_ts from the detector. In new logic, waking-up happens in the new lock waiting queue, and when a lock-waiting request is finished (either canceled or resumed and successfully acquired, which is not yet supported), the remove_lock_wait function in LockManager will be invoked, which then leads to a call to clean_up_wait_for (here)

Signed-off-by: MyonKeminta <MyonKeminta@users.noreply.github.com>
.remove("wake_up_delay_duration")
.map(ReadableDuration::from)
{
info!(
Copy link
Contributor

Choose a reason for hiding this comment

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

Why only the config wake_up_delay_duration need to print log?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The logs about the two config items mentioned here were previously printed in waiter_manager.rs when handling Task::ChangeConfig message. Now the wake_up_delay_duration is changed to be handled somewhere else, so I printed it here. When changing wait_for_lock_timeout, the log will still be printed at the old place.

}
self.waiter_mgr_scheduler.wait_for(
Copy link
Contributor

Choose a reason for hiding this comment

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

Is there any special meanings that you moved self.waiter_mgr_scheduler.wait_for behind self.detector_scheduler.detect?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No. It seems to be an accident. I'll change it back.

/// `Notify` consumes the `Waiter` to notify the corresponding transaction
/// going on.
fn notify(self) {
/// Consumes the `Waiter` to notify the corresponding transaction `going on.
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
/// Consumes the `Waiter` to notify the corresponding transaction `going on.
/// Consumes the `Waiter` to notify the corresponding transaction going on.

}

fn cancel_for_timeout(self, _skip_resolving_lock: bool) -> KeyLockWaitInfo {
let lock_info = self.wait_info.lock_info.clone();
Copy link
Contributor

Choose a reason for hiding this comment

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

Why do we need to clone lock_info?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

If we move it, we will not be able to call another method cancel on self since self is partially moved. And also, the function needs to return a complete KeyLockWaitInfo to be used by the caller.

@cfzjywxk cfzjywxk requested a review from ekexium October 25, 2022 14:41
Copy link
Contributor

@ekexium ekexium left a comment

Choose a reason for hiding this comment

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

I don't see other problems

detector_scheduler,
default_wait_for_lock_timeout: cfg.wait_for_lock_timeout,
wake_up_delay_duration: cfg.wake_up_delay_duration,
// wake_up_delay_duration: cfg.wake_up_delay_duration,
Copy link
Contributor

Choose a reason for hiding this comment

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

Shall we just remove it?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes. I forgot it.

Signed-off-by: MyonKeminta <MyonKeminta@users.noreply.github.com>
@MyonKeminta
Copy link
Contributor Author

/merge

@ti-chi-bot
Copy link
Member

@MyonKeminta: It seems you want to merge this PR, I will help you trigger all the tests:

/run-all-tests

You only need to trigger /merge once, and if the CI test fails, you just re-trigger the test that failed and the bot will merge the PR for you after the CI passes.

If you have any questions about the PR merge process, please refer to pr process.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the ti-community-infra/tichi repository.

@ti-chi-bot
Copy link
Member

This pull request has been accepted and is ready to merge.

Commit hash: 77caef7

@ti-chi-bot ti-chi-bot added the status/can-merge Status: Can merge to base branch label Oct 26, 2022
@ti-chi-bot
Copy link
Member

@MyonKeminta: Your PR was out of date, I have automatically updated it for you.

At the same time I will also trigger all tests for you:

/run-all-tests

If the CI test fails, you just re-trigger the test that failed and the bot will merge the PR for you after the CI passes.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the ti-community-infra/tichi repository.

@ti-chi-bot ti-chi-bot merged commit a4dc37b into tikv:master Oct 26, 2022
@ti-chi-bot ti-chi-bot added this to the Pool milestone Oct 26, 2022
@MyonKeminta MyonKeminta deleted the m/new-lock-waiting-queue branch November 29, 2022 19:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
release-note-none size/XXL status/can-merge Status: Can merge to base branch status/LGT2 Status: PR - There are already 2 approvals
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

8 participants