Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 9 additions & 14 deletions include/pingcap/kv/LockResolver.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,25 +20,20 @@ struct TxnStatus
{
uint64_t ttl = 0;
uint64_t commit_ts = 0;
::kvrpcpb::Action action;
::kvrpcpb::Action action = ::kvrpcpb::Action::NoAction;
std::optional<::kvrpcpb::LockInfo> primary_lock;
bool isCommitted() const { return ttl == 0 && commit_ts > 0; }

bool isRolledBack() const
{
return ttl == 0 && commit_ts == 0
&& (action == kvrpcpb::Action::NoAction || action == kvrpcpb::Action::LockNotExistRollback
|| action == kvrpcpb::Action::TTLExpireRollback);
}

bool isCacheable() const
{
if (isCommitted())
{
return true;
}
if (ttl == 0)
{
if (action == kvrpcpb::Action::NoAction || action == kvrpcpb::Action::LockNotExistRollback
|| action == kvrpcpb::Action::TTLExpireRollback)
{
return true;
}
}
return false;
return isCommitted() || isRolledBack();
}
};

Expand Down
24 changes: 24 additions & 0 deletions src/kv/LockResolver.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,24 @@ namespace pingcap
{
namespace kv
{
namespace
{
bool canBypassLockForRead(const TxnStatus & status, uint64_t caller_start_ts)
{
if (status.ttl != 0)
return false;

if (status.isCommitted())
return status.commit_ts > caller_start_ts;

// Expired async-commit locks need resolveLockAsync to determine the final status.
if (status.primary_lock.has_value() && status.primary_lock->use_async_commit())
return false;

return status.isRolledBack();
}
} // namespace

std::string Lock::toDebugString() const
{
return "key: " + Redact::keyToDebugString(key) + " primary: " + Redact::keyToDebugString(primary)
Expand Down Expand Up @@ -56,6 +74,12 @@ int64_t LockResolver::resolveLocks(

if (status.ttl == 0)
{
if (!for_write && canBypassLockForRead(status, caller_start_ts))
{
pushed.push_back(lock->txn_id);
break;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The lock will not be resolved, so it must be put into resolved_locks to skip it in tikv. However the scanner doesn't use the returned pushed?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

In client-c, pushed will be treated as min_commit_ts_pushed in

auto before_expired = cluster->lock_resolver->resolveLocks(bo, task.req->start_ts, locks, pushed);
if (!pushed.empty())
{
min_commit_ts_pushed.addTimestamps(pushed);
}

And min_commit_ts_pushed wil be added to add_resolved_locks when constructing request

for (auto ts : min_commit_ts_pushed.getTimestamps())
{
cop_req_context->add_resolved_locks(ts);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I mean here

std::vector<uint64_t> pushed{};
auto ms_before_expired = snap.cluster->lock_resolver->resolveLocks(bo, snap.version, locks, pushed);

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Good catch. Scanner missed this path. Fixed it by adding returned pushed into snap.min_commit_ts_pushed after resolving scan response locks, and by adding snap.min_commit_ts_pushed to ScanRequest.context.resolved_locks on retry. Also added a scanner regression test for the committed-after-read case.

}

bool exists = true;
if (clean_txns.find(lock->txn_id) == clean_txns.end())
{
Expand Down
Loading