|
2 | 2 |
|
3 | 3 | [](https://travis-ci.org/tikv/client-rust)
|
4 | 4 |
|
5 |
| -> Currently this crate is experimental and some portions (e.g. the Transactional API) are still in active development. You're encouraged to use this library for testing and to help us find problems! |
6 |
| -
|
7 | 5 | [Docs](https://www.tikv.dev/doc/rust-client/tikv_client/)
|
8 | 6 |
|
9 |
| -This crate provides a clean, ready to use client for [TiKV](https://github.com/tikv/tikv), a |
10 |
| -distributed transactional Key-Value database written in Rust. |
| 7 | +This crate provides an easy-to-use client for [TiKV](https://github.com/tikv/tikv), a distributed, transactional key-value database written in Rust. |
11 | 8 |
|
12 |
| -With this crate you can easily connect to any TiKV deployment, interact with it, and mutate the data it contains. It uses async/await internally and exposes some `async fn` APIs as well. |
| 9 | +This crate lets you connect to a TiKV cluster and use either a transactional or raw (simple get/put style without transactional consistency guarantees) API to access and update your data. |
13 | 10 |
|
14 |
| -This is an open source (Apache 2) project hosted by the Cloud Native Computing Foundation (CNCF) and maintained by the TiKV Authors. *We'd love it if you joined us in improving this project.* |
| 11 | +This is an open source (Apache 2) project maintained by the TiKV Authors. We welcome community contributions, see below for more info. |
15 | 12 |
|
16 | 13 | ## Getting started
|
17 | 14 |
|
18 |
| -The TiKV client is a Rust library (crate). To use this crate in your project, add following dependencies in your `Cargo.toml`: |
| 15 | +The TiKV client is a Rust library (crate). To use this crate in your project, add the following dependency to your `Cargo.toml`: |
19 | 16 |
|
20 | 17 | ```toml
|
21 | 18 | [dependencies]
|
22 |
| -tikv-client = { git = "https://github.com/tikv/client-rust.git" } |
| 19 | +tikv-client = 0.1 |
23 | 20 | ```
|
24 | 21 |
|
25 |
| -The client requires a Git dependency until we can [publish it](https://github.com/tikv/client-rust/issues/32). |
| 22 | +Note, that you will need `tikv-client = { git = "https://github.com/tikv/client-rust.git" }` until we publish the crate (should be any day now). |
26 | 23 |
|
27 |
| -The client provides two modes to interact with TiKV: raw and transactional. |
28 |
| -In the current version (0.0.0), the transactional API supports optimistic transactions. Pessimistic transactions are implemented but not well tested. |
| 24 | +The minimum supported version of Rust is 1.40. |
29 | 25 |
|
30 |
| -Important note: It is **not recommended or supported** to use both the raw and transactional APIs on the same database. |
| 26 | +The general flow of using the client crate is to create either a raw or transaction client object (which can be configured) then send commands using the client object, or use it to create transactions objects. In the latter case, the transaction is built up using various commands and then committed (or rolled back). |
31 | 27 |
|
32 |
| -### Code examples |
| 28 | +### Examples |
33 | 29 |
|
34 | 30 | Raw mode:
|
35 | 31 |
|
36 | 32 | ```rust
|
37 |
| -let config = Config::new(vec!["127.0.0.1:2379"]); |
38 |
| -let client = RawClient::new(config).await?; |
39 |
| -client.put("key".to_owned(), "value".to_owned()).await; |
40 |
| -let value = client.get("key".to_owned()).await; |
| 33 | +use tikv_client::RawClient; |
| 34 | + |
| 35 | +let client = RawClient::new(vec!["127.0.0.1:2379"]).await?; |
| 36 | +client.put("key".to_owned(), "value".to_owned()).await?; |
| 37 | +let value = client.get("key".to_owned()).await?; |
41 | 38 | ```
|
42 | 39 |
|
43 | 40 | Transactional mode:
|
44 | 41 |
|
45 | 42 | ```rust
|
46 |
| -let config = Config::new(vec!["127.0.0.1:2379"]); |
47 |
| -let txn_client = TransactionClient::new(config).await?; |
48 |
| -let mut txn = txn_client.begin().await?; |
| 43 | +use tikv_client::TransactionClient; |
| 44 | + |
| 45 | +let txn_client = TransactionClient::new(vec!["127.0.0.1:2379"]).await?; |
| 46 | +let mut txn = txn_client.begin_optimistic().await?; |
49 | 47 | txn.put("key".to_owned(), "value".to_owned()).await?;
|
50 |
| -let value = txn.get("key".to_owned()).await; |
| 48 | +let value = txn.get("key".to_owned()).await?; |
51 | 49 | txn.commit().await?;
|
52 | 50 | ```
|
53 | 51 |
|
54 |
| -There are some [examples](examples) which show how to use the client in a Rust program. |
| 52 | +## API summary |
55 | 53 |
|
56 |
| -### API |
| 54 | +The TiKV Rust client supports several levels of abstraction. The most convenient way to use the client is via `RawClient` and `TransactionClient`. This gives a very high-level API which mostly abstracts over the distributed nature of the store and has sensible defaults for all protocols. This interface can be configured, primarily when creating the client or transaction objects via the `Config` and `TransactionOptions` structs. Using some options, you can take over parts of the protocols (such as retrying failed messages) yourself. |
57 | 55 |
|
58 |
| -#### Raw requests |
| 56 | +The lowest level of abstraction is to create and send gRPC messages directly to TiKV (and PD) nodes. The `tikv-client-store` and `tikv-client-pd` crates make this easier than using the protobuf definitions and a gRPC library directly, but give you the same level of control. |
59 | 57 |
|
60 |
| -| Request | Main parameter type | Successful result type | Noteworthy Behavior | |
61 |
| -| -------------- | ------------------- | ---------------------- | --------------------------------------------- | |
62 |
| -| `put` | `KvPair` | `()` | | |
63 |
| -| `get` | `Key` | `Option<Value>` | | |
64 |
| -| `delete` | `Key` | `()` | | |
65 |
| -| `scan` | `BoundRange` | `Vec<KvPair>` | | |
66 |
| -| `batch_put` | `Iter<KvPair>` | `()` | | |
67 |
| -| `batch_get` | `Iter<Key>` | `Vec<KvPair>` | Skip non-existent keys; Does not retain order | |
68 |
| -| `batch_delete` | `Iter<Key>` | `()` | | |
69 |
| -| `delete_range` | `BoundRange` | `()` | | |
| 58 | +In between these levels of abstraction, you can send and receive individual messages to the TiKV cluster, but take advantage of library code for common operations such as resolving data to regions and thus nodes in the cluster, or retrying failed messages. This can be useful for testing a TiKV cluster or for some advanced use cases. See the `client_rust::request` module for this API, and `client_rust::raw::lowering` and `client_rust::transaction::lowering` for convenience methods for creating request objects. |
70 | 59 |
|
71 |
| -#### Transactional requests |
| 60 | +The rest of this document describes only the `RawClient`/`TransactionClient` APIs. |
72 | 61 |
|
73 |
| -| Request | Main parameter type | Successful result type | Noteworthy Behavior | |
74 |
| -| ----------- | ------------------- | ---------------------- | ------------------------------------------------------------------ | |
75 |
| -| `put` | `KvPair` | `()` | | |
76 |
| -| `get` | `Key` | `Option<value>` | | |
77 |
| -| `key_exists` | `Key` | `bool` | | |
78 |
| -| `delete` | `Key` | `()` | | |
79 |
| -| `scan` | `BoundRange` | `Iter<KvPair>` | | |
80 |
| -| `scan_keys` | `BoundRange` | `Iter<Key>` | | |
81 |
| -| `batch_get` | `Iter<Key>` | `Iter<KvPair>` | Skip non-existent keys; Does not retain order | |
82 |
| -| `lock_keys` | `Iter<Key>` | `()` | | |
83 |
| -| `gc` | `Timestamp` | `bool` | It returns whether the latest safepoint in PD equals the parameter | |
| 62 | +Important note: It is **not recommended or supported** to use both the raw and transactional APIs on the same database. |
84 | 63 |
|
85 |
| -For detailed behavior of each request, please refer to the [doc](#Access-the-documentation). |
| 64 | +### Types |
86 | 65 |
|
87 |
| -#### Experimental raw requests |
| 66 | +`Key`: a key in the store. `String` and `Vec<u8>` implement `Into<Key>`, so you can pass them directly into client functions. |
88 | 67 |
|
89 |
| -You must be careful if you want to use the following request(s). Read the description for reasons. |
| 68 | +`Value`: a value in the store; just an alias of `Vec<u8>`. |
90 | 69 |
|
91 |
| -| Request | Main parameter type | Successful result type | |
92 |
| -| ------------ | ------------------- | ---------------------- | |
93 |
| -| `batch_scan` | `Iter<BoundRange>` | `Vec<KvPair>` | |
| 70 | +`KvPair`: a pair of a `Key` and a `Value`. It provides convenience methods for conversion to and from other types. |
94 | 71 |
|
95 |
| -The `each_limit` parameter does not work as expected. It does not limit the number of results returned of each range, instead it limits the number of results in each region of each range. As a result, you may get **more than** `each_limit` key-value pairs for each range. But you should not miss any entries. |
| 72 | +`BoundRange`: used for range related requests like `scan`. It implements `From` for Rust ranges so you can pass a Rust range of keys to the request, e.g., `client.delete_range(vec![]..)`. |
96 | 73 |
|
97 |
| -The results of `batch_scan` are flattened. The order of ranges is retained. |
| 74 | +### Raw requests |
98 | 75 |
|
99 |
| -### Useful types |
| 76 | +| Request | Main parameter type | Result type | Noteworthy Behavior | |
| 77 | +| -------------- | ------------------- | ---------------- | ---------------------------------------------- | |
| 78 | +| `put` | `KvPair` | | | |
| 79 | +| `get` | `Key` | `Option<Value>` | | |
| 80 | +| `delete` | `Key` | | | |
| 81 | +| `delete_range` | `BoundRange` | | | |
| 82 | +| `scan` | `BoundRange` | `Vec<KvPair>` | | |
| 83 | +| `batch_put` | `Iter<KvPair>` | | | |
| 84 | +| `batch_get` | `Iter<Key>` | `Vec<KvPair>` | Skips non-existent keys; does not retain order | |
| 85 | +| `batch_delete` | `Iter<Key>` | | | |
| 86 | +| `batch_scan` | `Iter<BoundRange>` | `Vec<KvPair>` | See docs for `each_limit` parameter behavior. The order of ranges is retained. | |
100 | 87 |
|
101 |
| -To use the client, there are 4 types you will need. |
| 88 | +### Transactional requests |
102 | 89 |
|
103 |
| -`Key` is simply a vector of bytes(`Vec<u8>`). `String` and `Vec<u8>` implements `Into<Key>`, so you can directly pass them to clients. |
| 90 | +| Request | Main parameter type | Result type | Noteworthy Behavior | |
| 91 | +| -------------| ------------------- | --------------- | ------------------------------------------------------------------ | |
| 92 | +| `put` | `KvPair` | | | |
| 93 | +| `get` | `Key` | `Option<value>` | | |
| 94 | +| `key_exists` | `Key` | `bool` | | |
| 95 | +| `delete` | `Key` | | | |
| 96 | +| `scan` | `BoundRange` | `Iter<KvPair>` | | |
| 97 | +| `scan_keys` | `BoundRange` | `Iter<Key>` | | |
| 98 | +| `batch_get` | `Iter<Key>` | `Iter<KvPair>` | Skips non-existent keys; does not retain order | |
| 99 | +| `lock_keys` | `Iter<Key>` | | | |
| 100 | +| `gc` | `Timestamp` | `bool` | Returns true if the latest safepoint in PD equals the parameter | |
104 | 101 |
|
105 |
| -`Value` is just an alias of `Vec<u8>`. |
106 | 102 |
|
107 |
| -`KvPair` is a tuple consisting of a `Key` and a `Value`. It also provides some convenience methods for conversion to and from other types. |
| 103 | +# Development and contributing |
108 | 104 |
|
109 |
| -`BoundRange` is used for range related requests like `scan`. It implements `From` for usual ranges so you can just create a range and pass them to the request.For instance, `client.scan("k2".to_owned()..="k5".to_owned(), 5)` or `client.delete_range(vec![]..)`. |
| 105 | +We welcome your contributions! Contributing code is great, we also appreciate filing [issues](https://github.com/tikv/client-rust/issues/new) to identify bugs and provide feedback, adding tests or examples, and improvements to documentation. |
110 | 106 |
|
111 |
| -## Access the documentation |
| 107 | +## Building and testing |
112 | 108 |
|
113 |
| -We've done our best to include ample, tested, and understandable examples. |
| 109 | +We use the standard Cargo workflows, e.g., `cargo build` to build and `cargo test` to run unit tests. You will need to use a nightly Rust toolchain to build and run tests. |
114 | 110 |
|
115 |
| -We recommend using the officially maintained documentation [here](https://www.tikv.dev/doc/rust-client/tikv_client/). |
| 111 | +Running integration tests or manually testing the client with a TiKV cluster is a little bit more involved. The easiest way is to use [TiUp](https://github.com/pingcap/tiup) to initialise a cluster on your local machine: |
116 | 112 |
|
117 |
| -You can also access the documentation on your machine by running the following in any project that depends on `tikv-client`. |
| 113 | +``` |
| 114 | +tiup playground nightly --db 0 --tiflash 0 --monitor false |
| 115 | +``` |
118 | 116 |
|
119 |
| -```bash |
120 |
| -cargo doc --package tikv-client --open |
121 |
| -# If it didn't work, browse file URL it tried to open with your browser. |
| 117 | +Then if you want to run integration tests: |
| 118 | + |
| 119 | +``` |
| 120 | +PD_ADDRS="127.0.0.1:2379" cargo test --package tikv-client --test integration_tests --features integration-tests |
122 | 121 | ```
|
123 | 122 |
|
124 |
| -## Minimal Rust version |
| 123 | +## Creating a PR |
| 124 | + |
| 125 | +We use a standard GitHub PR workflow. We run CI on every PR and require all PRs to build without warnings (including clippy and Rustfmt warnings), pass tests, have a DCO sign-off (use `-s` when you commit, the DCO bot will guide you through completing the DCO agreement for your first PR), and have at least one review. If any of this is difficult for you, don't worry about it and ask on the PR. |
| 126 | + |
| 127 | +To run CI-like tests locally, we recommend you run `cargo clippy`, `cargo test`, and `cargo fmt` before submitting your PR. See above for running integration tests, but you probably won't need to worry about this for your first few PRs. |
| 128 | + |
| 129 | +Please follow PingCAP's [Rust style guide](https://pingcap.github.io/style-guide/rust/). All code PRs should include new tests or test cases. |
| 130 | + |
| 131 | +## Getting help |
125 | 132 |
|
126 |
| -This crate supports Rust 1.40 and above. |
| 133 | +If you need help, either to find something to work on, or with any technical problem, the easiest way to get it is via Slack. We monitor the client-rust (better for general client questions) and sig-transaction (better for technical questions about TiKV's transaction protocol) channels on the [tikv-wg slack](https://tikv.org/chat). |
127 | 134 |
|
128 |
| -For development, a nightly Rust compiler is needed to compile the tests. |
| 135 | +You can also get help on GitHub issues or PRs directly. You can just ask a question; if you don't get a response, you should ping @nrc or @ekexium. |
0 commit comments