Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ license = "Apache-2.0"
authors = ["The TiKV Project Authors"]
repository = "https://github.com/tikv/client-rust"
description = "The rust language implementation of TiKV client."
edition = "2018"

[lib]
name = "tikv_client"
Expand Down
71 changes: 45 additions & 26 deletions examples/raw.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,42 +11,58 @@
// See the License for the specific language governing permissions and
// limitations under the License.

extern crate futures;
extern crate tikv_client;

use futures::future::Future;
use std::path::PathBuf;
use tikv_client::{Result, Config, raw::Client, Key, Value};

use futures::future::Future;
use tikv_client::*;
const KEY: &str = "TiKV";
const VALUE: &str = "Rust";
const CUSTOM_CF: &str = "custom_cf";

fn main() {
let config = Config::new(vec!["127.0.0.1:3379"]).with_security(
fn main() -> Result<()> {
// Create a configuration to use for the example.
// Optionally encrypt the traffic.
let config = Config::new(vec![
"192.168.0.101:3379", // Avoid a single point of failure,
"192.168.0.100:3379", // use at least two PD endpoints.
]).with_security(
PathBuf::from("/path/to/ca.pem"),
PathBuf::from("/path/to/client.pem"),
PathBuf::from("/path/to/client-key.pem"),
);
let raw = raw::Client::new(&config)
.wait()
.expect("Could not connect to tikv");

let key: Key = b"Company".to_vec().into();
let value: Value = b"PingCAP".to_vec().into();
// When we first create a client we recieve a `Connect` structure which must be resolved before
// the client is actually connected and usable.
let unconnnected_client = Client::new(&config);
let client = unconnnected_client.wait()?;

raw.put(key.clone(), value.clone())
.cf("test_cf")
.wait()
.expect("Could not put kv pair to tikv");
println!("Successfully put {:?}:{:?} to tikv", key, value);
// Requests are created from the connected client. These calls return structures which
// implement `Future`. This means the `Future` must be resolved before the action ever takes
// place.
//
// Here we set the key `TiKV` to have the value `Rust` associated with it.
let put_request = client.put(KEY, VALUE);
let put_result: () = put_request.wait()?; // Returns a `tikv_client::Error` on failure.
println!("Put key \"{}\", value \"{}\".", KEY, VALUE);

let value = raw
.get(&key)
.cf("test_cf")
.wait()
.expect("Could not get value");
println!("Found val: {:?} for key: {:?}", value, key);
//
// Unlike a standard Rust HashMap all calls take owned values. This is because under the hood
// protobufs must take ownership of the data. If we only took a borrow we'd need to internally // clone it. This is against Rust API guidelines, so you must manage this yourself.
//
// Above, you saw we can use a `&'static str`, this is primarily for making examples short.
// This type is practical to use for real things, and usage forces an internal copy.
//
// It is best to pass a `Vec<u8>` in terms of explictness and speed. `String`s and a few other
// types are supported as well, but it all ends up as `Vec<u8>` in the end.
let key: String = String::from(KEY);
let value: Value = client.get(key).wait()?;
assert_eq!(value.as_ref(), VALUE);
println!("Get key \"{:?}\" returned value \"{:?}\".", value, KEY);

raw.delete(&key)
.cf("test_cf")
// You can also set the `ColumnFamily` used by the request.
// This is *advanced usage* and should have some special considerations.
let req = raw.delete(&key)
.cf(CUSTOM_CF)
.wait()
.expect("Could not delete value");
println!("Key: {:?} deleted", key);
Expand Down Expand Up @@ -74,9 +90,12 @@ fn main() {
.expect("Could not scan");

let ranges = [&start..&end, &start..&end];
raw.batch_scan(&ranges, 10)
raw.batch_scan(ranges, 10)
.cf("test_cf")
.key_only()
.wait()
.expect("Could not batch scan");

// Cleanly exit.
Ok(())
}
24 changes: 13 additions & 11 deletions examples/transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,13 @@
// See the License for the specific language governing permissions and
// limitations under the License.

extern crate futures;
extern crate tikv_client;

use futures::{future, Future, Stream};
use std::ops::RangeBounds;
use std::path::PathBuf;

use futures::{future, Future, Stream};
use tikv_client::transaction::{Client, IsolationLevel};
use tikv_client::*;
use tikv_client::{
transaction::{Client, IsolationLevel},
Config, Key, KvPair, Value,
};

fn puts(client: &Client, pairs: impl IntoIterator<Item = impl Into<KvPair>>) {
let mut txn = client.begin();
Expand All @@ -28,7 +26,8 @@ fn puts(client: &Client, pairs: impl IntoIterator<Item = impl Into<KvPair>>) {
.into_iter()
.map(Into::into)
.map(|p| txn.set(p.key().clone(), p.value().clone())),
).wait()
)
.wait()
.expect("Could not set key value pairs");
txn.commit().wait().expect("Could not commit transaction");
}
Expand All @@ -49,10 +48,12 @@ fn scan(client: &Client, range: impl RangeBounds<Key>, mut limit: usize) {
limit -= 1;
true
})
}).for_each(|pair| {
})
.for_each(|pair| {
println!("{:?}", pair);
Ok(())
}).wait()
})
.wait()
.expect("Could not scan keys");
}

Expand All @@ -63,7 +64,8 @@ fn dels(client: &Client, keys: impl IntoIterator<Item = Key>) {
.into_iter()
.map(|p| {
txn.delete(p).wait().expect("Could not delete key");
}).collect();
})
.collect();
txn.commit().wait().expect("Could not commit transaction");
}

Expand Down
4 changes: 4 additions & 0 deletions rust-toolchain
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
nightly

# We explicitly use nightly for the moment even though we target stable so we
# can develop for the 2018 edition.
26 changes: 23 additions & 3 deletions src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,66 +11,86 @@
// See the License for the specific language governing permissions and
// limitations under the License.

use std::error;
use std::result;
use grpcio;
use quick_error::quick_error;
use std::{error, result};

quick_error!{
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO, I want to try Failure instead of quick_error :-)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let me take a look into failure.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also do! :)

/// An error originating from the TiKV client or dependencies.
///
/// This client currently uses [`quick_error`](https://docs.rs/quick-error/1.2.2/quick_error/)
/// for errors. *This may change in future versions.*
#[derive(Debug)]
pub enum Error {
/// Wraps a a `std::io::Error`.
Io(err: ::std::io::Error) {
from()
cause(err)
description(err.description())
}
Grpc(err: ::grpc::Error) {
/// Wraps a `grpcio::Error`.
Grpc(err: grpcio::Error) {
from()
cause(err)
description(err.description())
}
/// Represents that a futures oneshot channel was cancelled.
Canceled(err: ::futures::sync::oneshot::Canceled) {
from()
cause(err)
description(err.description())
}
/// An unknown error.
///
/// Generally, this is not an expected error. Please report it if encountered.
Other(err: Box<error::Error + Sync + Send>) {
from()
cause(err.as_ref())
description(err.description())
display("unknown error {:?}", err)
}
/// A region was not found for the given key.
RegionForKeyNotFound(key: Vec<u8>) {
description("region is not found")
display("region is not found for key {:?}", key)
}
/// A region was not found.
RegionNotFound(id: u64) {
description("region is not found")
display("region {:?} is not found", id)
}
/// The peer is not a leader of the given region.
NotLeader(region_id: u64) {
description("peer is not leader")
display("peer is not leader for region {:?}.", region_id)
}
/// The store does not match.
StoreNotMatch {
description("store not match")
display("store not match")
}
/// The given key is not eithin the given region.
KeyNotInRegion(key: Vec<u8>, region_id: u64, start_key: Vec<u8>, end_key: Vec<u8>) {
description("region is not found")
display("key {:?} is not in region {:?}: [{:?}, {:?})", key, region_id, start_key, end_key)
}
/// A stale epoch.
StaleEpoch {
description("stale epoch")
display("stale epoch")
}
/// The server is too busy.
ServerIsBusy(reason: String) {
description("server is busy")
display("server is busy: {:?}", reason)
}
/// The given raft entry is too large for the region.
RaftEntryTooLarge(region_id: u64, entry_size: u64) {
description("raft entry too large")
display("{:?} bytes raft entry of region {:?} is too large", entry_size, region_id)
}
}
}

/// A result holding an [`Error`](enum.Error.html).
pub type Result<T> = result::Result<T, Error>;
Loading