Skip to content

Commit c59911a

Browse files
authored
Merge pull request #228 from andylokandy/not_founds
Distinguish not existing key and existing key with empty value in get_for_update
2 parents b4e5d37 + 95a6828 commit c59911a

File tree

3 files changed

+27
-6
lines changed

3 files changed

+27
-6
lines changed

src/transaction/requests.rs

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -521,7 +521,7 @@ impl KvRequest for kvrpcpb::PessimisticLockRequest {
521521
// We need to pair keys and values returned somewhere.
522522
// But it's blocked by the structure of the program that `map_result` only accepts the response as input
523523
// Before we fix this `batch_get_for_update` is problematic.
524-
type Result = Vec<Vec<u8>>;
524+
type Result = Vec<Option<Vec<u8>>>;
525525
type RpcResponse = kvrpcpb::PessimisticLockResponse;
526526
type KeyData = Vec<kvrpcpb::Mutation>;
527527

@@ -551,7 +551,24 @@ impl KvRequest for kvrpcpb::PessimisticLockRequest {
551551
}
552552

553553
fn map_result(mut resp: Self::RpcResponse) -> Self::Result {
554-
resp.take_values()
554+
let values = resp.take_values();
555+
let not_founds = resp.take_not_founds();
556+
if not_founds.is_empty() {
557+
// Legacy TiKV does not distiguish not existing key and existing key
558+
// that with empty value. We assume that key does not exist if value
559+
// is emtpy.
560+
values
561+
.into_iter()
562+
.map(|v| if v.is_empty() { None } else { Some(v) })
563+
.collect()
564+
} else {
565+
assert_eq!(values.len(), not_founds.len());
566+
values
567+
.into_iter()
568+
.zip(not_founds.into_iter())
569+
.map(|(v, not_found)| if not_found { None } else { Some(v) })
570+
.collect()
571+
}
555572
}
556573

557574
async fn reduce(results: BoxStream<'static, Result<Self::Result>>) -> Result<Self::Result> {

src/transaction/transaction.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -128,21 +128,21 @@ impl Transaction {
128128
/// # let client = TransactionClient::new(vec!["192.168.0.100", "192.168.0.101"]).await.unwrap();
129129
/// let mut txn = client.begin_pessimistic().await.unwrap();
130130
/// let key = "TiKV".to_owned();
131-
/// let result: Value = txn.get_for_update(key).await.unwrap();
131+
/// let result: Value = txn.get_for_update(key).await.unwrap().unwrap();
132132
/// // now the key "TiKV" is locked, other transactions cannot modify it
133133
/// // Finish the transaction...
134134
/// txn.commit().await.unwrap();
135135
/// # });
136136
/// ```
137-
pub async fn get_for_update(&mut self, key: impl Into<Key>) -> Result<Value> {
137+
pub async fn get_for_update(&mut self, key: impl Into<Key>) -> Result<Option<Value>> {
138138
self.check_allow_operation()?;
139139
if !self.is_pessimistic() {
140140
Err(Error::InvalidTransactionType)
141141
} else {
142142
let key = key.into();
143143
let mut values = self.pessimistic_lock(iter::once(key.clone()), true).await?;
144144
assert!(values.len() == 1);
145-
Ok(values.swap_remove(0))
145+
Ok(values.pop().unwrap())
146146
}
147147
}
148148

@@ -545,7 +545,7 @@ impl Transaction {
545545
&mut self,
546546
keys: impl IntoIterator<Item = impl Into<Key>>,
547547
need_value: bool,
548-
) -> Result<Vec<Vec<u8>>> {
548+
) -> Result<Vec<Option<Vec<u8>>>> {
549549
assert!(
550550
matches!(self.options.kind, TransactionKind::Pessimistic(_)),
551551
"`pessimistic_lock` is only valid to use with pessimistic transactions"

tikv-client-proto/proto/kvrpcpb.proto

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,10 @@ message PessimisticLockResponse {
160160
// The values is set if 'return_values' is true in the request and no error.
161161
// If 'force' is true, this field is not used.
162162
repeated bytes values = 5;
163+
// Indicates whether the values at the same index is correspond to an existing key.
164+
// In legacy TiKV, this field is not used even 'force' is false. In that case, an empty value indicates
165+
// two possible situations: (1) the key does not exist. (2) the key exists but the value is empty.
166+
repeated bool not_founds = 6;
163167
}
164168

165169
// Unlock keys locked using `PessimisticLockRequest`.

0 commit comments

Comments
 (0)