Skip to content

Commit d42b31a

Browse files
authored
Return live locks on resolve locks error (#417)
* API v2 part1 Signed-off-by: Ping Yu <yuping@pingcap.com> * inplace encoding Signed-off-by: Ping Yu <yuping@pingcap.com> * polish Signed-off-by: Ping Yu <yuping@pingcap.com> * polish Signed-off-by: Ping Yu <yuping@pingcap.com> * export proto Signed-off-by: Ping Yu <yuping@pingcap.com> * fix set_context Signed-off-by: Ping Yu <yuping@pingcap.com> * get live locks Signed-off-by: Ping Yu <yuping@pingcap.com> * wip Signed-off-by: Ping Yu <yuping@pingcap.com> * add Codec parameter to Transaction & Snapshot Signed-off-by: Ping Yu <yuping@pingcap.com> * polish Signed-off-by: Ping Yu <yuping@pingcap.com> --------- Signed-off-by: Ping Yu <yuping@pingcap.com>
1 parent 4b0e844 commit d42b31a

File tree

4 files changed

+20
-20
lines changed

4 files changed

+20
-20
lines changed

src/common/errors.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use std::result;
44

55
use thiserror::Error;
66

7+
use crate::proto::kvrpcpb;
78
use crate::BoundRange;
89

910
/// An error originating from the TiKV client or dependencies.
@@ -18,7 +19,7 @@ pub enum Error {
1819
DuplicateKeyInsertion,
1920
/// Failed to resolve a lock
2021
#[error("Failed to resolve lock")]
21-
ResolveLockError,
22+
ResolveLockError(Vec<kvrpcpb::LockInfo>),
2223
/// Will raise this error when using a pessimistic txn only operation on an optimistic txn
2324
#[error("Invalid operation for this type of transaction")]
2425
InvalidTransactionType,

src/request/plan.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -434,15 +434,16 @@ where
434434
}
435435

436436
if self.backoff.is_none() {
437-
return Err(Error::ResolveLockError);
437+
return Err(Error::ResolveLockError(locks));
438438
}
439439

440440
let pd_client = self.pd_client.clone();
441-
if resolve_locks(locks, pd_client.clone()).await? {
441+
let live_locks = resolve_locks(locks, pd_client.clone()).await?;
442+
if live_locks.is_empty() {
442443
result = self.inner.execute().await?;
443444
} else {
444445
match clone.backoff.next_delay_duration() {
445-
None => return Err(Error::ResolveLockError),
446+
None => return Err(Error::ResolveLockError(live_locks)),
446447
Some(delay_duration) => {
447448
sleep(delay_duration).await;
448449
result = clone.inner.execute().await?;

src/transaction/lock.rs

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ use crate::Result;
3434

3535
const RESOLVE_LOCK_RETRY_LIMIT: usize = 10;
3636

37-
/// _Resolves_ the given locks. Returns whether all the given locks are resolved.
37+
/// _Resolves_ the given locks. Returns locks still live. When there is no live locks, all the given locks are resolved.
3838
///
3939
/// If a key has a lock, the latest status of the key is unknown. We need to "resolve" the lock,
4040
/// which means the key is finally either committed or rolled back, before we read the value of
@@ -44,18 +44,16 @@ const RESOLVE_LOCK_RETRY_LIMIT: usize = 10;
4444
pub async fn resolve_locks(
4545
locks: Vec<kvrpcpb::LockInfo>,
4646
pd_client: Arc<impl PdClient>,
47-
) -> Result<bool> {
47+
) -> Result<Vec<kvrpcpb::LockInfo> /* live_locks */> {
4848
debug!("resolving locks");
4949
let ts = pd_client.clone().get_timestamp().await?;
50-
let mut has_live_locks = false;
51-
let expired_locks = locks.into_iter().filter(|lock| {
52-
let expired = ts.physical - Timestamp::from_version(lock.lock_version).physical
53-
>= lock.lock_ttl as i64;
54-
if !expired {
55-
has_live_locks = true;
56-
}
57-
expired
58-
});
50+
let (expired_locks, live_locks) =
51+
locks
52+
.into_iter()
53+
.partition::<Vec<kvrpcpb::LockInfo>, _>(|lock| {
54+
ts.physical - Timestamp::from_version(lock.lock_version).physical
55+
>= lock.lock_ttl as i64
56+
});
5957

6058
// records the commit version of each primary lock (representing the status of the transaction)
6159
let mut commit_versions: HashMap<u64, u64> = HashMap::new();
@@ -103,7 +101,7 @@ pub async fn resolve_locks(
103101
.or_insert_with(HashSet::new)
104102
.insert(cleaned_region);
105103
}
106-
Ok(!has_live_locks)
104+
Ok(live_locks)
107105
}
108106

109107
async fn resolve_lock_with_retry(
@@ -290,12 +288,12 @@ impl LockResolver {
290288
}
291289

292290
match &status.kind {
293-
TransactionStatusKind::Locked(..) => {
291+
TransactionStatusKind::Locked(_, lock_info) => {
294292
error!(
295293
"cleanup_locks fail to clean locks, this result is not expected. txn_id:{}",
296294
txn_id
297295
);
298-
return Err(Error::ResolveLockError);
296+
return Err(Error::ResolveLockError(vec![lock_info.clone()]));
299297
}
300298
TransactionStatusKind::Committed(ts) => txn_infos.insert(txn_id, ts.version()),
301299
TransactionStatusKind::RolledBack => txn_infos.insert(txn_id, 0),

src/transaction/requests.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -950,7 +950,7 @@ mod tests {
950950
let input = vec![
951951
Ok(resp1),
952952
Ok(resp_empty_value),
953-
Err(ResolveLockError),
953+
Err(ResolveLockError(vec![])),
954954
Ok(resp_not_found),
955955
];
956956
let result = merger.merge(input);
@@ -960,7 +960,7 @@ mod tests {
960960
success_keys,
961961
} = result.unwrap_err()
962962
{
963-
assert!(matches!(*inner, ResolveLockError));
963+
assert!(matches!(*inner, ResolveLockError(_)));
964964
assert_eq!(
965965
success_keys,
966966
vec![key1.to_vec(), key2.to_vec(), key3.to_vec(), key4.to_vec()]

0 commit comments

Comments
 (0)