Merge pull request #202 from andylokandy/master

Allow unbounded start key
This commit is contained in:
Nick Cameron 2020-11-26 15:59:20 +13:00 committed by GitHub
commit 70dd5580f1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 85 additions and 32 deletions

View File

@ -1,17 +1,19 @@
// Copyright 2019 TiKV Project Authors. Licensed under Apache-2.0.
use super::Key;
use crate::{Error, Result};
#[cfg(test)]
use proptest_derive::Arbitrary;
use std::{
borrow::Borrow,
cmp::{Eq, PartialEq},
convert::TryFrom,
ops::{Bound, Range, RangeBounds, RangeFrom, RangeInclusive},
ops::{
Bound, Range, RangeBounds, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive,
},
};
#[cfg(test)]
use proptest_derive::Arbitrary;
use tikv_client_proto::kvrpcpb;
use super::Key;
/// A struct for expressing ranges. This type is semi-opaque and is not really meant for users to
/// deal with directly. Most functions which operate on ranges will accept any types which
/// implement `Into<BoundRange>`.
@ -23,7 +25,7 @@ use tikv_client_proto::kvrpcpb;
/// The unbounded lower bound in a [`Range`](Range) will be converted to an empty key.
///
/// **Maximum key**: There is no limit of the maximum key. When an empty key is used as the upper bound, it means upper unbounded.
/// The unbounded upper bound in a [`Range`](Range). The range covering all keys is just `vec![]..`.
/// The unbounded upper bound in a [`Range`](Range). The range covering all keys is just `Key::EMPTY..`.
///
/// **But, you should not need to worry about all this:** Most functions which operate
/// on ranges will accept any types which implement `Into<BoundRange>`.
@ -70,8 +72,6 @@ impl BoundRange {
///
/// The caller must ensure that `from` is not `Unbounded`.
fn new(from: Bound<Key>, to: Bound<Key>) -> BoundRange {
// Debug assert because this function is private.
debug_assert!(from != Bound::Unbounded);
BoundRange { from, to }
}
@ -96,12 +96,30 @@ impl BoundRange {
/// BoundRange::from(range.to_owned()).into_keys(),
/// (Key::from("a".to_owned()), Some(Key::from("z\0".to_owned()))),
/// );
/// // Open
/// // Open right
/// let range = "a".to_owned()..;
/// assert_eq!(
/// BoundRange::from(range).into_keys(),
/// BoundRange::from(range.to_owned()).into_keys(),
/// (Key::from("a".to_owned()), None),
/// );
/// // Left open right exclusive
/// let range = .."z";
/// assert_eq!(
/// BoundRange::from(range.to_owned()).into_keys(),
/// (Key::from("".to_owned()), Some(Key::from("z".to_owned()))),
/// );
/// // Left open right inclusive
/// let range = ..="z";
/// assert_eq!(
/// BoundRange::from(range.to_owned()).into_keys(),
/// (Key::from("".to_owned()), Some(Key::from("z\0".to_owned()))),
/// );
/// // Full range
/// let range = ..;
/// assert_eq!(
/// BoundRange::from(range.to_owned()).into_keys(),
/// (Key::from("".to_owned()), None),
/// );
// ```
pub fn into_keys(self) -> (Key, Option<Key>) {
let start = match self.from {
@ -110,7 +128,7 @@ impl BoundRange {
v.push_zero();
v
}
Bound::Unbounded => unreachable!(),
Bound::Unbounded => Key::EMPTY,
};
let end = match self.to {
Bound::Included(mut v) => {
@ -177,6 +195,12 @@ impl<T: Into<Key>> From<RangeFrom<T>> for BoundRange {
}
}
impl<T: Into<Key>> From<RangeTo<T>> for BoundRange {
fn from(other: RangeTo<T>) -> BoundRange {
BoundRange::new(Bound::Unbounded, Bound::Excluded(other.end.into()))
}
}
impl<T: Into<Key>> From<RangeInclusive<T>> for BoundRange {
fn from(other: RangeInclusive<T>) -> BoundRange {
let (start, end) = other.into_inner();
@ -184,6 +208,18 @@ impl<T: Into<Key>> From<RangeInclusive<T>> for BoundRange {
}
}
impl<T: Into<Key>> From<RangeToInclusive<T>> for BoundRange {
fn from(other: RangeToInclusive<T>) -> BoundRange {
BoundRange::new(Bound::Unbounded, Bound::Included(other.end.into()))
}
}
impl From<RangeFull> for BoundRange {
fn from(_other: RangeFull) -> BoundRange {
BoundRange::new(Bound::Unbounded, Bound::Unbounded)
}
}
impl<T: Into<Key>> From<(T, Option<T>)> for BoundRange {
fn from(other: (T, Option<T>)) -> BoundRange {
let to = match other.1 {
@ -204,18 +240,12 @@ impl<T: Into<Key>> From<(T, T)> for BoundRange {
}
}
impl<T: Into<Key> + Eq> TryFrom<(Bound<T>, Bound<T>)> for BoundRange {
type Error = Error;
fn try_from(bounds: (Bound<T>, Bound<T>)) -> Result<BoundRange> {
if bounds.0 == Bound::Unbounded {
Err(Error::invalid_key_range())
} else {
Ok(BoundRange::new(
convert_to_bound_key(bounds.0),
convert_to_bound_key(bounds.1),
))
}
impl<T: Into<Key> + Eq> From<(Bound<T>, Bound<T>)> for BoundRange {
fn from(bounds: (Bound<T>, Bound<T>)) -> BoundRange {
BoundRange::new(
convert_to_bound_key(bounds.0),
convert_to_bound_key(bounds.1),
)
}
}
@ -242,7 +272,7 @@ impl From<kvrpcpb::KeyRange> for BoundRange {
/// # Examples
/// ```rust
/// # use tikv_client::{ToOwnedRange, BoundRange};
/// # use std::ops::{Range, RangeFrom, RangeInclusive};
/// # use std::ops::*;
/// let r1: Range<&str> = "s".."e";
/// let r1: BoundRange = r1.to_owned();
///
@ -252,6 +282,9 @@ impl From<kvrpcpb::KeyRange> for BoundRange {
/// let r3: RangeInclusive<&str> = "s"..="e";
/// let r3: BoundRange = r3.to_owned();
///
/// let r4: RangeTo<&str> = .."z";
/// let r4: BoundRange = r4.to_owned();
///
/// let k1: Vec<u8> = "start".to_owned().into_bytes();
/// let k2: Vec<u8> = "end".to_owned().into_bytes();
/// let r4: BoundRange = (&k1, &k2).to_owned();
@ -283,6 +316,14 @@ impl<T: Into<Key> + Borrow<U>, U: ToOwned<Owned = T> + ?Sized> ToOwnedRange for
}
}
impl<T: Into<Key> + Borrow<U>, U: ToOwned<Owned = T> + ?Sized> ToOwnedRange for RangeTo<&U> {
fn to_owned(self) -> BoundRange {
From::from(RangeTo {
end: self.end.to_owned(),
})
}
}
impl<T: Into<Key> + Borrow<U>, U: ToOwned<Owned = T> + ?Sized> ToOwnedRange for RangeInclusive<&U> {
fn to_owned(self) -> BoundRange {
let (from, to) = self.into_inner();
@ -290,6 +331,22 @@ impl<T: Into<Key> + Borrow<U>, U: ToOwned<Owned = T> + ?Sized> ToOwnedRange for
}
}
impl<T: Into<Key> + Borrow<U>, U: ToOwned<Owned = T> + ?Sized> ToOwnedRange
for RangeToInclusive<&U>
{
fn to_owned(self) -> BoundRange {
From::from(RangeToInclusive {
end: self.end.to_owned(),
})
}
}
impl ToOwnedRange for RangeFull {
fn to_owned(self) -> BoundRange {
From::from(self)
}
}
impl<T: Into<Key> + Borrow<U>, U: ToOwned<Owned = T> + ?Sized> ToOwnedRange for (&U, Option<&U>) {
fn to_owned(self) -> BoundRange {
From::from((self.0.to_owned(), self.1.map(|u| u.to_owned())))

View File

@ -73,6 +73,9 @@ impl AsRef<Key> for kvrpcpb::Mutation {
}
impl Key {
/// The empty key.
pub const EMPTY: Self = Key(Vec::new());
/// Return whether the key is empty.
#[inline]
pub fn is_empty(&self) -> bool {

View File

@ -26,9 +26,6 @@ pub enum ErrorKind {
/// Will raise this error when using a pessimistic txn only operation on an optimistic txn
#[fail(display = "Invalid operation for this type of transaction")]
InvalidTransactionType,
/// Invalid key range to scan. Only left bounded intervals are supported.
#[fail(display = "Only left bounded intervals are supported")]
InvalidKeyRange,
/// It's not allowed to perform operations in a transaction after it has been committed or rolled back.
#[fail(
display = "Cannot read or write data after any attempt to commit or roll back the transaction"
@ -119,10 +116,6 @@ impl Error {
Error::from(ErrorKind::LeaderNotFound { region_id })
}
pub fn invalid_key_range() -> Self {
Error::from(ErrorKind::InvalidKeyRange)
}
pub fn max_scan_limit_exceeded(limit: u32, max_limit: u32) -> Self {
Error::from(ErrorKind::MaxScanLimitExceeded { limit, max_limit })
}