Skip to content

Commit 4e9a42f

Browse files
sticnarfHoverbear
authored andcommitted
Use failure for error management (#23)
* Use failure for error management. Signed-off-by: Yilin Chen <[email protected]> * Add error constructors Signed-off-by: Yilin Chen <[email protected]> * Remove NoSuchKey error Signed-off-by: Yilin Chen <[email protected]>
1 parent a5a6b15 commit 4e9a42f

File tree

11 files changed

+281
-175
lines changed

11 files changed

+281
-175
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,14 @@ name = "tikv_client"
1515
futures = "0.1"
1616
serde = "1.0"
1717
serde_derive = "1.0"
18-
quick-error = "1.2"
1918
grpcio = { version = "0.4", features = [ "secure" ] }
2019
protobuf = "~2.0"
2120
tokio-core = "0.1"
2221
tokio-timer = "0.2"
2322
fxhash = "0.2"
2423
lazy_static = "0.2.1"
2524
log = "0.3.9"
25+
failure = "0.1"
2626

2727
[dependencies.kvproto]
2828
git = "https://github.com/pingcap/kvproto.git"

examples/raw.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -70,10 +70,8 @@ fn main() -> Result<()> {
7070
.expect("Could not delete value");
7171
println!("Key: {:?} deleted", key);
7272

73-
client
74-
.get(key)
75-
.wait()
76-
.expect_err("Get returned value for not existing key");
73+
// Get returns None for non-existing key
74+
assert!(client.get(key).wait()?.is_none());
7775

7876
let pairs: Vec<KvPair> = (1..3)
7977
.map(|i| KvPair::from((Key::from(format!("k{}", i)), Value::from(format!("v{}", i)))))

src/errors.rs

Lines changed: 235 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -10,127 +10,245 @@
1010
// distributed under the License is distributed on an "AS IS" BASIS,
1111
// See the License for the specific language governing permissions and
1212
// limitations under the License.
13-
13+
use failure::{Backtrace, Context, Fail};
1414
use grpcio;
15-
use quick_error::quick_error;
16-
use std::{error, result};
17-
18-
quick_error! {
19-
/// An error originating from the TiKV client or dependencies.
20-
///
21-
/// This client currently uses [`quick_error`](https://docs.rs/quick-error/1.2.2/quick_error/)
22-
/// for errors. *This may change in future versions.*
23-
#[derive(Debug)]
24-
pub enum Error {
25-
/// Wraps a `std::io::Error`.
26-
Io(err: ::std::io::Error) {
27-
from()
28-
cause(err)
29-
description(err.description())
30-
}
31-
/// Wraps a `grpcio::Error`.
32-
Grpc(err: grpcio::Error) {
33-
from()
34-
cause(err)
35-
description(err.description())
36-
}
37-
/// Represents that a futures oneshot channel was cancelled.
38-
Canceled(err: ::futures::sync::oneshot::Canceled) {
39-
from()
40-
cause(err)
41-
description(err.description())
42-
}
43-
/// An unknown error.
44-
///
45-
/// Generally, this is not an expected error. Please report it if encountered.
46-
Other(err: Box<error::Error + Sync + Send>) {
47-
from()
48-
cause(err.as_ref())
49-
description(err.description())
50-
display("unknown error {:?}", err)
51-
}
52-
/// A region was not found for the given key.
53-
RegionForKeyNotFound(key: Vec<u8>) {
54-
description("region is not found")
55-
display("region is not found for key {:?}", key)
56-
}
57-
/// A region was not found.
58-
RegionNotFound(region_id: u64, message: Option<String>) {
59-
description("region is not found")
60-
display("region {:?} is not found. {}", region_id, message.as_ref().unwrap_or(&"".to_owned()))
61-
}
62-
/// The peer is not a leader of the given region.
63-
NotLeader(region_id: u64, message: Option<String>) {
64-
description("peer is not leader")
65-
display("peer is not leader for region {}. {}", region_id, message.as_ref().unwrap_or(&"".to_owned()))
66-
}
67-
/// The store does not match.
68-
StoreNotMatch(request_store_id: u64, actual_store_id: u64, message: String) {
69-
description("store not match")
70-
display("requesting store '{}' when actual store is '{}'. {}", request_store_id, actual_store_id, message)
71-
}
72-
/// The given key is not within the given region.
73-
KeyNotInRegion(key: Vec<u8>, region_id: u64, start_key: Vec<u8>, end_key: Vec<u8>) {
74-
description("region is not found")
75-
display("key {:?} is not in region {:?}: [{:?}, {:?})", key, region_id, start_key, end_key)
76-
}
77-
/// A stale epoch.
78-
StaleEpoch(message: Option<String>) {
79-
description("stale epoch")
80-
display("{}", message.as_ref().unwrap_or(&"".to_owned()))
81-
}
82-
StaleCommand(message: String) {
83-
description("stale command")
84-
display("{}", message)
85-
}
86-
/// The server is too busy.
87-
ServerIsBusy(reason: String, backoff: u64) {
88-
description("server is busy")
89-
display("server is busy: {:?}. Backoff {} ms", reason, backoff)
90-
}
91-
/// The given raft entry is too large for the region.
92-
RaftEntryTooLarge(region_id: u64, entry_size: u64, message: String) {
93-
description("raft entry too large")
94-
display("{:?} bytes raft entry of region {:?} is too large. {}", entry_size, region_id, message)
95-
}
96-
KeyError(message: String) {
97-
description("key error")
98-
display("{}", message)
99-
}
100-
KVError(message: String) {
101-
description("kv error")
102-
display("{}", message)
103-
}
104-
InternalError(message: String) {
105-
description("internal error")
106-
display("{}", message)
107-
}
108-
InvalidKeyRange {
109-
description("invalid key range")
110-
display("Only left closed intervals are supported")
111-
}
112-
Unimplemented {
113-
description("unimplemented feature")
114-
display("Unimplemented feature")
115-
}
116-
EmptyValue {
117-
description("can not set empty value")
118-
display("Can not set empty value")
119-
}
120-
NoSuchKey {
121-
description("key does not exist")
122-
display("Key doest not exist")
123-
}
124-
InvalidOverlappingRanges {
125-
description("ranges can not be overlapping")
126-
display("Ranges can not be overlapping")
127-
}
128-
MaxScanLimitExceeded(limit: u32, max_limit: u32) {
129-
description("limit exceeds max scan limit")
130-
display("Limit {} excceds max scan limit {}", limit, max_limit)
15+
use std::fmt::{self, Display};
16+
use std::result;
17+
18+
#[derive(Debug)]
19+
pub struct Error {
20+
inner: Context<ErrorKind>,
21+
}
22+
23+
/// An error originating from the TiKV client or dependencies.
24+
#[derive(Debug, Fail)]
25+
pub enum ErrorKind {
26+
/// Wraps a `std::io::Error`.
27+
#[fail(display = "IO error: {}", _0)]
28+
Io(#[fail(cause)] std::io::Error),
29+
/// Wraps a `grpcio::Error`.
30+
#[fail(display = "gRPC error: {}", _0)]
31+
Grpc(#[fail(cause)] grpcio::Error),
32+
/// Represents that a futures oneshot channel was cancelled.
33+
#[fail(display = "A futures oneshot channel was canceled. {}", _0)]
34+
Canceled(#[fail(cause)] futures::sync::oneshot::Canceled),
35+
/// Feature is not implemented.
36+
#[fail(display = "Unimplemented feature")]
37+
Unimplemented,
38+
// No region is found for the given key.
39+
#[fail(display = "Region is not found for key: {:?}", key)]
40+
RegionForKeyNotFound { key: Vec<u8> },
41+
/// The peer is not the leader for the region.
42+
#[fail(display = "Peer is not leader for region {}. {}", region_id, message)]
43+
NotLeader { region_id: u64, message: String },
44+
/// Stale epoch
45+
#[fail(display = "Stale epoch. {}", message)]
46+
StaleEpoch { message: String },
47+
/// No region is found for the given id.
48+
#[fail(display = "Region {} is not found. {}", region_id, message)]
49+
RegionNotFound { region_id: u64, message: String },
50+
/// Invalid key range to scan. Only left bounded intervals are supported.
51+
#[fail(display = "Only left bounded intervals are supported")]
52+
InvalidKeyRange,
53+
/// Cannot set an empty value
54+
#[fail(display = "Cannot set an empty value")]
55+
EmptyValue,
56+
/// Scan limit exceeds the maximum
57+
#[fail(display = "Limit {} exceeds max scan limit {}", limit, max_limit)]
58+
MaxScanLimitExceeded { limit: u32, max_limit: u32 },
59+
/// Wraps `kvproto::kvrpcpb::KeyError`
60+
#[fail(display = "{:?}", _0)]
61+
KeyError(kvproto::kvrpcpb::KeyError),
62+
/// A string error returned by TiKV server
63+
#[fail(display = "Kv error. {}", message)]
64+
KvError { message: String },
65+
/// Reconstructed `kvproto::errorpb::KeyNotInRegion`
66+
#[fail(
67+
display = "Key {:?} is not in region {}: [{:?}, {:?})",
68+
key, region_id, start_key, end_key
69+
)]
70+
KeyNotInRegion {
71+
key: Vec<u8>,
72+
region_id: u64,
73+
start_key: Vec<u8>,
74+
end_key: Vec<u8>,
75+
},
76+
/// Reconstructed `kvproto::errorpb::ServerIsBusy`
77+
#[fail(display = "Server is busy: {}. Backoff {} ms", reason, backoff_ms)]
78+
ServerIsBusy { reason: String, backoff_ms: u64 },
79+
/// Represents `kvproto::errorpb::StaleCommand` with additional error message
80+
#[fail(display = "Stale command. {}", message)]
81+
StaleCommand { message: String },
82+
/// Represents `kvproto::errorpb::StoreNotMatch` with additional error message
83+
#[fail(
84+
display = "Requesting store {} when actual store is {}. {}",
85+
request_store_id, actual_store_id, message
86+
)]
87+
StoreNotMatch {
88+
request_store_id: u64,
89+
actual_store_id: u64,
90+
message: String,
91+
},
92+
/// Represents `kvproto::errorpb::RaftEntryTooLarge` with additional error message
93+
#[fail(
94+
display = "{} bytes raft entry of region {} is too large. {}",
95+
entry_size, region_id, message
96+
)]
97+
RaftEntryTooLarge {
98+
region_id: u64,
99+
entry_size: u64,
100+
message: String,
101+
},
102+
#[fail(display = "{}", message)]
103+
InternalError { message: String },
104+
}
105+
106+
impl Fail for Error {
107+
fn cause(&self) -> Option<&Fail> {
108+
self.inner.cause()
109+
}
110+
111+
fn backtrace(&self) -> Option<&Backtrace> {
112+
self.inner.backtrace()
113+
}
114+
}
115+
116+
impl Display for Error {
117+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
118+
Display::fmt(&self.inner, f)
119+
}
120+
}
121+
122+
impl Error {
123+
pub fn kind(&self) -> &ErrorKind {
124+
self.inner.get_context()
125+
}
126+
127+
pub(crate) fn unimplemented() -> Self {
128+
Error::from(ErrorKind::Unimplemented)
129+
}
130+
131+
pub(crate) fn region_for_key_not_found(key: Vec<u8>) -> Self {
132+
Error::from(ErrorKind::RegionForKeyNotFound { key })
133+
}
134+
135+
pub(crate) fn not_leader(region_id: u64, message: Option<String>) -> Self {
136+
Error::from(ErrorKind::NotLeader {
137+
region_id,
138+
message: message.unwrap_or_default(),
139+
})
140+
}
141+
142+
pub(crate) fn stale_epoch(message: Option<String>) -> Self {
143+
Error::from(ErrorKind::StaleEpoch {
144+
message: message.unwrap_or_default(),
145+
})
146+
}
147+
148+
pub(crate) fn region_not_found(region_id: u64, message: Option<String>) -> Self {
149+
Error::from(ErrorKind::RegionNotFound {
150+
region_id,
151+
message: message.unwrap_or_default(),
152+
})
153+
}
154+
155+
pub(crate) fn invalid_key_range() -> Self {
156+
Error::from(ErrorKind::InvalidKeyRange)
157+
}
158+
159+
pub(crate) fn empty_value() -> Self {
160+
Error::from(ErrorKind::EmptyValue)
161+
}
162+
163+
pub(crate) fn max_scan_limit_exceeded(limit: u32, max_limit: u32) -> Self {
164+
Error::from(ErrorKind::MaxScanLimitExceeded { limit, max_limit })
165+
}
166+
167+
pub(crate) fn kv_error(message: String) -> Self {
168+
Error::from(ErrorKind::KvError { message })
169+
}
170+
171+
pub(crate) fn key_not_in_region(mut e: kvproto::errorpb::KeyNotInRegion) -> Self {
172+
Error::from(ErrorKind::KeyNotInRegion {
173+
key: e.take_key(),
174+
region_id: e.get_region_id(),
175+
start_key: e.take_start_key(),
176+
end_key: e.take_end_key(),
177+
})
178+
}
179+
180+
pub(crate) fn server_is_busy(mut e: kvproto::errorpb::ServerIsBusy) -> Self {
181+
Error::from(ErrorKind::ServerIsBusy {
182+
reason: e.take_reason(),
183+
backoff_ms: e.get_backoff_ms(),
184+
})
185+
}
186+
187+
pub(crate) fn stale_command(message: String) -> Self {
188+
Error::from(ErrorKind::StaleCommand { message })
189+
}
190+
191+
pub(crate) fn store_not_match(e: kvproto::errorpb::StoreNotMatch, message: String) -> Self {
192+
Error::from(ErrorKind::StoreNotMatch {
193+
request_store_id: e.get_request_store_id(),
194+
actual_store_id: e.get_actual_store_id(),
195+
message,
196+
})
197+
}
198+
199+
pub(crate) fn raft_entry_too_large(
200+
e: kvproto::errorpb::RaftEntryTooLarge,
201+
message: String,
202+
) -> Self {
203+
Error::from(ErrorKind::RaftEntryTooLarge {
204+
region_id: e.get_region_id(),
205+
entry_size: e.get_entry_size(),
206+
message,
207+
})
208+
}
209+
210+
pub(crate) fn internal_error(message: String) -> Self {
211+
Error::from(ErrorKind::InternalError { message })
212+
}
213+
}
214+
215+
impl From<ErrorKind> for Error {
216+
fn from(kind: ErrorKind) -> Error {
217+
Error {
218+
inner: Context::new(kind),
131219
}
132220
}
133221
}
134222

223+
impl From<Context<ErrorKind>> for Error {
224+
fn from(inner: Context<ErrorKind>) -> Error {
225+
Error { inner }
226+
}
227+
}
228+
229+
impl From<std::io::Error> for Error {
230+
fn from(err: std::io::Error) -> Self {
231+
Error::from(ErrorKind::Io(err))
232+
}
233+
}
234+
235+
impl From<grpcio::Error> for Error {
236+
fn from(err: grpcio::Error) -> Self {
237+
Error::from(ErrorKind::Grpc(err))
238+
}
239+
}
240+
241+
impl From<futures::sync::oneshot::Canceled> for Error {
242+
fn from(err: futures::sync::oneshot::Canceled) -> Self {
243+
Error::from(ErrorKind::Canceled(err))
244+
}
245+
}
246+
247+
impl From<kvproto::kvrpcpb::KeyError> for Error {
248+
fn from(err: kvproto::kvrpcpb::KeyError) -> Self {
249+
Error::from(ErrorKind::KeyError(err))
250+
}
251+
}
252+
135253
/// A result holding an [`Error`](enum.Error.html).
136254
pub type Result<T> = result::Result<T, Error>;

0 commit comments

Comments
 (0)