Skip to content

Commit d07e80f

Browse files
committed
Merge branch 'master' into sync-api-txclient
2 parents 4807831 + 9d9b680 commit d07e80f

File tree

16 files changed

+386
-57
lines changed

16 files changed

+386
-57
lines changed

Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ prometheus = ["prometheus/push", "prometheus/process"]
1414
# Enable integration tests with a running TiKV and PD instance.
1515
# Use $PD_ADDRS, comma separated, to set the addresses the tests use.
1616
integration-tests = []
17-
apiv2-no-prefix = []
1817

1918
[lib]
2019
name = "tikv_client"

Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@ export RUSTFLAGS=-Dwarnings
55
export PD_ADDRS ?= 127.0.0.1:2379
66
export MULTI_REGION ?= 1
77

8-
ALL_FEATURES := integration-tests apiv2-no-prefix
8+
ALL_FEATURES := integration-tests
99

1010
NEXTEST_ARGS := --config-file $(shell pwd)/config/nextest.toml
1111

12-
INTEGRATION_TEST_ARGS := --features "integration-tests apiv2-no-prefix" --test-threads 1
12+
INTEGRATION_TEST_ARGS := --features "integration-tests" --test-threads 1
1313

1414
RUN_INTEGRATION_TEST := cargo nextest run ${NEXTEST_ARGS} --all ${INTEGRATION_TEST_ARGS}
1515

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ The TiKV client is a Rust library (crate). To use this crate in your project, ad
1717

1818
```toml
1919
[dependencies]
20-
tikv-client = "0.3"
20+
tikv-client = "0.4"
2121
```
2222

2323
### Prerequisites

src/common/errors.rs

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,20 @@ use crate::proto::kvrpcpb;
88
use crate::region::RegionVerId;
99
use crate::BoundRange;
1010

11+
/// Protobuf-generated region-level error returned by TiKV.
12+
///
13+
/// This type is generated from TiKV's protobuf definitions and may change in a
14+
/// future release even if the wire format is compatible.
15+
#[doc(inline)]
16+
pub use crate::proto::errorpb::Error as ProtoRegionError;
17+
18+
/// Protobuf-generated per-key error returned by TiKV.
19+
///
20+
/// This type is generated from TiKV's protobuf definitions and may change in a
21+
/// future release even if the wire format is compatible.
22+
#[doc(inline)]
23+
pub use crate::proto::kvrpcpb::KeyError as ProtoKeyError;
24+
1125
/// An error originating from the TiKV client or dependencies.
1226
#[derive(Debug, Error)]
1327
#[allow(clippy::large_enum_variant)]
@@ -63,13 +77,13 @@ pub enum Error {
6377
Canceled(#[from] futures::channel::oneshot::Canceled),
6478
/// Errors caused by changes of region information
6579
#[error("Region error: {0:?}")]
66-
RegionError(Box<crate::proto::errorpb::Error>),
80+
RegionError(Box<ProtoRegionError>),
6781
/// Whether the transaction is committed or not is undetermined
6882
#[error("Whether the transaction is committed or not is undetermined")]
6983
UndeterminedError(Box<Error>),
70-
/// Wraps `crate::proto::kvrpcpb::KeyError`
84+
/// Wraps a per-key error returned by TiKV.
7185
#[error("{0:?}")]
72-
KeyError(Box<crate::proto::kvrpcpb::KeyError>),
86+
KeyError(Box<ProtoKeyError>),
7387
/// Multiple errors generated from the ExtractError plan.
7488
#[error("Multiple errors: {0:?}")]
7589
ExtractedErrors(Vec<Error>),
@@ -122,14 +136,14 @@ Use TransactionClient instead or move SyncTransactionClient usage outside the as
122136
NestedRuntimeError(String),
123137
}
124138

125-
impl From<crate::proto::errorpb::Error> for Error {
126-
fn from(e: crate::proto::errorpb::Error) -> Error {
139+
impl From<ProtoRegionError> for Error {
140+
fn from(e: ProtoRegionError) -> Error {
127141
Error::RegionError(Box::new(e))
128142
}
129143
}
130144

131-
impl From<crate::proto::kvrpcpb::KeyError> for Error {
132-
fn from(e: crate::proto::kvrpcpb::KeyError) -> Error {
145+
impl From<ProtoKeyError> for Error {
146+
fn from(e: ProtoKeyError) -> Error {
133147
Error::KeyError(Box::new(e))
134148
}
135149
}

src/common/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,6 @@ mod errors;
44
pub mod security;
55

66
pub use self::errors::Error;
7+
pub use self::errors::ProtoKeyError;
8+
pub use self::errors::ProtoRegionError;
79
pub use self::errors::Result;

src/kv/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ pub use key::KvPairTTL;
1414
pub use kvpair::KvPair;
1515
pub use value::Value;
1616

17-
struct HexRepr<'a>(pub &'a [u8]);
17+
pub struct HexRepr<'a>(pub &'a [u8]);
1818

1919
impl fmt::Display for HexRepr<'_> {
2020
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {

src/lib.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,10 @@ pub use common::security::SecurityManager;
122122
#[doc(inline)]
123123
pub use common::Error;
124124
#[doc(inline)]
125+
pub use common::ProtoKeyError;
126+
#[doc(inline)]
127+
pub use common::ProtoRegionError;
128+
#[doc(inline)]
125129
pub use common::Result;
126130
#[doc(inline)]
127131
pub use config::Config;
@@ -157,6 +161,8 @@ pub use crate::transaction::CheckLevel;
157161
#[doc(inline)]
158162
pub use crate::transaction::Client as TransactionClient;
159163
#[doc(inline)]
164+
pub use crate::transaction::ProtoLockInfo;
165+
#[doc(inline)]
160166
pub use crate::transaction::Snapshot;
161167
#[doc(inline)]
162168
pub use crate::transaction::SyncSnapshot;

src/request/keyspace.rs

Lines changed: 132 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ pub const TXN_KEY_PREFIX: u8 = b'x';
1313
pub const KEYSPACE_PREFIX_LEN: usize = 4;
1414

1515
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
16+
#[non_exhaustive]
1617
pub enum Keyspace {
1718
Disable,
1819
Enable {
@@ -23,7 +24,6 @@ pub enum Keyspace {
2324
/// This mode is intended for **server-side embedding** use cases (e.g. embedding this client in
2425
/// `tikv-server`) where keys are already in API V2 "logical key bytes" form and must be passed
2526
/// through unchanged.
26-
#[cfg(feature = "apiv2-no-prefix")]
2727
ApiV2NoPrefix,
2828
}
2929

@@ -38,7 +38,6 @@ impl Keyspace {
3838
match self {
3939
Keyspace::Disable => kvrpcpb::ApiVersion::V1,
4040
Keyspace::Enable { .. } => kvrpcpb::ApiVersion::V2,
41-
#[cfg(feature = "apiv2-no-prefix")]
4241
Keyspace::ApiV2NoPrefix => kvrpcpb::ApiVersion::V2,
4342
}
4443
}
@@ -183,6 +182,32 @@ impl TruncateKeyspace for Vec<crate::proto::kvrpcpb::LockInfo> {
183182
}
184183
}
185184

185+
impl EncodeKeyspace for Vec<crate::proto::kvrpcpb::LockInfo> {
186+
fn encode_keyspace(mut self, keyspace: Keyspace, key_mode: KeyMode) -> Self {
187+
if !matches!(keyspace, Keyspace::Enable { .. }) {
188+
return self;
189+
}
190+
for lock in &mut self {
191+
take_mut::take(&mut lock.key, |key| {
192+
Key::from(key).encode_keyspace(keyspace, key_mode).into()
193+
});
194+
take_mut::take(&mut lock.primary_lock, |primary| {
195+
Key::from(primary)
196+
.encode_keyspace(keyspace, key_mode)
197+
.into()
198+
});
199+
for secondary in lock.secondaries.iter_mut() {
200+
take_mut::take(secondary, |secondary| {
201+
Key::from(secondary)
202+
.encode_keyspace(keyspace, key_mode)
203+
.into()
204+
});
205+
}
206+
}
207+
self
208+
}
209+
}
210+
186211
fn keyspace_prefix(keyspace_id: u32, key_mode: KeyMode) -> [u8; KEYSPACE_PREFIX_LEN] {
187212
let mut prefix = keyspace_id.to_be_bytes();
188213
prefix[0] = match key_mode {
@@ -274,26 +299,105 @@ mod tests {
274299
mutation.encode_keyspace(keyspace, key_mode),
275300
expected_mutation
276301
);
302+
303+
let key_mode = KeyMode::Txn;
304+
let lock = crate::proto::kvrpcpb::LockInfo {
305+
key: vec![b'k', b'1'],
306+
primary_lock: vec![b'p', b'1'],
307+
secondaries: vec![vec![b's', b'1'], vec![b's', b'2']],
308+
..Default::default()
309+
};
310+
let locks = vec![lock].encode_keyspace(keyspace, key_mode);
311+
assert_eq!(locks.len(), 1);
312+
assert_eq!(locks[0].key, vec![b'x', 0, 0xDE, 0xAD, b'k', b'1']);
313+
assert_eq!(locks[0].primary_lock, vec![b'x', 0, 0xDE, 0xAD, b'p', b'1']);
314+
assert_eq!(
315+
locks[0].secondaries,
316+
vec![
317+
vec![b'x', 0, 0xDE, 0xAD, b's', b'1'],
318+
vec![b'x', 0, 0xDE, 0xAD, b's', b'2']
319+
]
320+
);
277321
}
278322

279323
#[test]
280324
fn test_truncate_version() {
281-
let key = Key::from(vec![b'r', 0, 0xDE, 0xAD, 0xBE, 0xEF]);
282325
let keyspace = Keyspace::Enable {
283326
keyspace_id: 0xDEAD,
284327
};
328+
329+
let key = Key::from(vec![b'r', 0, 0xDE, 0xAD, 0xBE, 0xEF]);
285330
let expected_key = Key::from(vec![0xBE, 0xEF]);
286331
assert_eq!(key.truncate_keyspace(keyspace), expected_key);
287332

288333
let key = Key::from(vec![b'x', 0, 0xDE, 0xAD, 0xBE, 0xEF]);
289-
let keyspace = Keyspace::Enable {
290-
keyspace_id: 0xDEAD,
291-
};
292334
let expected_key = Key::from(vec![0xBE, 0xEF]);
293335
assert_eq!(key.truncate_keyspace(keyspace), expected_key);
336+
337+
let pair = KvPair(Key::from(vec![b'x', 0, 0xDE, 0xAD, b'k']), vec![b'v']);
338+
let expected_pair = KvPair(Key::from(vec![b'k']), vec![b'v']);
339+
assert_eq!(pair.truncate_keyspace(keyspace), expected_pair);
340+
341+
let range = Range {
342+
start: Key::from(vec![b'x', 0, 0xDE, 0xAD, b'a']),
343+
end: Key::from(vec![b'x', 0, 0xDE, 0xAD, b'b']),
344+
};
345+
let expected_range = Range {
346+
start: Key::from(vec![b'a']),
347+
end: Key::from(vec![b'b']),
348+
};
349+
assert_eq!(range.truncate_keyspace(keyspace), expected_range);
350+
351+
let ranges = vec![
352+
Range {
353+
start: Key::from(vec![b'x', 0, 0xDE, 0xAD, b'a']),
354+
end: Key::from(vec![b'x', 0, 0xDE, 0xAD, b'b']),
355+
},
356+
Range {
357+
start: Key::from(vec![b'x', 0, 0xDE, 0xAD, b'c']),
358+
end: Key::from(vec![b'x', 0, 0xDE, 0xAD, b'd']),
359+
},
360+
];
361+
let expected_ranges = vec![
362+
Range {
363+
start: Key::from(vec![b'a']),
364+
end: Key::from(vec![b'b']),
365+
},
366+
Range {
367+
start: Key::from(vec![b'c']),
368+
end: Key::from(vec![b'd']),
369+
},
370+
];
371+
assert_eq!(ranges.truncate_keyspace(keyspace), expected_ranges);
372+
373+
let pairs = vec![
374+
KvPair(Key::from(vec![b'x', 0, 0xDE, 0xAD, b'k']), vec![b'v']),
375+
KvPair(
376+
Key::from(vec![b'x', 0, 0xDE, 0xAD, b'k', b'2']),
377+
vec![b'v', b'2'],
378+
),
379+
];
380+
let expected_pairs = vec![
381+
KvPair(Key::from(vec![b'k']), vec![b'v']),
382+
KvPair(Key::from(vec![b'k', b'2']), vec![b'v', b'2']),
383+
];
384+
assert_eq!(pairs.truncate_keyspace(keyspace), expected_pairs);
385+
386+
let lock = crate::proto::kvrpcpb::LockInfo {
387+
key: vec![b'x', 0, 0xDE, 0xAD, b'k'],
388+
primary_lock: vec![b'x', 0, 0xDE, 0xAD, b'p'],
389+
secondaries: vec![vec![b'x', 0, 0xDE, 0xAD, b's']],
390+
..Default::default()
391+
};
392+
let expected_lock = crate::proto::kvrpcpb::LockInfo {
393+
key: vec![b'k'],
394+
primary_lock: vec![b'p'],
395+
secondaries: vec![vec![b's']],
396+
..Default::default()
397+
};
398+
assert_eq!(vec![lock].truncate_keyspace(keyspace), vec![expected_lock]);
294399
}
295400

296-
#[cfg(feature = "apiv2-no-prefix")]
297401
#[test]
298402
fn test_apiv2_no_prefix_api_version() {
299403
assert_eq!(
@@ -302,7 +406,6 @@ mod tests {
302406
);
303407
}
304408

305-
#[cfg(feature = "apiv2-no-prefix")]
306409
#[test]
307410
fn test_apiv2_no_prefix_encode_is_noop() {
308411
let keyspace = Keyspace::ApiV2NoPrefix;
@@ -323,9 +426,29 @@ mod tests {
323426
mutation.clone().encode_keyspace(keyspace, key_mode),
324427
mutation
325428
);
429+
430+
let lock = crate::proto::kvrpcpb::LockInfo {
431+
key: vec![b'x', 0, 0, 0, b'k'],
432+
primary_lock: vec![b'x', 0, 0, 0, b'p'],
433+
secondaries: vec![vec![b'x', 0, 0, 0, b's']],
434+
..Default::default()
435+
};
436+
let locks = vec![lock];
437+
assert_eq!(locks.clone().encode_keyspace(keyspace, key_mode), locks);
438+
439+
let lock = crate::proto::kvrpcpb::LockInfo {
440+
key: vec![b'k', b'1'],
441+
primary_lock: vec![b'p', b'1'],
442+
secondaries: vec![vec![b's', b'1']],
443+
..Default::default()
444+
};
445+
let locks = vec![lock.clone()];
446+
assert_eq!(
447+
locks.clone().encode_keyspace(Keyspace::Disable, key_mode),
448+
locks
449+
);
326450
}
327451

328-
#[cfg(feature = "apiv2-no-prefix")]
329452
#[test]
330453
fn test_apiv2_no_prefix_truncate_is_noop() {
331454
let keyspace = Keyspace::ApiV2NoPrefix;

src/request/plan.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ impl<Req: KvRequest + StoreRequest> StoreRequest for Dispatch<Req> {
8888
const MULTI_REGION_CONCURRENCY: usize = 16;
8989
const MULTI_STORES_CONCURRENCY: usize = 16;
9090

91-
fn is_grpc_error(e: &Error) -> bool {
91+
pub(crate) fn is_grpc_error(e: &Error) -> bool {
9292
matches!(e, Error::GrpcAPI(_) | Error::Grpc(_))
9393
}
9494

src/store/errors.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
// Copyright 2019 TiKV Project Authors. Licensed under Apache-2.0.
22

3-
use std::fmt::Display;
4-
53
use crate::proto::kvrpcpb;
64
use crate::Error;
75

@@ -162,11 +160,15 @@ impl HasKeyErrors for kvrpcpb::PessimisticRollbackResponse {
162160
}
163161
}
164162

165-
impl<T: HasKeyErrors, E: Display> HasKeyErrors for Result<T, E> {
163+
impl<T: HasKeyErrors> HasKeyErrors for Result<T, Error> {
166164
fn key_errors(&mut self) -> Option<Vec<Error>> {
167165
match self {
168166
Ok(x) => x.key_errors(),
169-
Err(e) => Some(vec![Error::StringError(e.to_string())]),
167+
Err(Error::MultipleKeyErrors(errs)) => Some(std::mem::take(errs)),
168+
Err(e) => Some(vec![std::mem::replace(
169+
e,
170+
Error::StringError("".to_string()), // placeholder, no use.
171+
)]),
170172
}
171173
}
172174
}

0 commit comments

Comments
 (0)