Struct tikv_client::Transaction[][src]

pub struct Transaction<PdC: PdClient = PdRpcClient> {
    status: Arc<RwLock<TransactionStatus>>,
    timestamp: Timestamp,
    buffer: Buffer,
    rpc: Arc<PdC>,
    options: TransactionOptions,
    is_heartbeat_started: bool,
}

An undo-able set of actions on the dataset.

Using a transaction you can prepare a set of actions (such as get, or put) on data at a particular timestamp called start_ts obtained from the placement driver. Once a transaction is commited, a new timestamp called commit_ts is obtained from the placement driver.

The snapshot isolation in TiKV ensures that a transaction behaves as if it operates on the snapshot taken at start_ts and its mutations take effect at commit_ts. In other words, the transaction can read mutations with commit_ts <= its start_ts, and its mutations are readable for transactions with start_ts >= its commit_ts.

Mutations, or write operations made in a transaction are buffered locally and sent at the time of commit, except for pessimisitc locking. In pessimistic mode, all write operations or xxx_for_update operations will first acquire pessimistic locks in TiKV. A lock exists until the transaction is committed (in the first phase of 2PC) or rolled back, or it exceeds its Time To Live (TTL).

For details, the SIG-Transaction provides materials explaining designs and implementations of multiple features in TiKV transactions.

Examples

use tikv_client::{Config, TransactionClient};
use futures::prelude::*;
let client = TransactionClient::new(vec!["192.168.0.100"]).await.unwrap();
let txn = client.begin_optimistic().await.unwrap();

Fields

status: Arc<RwLock<TransactionStatus>>timestamp: Timestampbuffer: Bufferrpc: Arc<PdC>options: TransactionOptionsis_heartbeat_started: bool

Implementations

impl<PdC: PdClient> Transaction<PdC>[src]

pub(crate) fn new(
    timestamp: Timestamp,
    rpc: Arc<PdC>,
    options: TransactionOptions
) -> Transaction<PdC>
[src]

pub async fn get(&self, key: impl Into<Key>) -> Result<Option<Value>>[src]

Create a new ‘get’ request

Once resolved this request will result in the fetching of the value associated with the given key.

Retuning Ok(None) indicates the key does not exist in TiKV.

Examples

let mut txn = client.begin_optimistic().await.unwrap();
let key = "TiKV".to_owned();
let result: Option<Value> = txn.get(key).await.unwrap();
// Finish the transaction...
txn.commit().await.unwrap();

pub async fn get_for_update(
    &mut self,
    key: impl Into<Key>
) -> Result<Option<Value>>
[src]

Create a get for udpate request. Once resolved this request will pessimistically lock and fetch the latest value associated with the given key at current timestamp.

The “current timestamp” (also called for_update_ts of the request) is fetched immediately from PD.

Note: The behavior of this command does not follow snapshot isolation. It is similar to select for update in TiDB, which is similar to that in MySQL. It reads the latest value (using current timestamp), and the value is not cached in the local buffer. So normal get-like commands after get_for_update will not be influenced, they still read values at start_ts.

Different from get, this request does not distinguish between empty values and non-existent keys , i.e. querying non-existent keys will result in empty values.

It can only be used in pessimistic mode.

Examples

let mut txn = client.begin_pessimistic().await.unwrap();
let key = "TiKV".to_owned();
let result: Value = txn.get_for_update(key).await.unwrap().unwrap();
// now the key "TiKV" is locked, other transactions cannot modify it
// Finish the transaction...
txn.commit().await.unwrap();

pub async fn key_exists(&self, key: impl Into<Key>) -> Result<bool>[src]

Check whether the key exists.

Examples

let mut txn = client.begin_pessimistic().await.unwrap();
let exists = txn.key_exists("k1".to_owned()).await.unwrap();
txn.commit().await.unwrap();

pub async fn batch_get(
    &self,
    keys: impl IntoIterator<Item = impl Into<Key>>
) -> Result<impl Iterator<Item = KvPair>>
[src]

Create a new ‘batch get’ request.

Once resolved this request will result in the fetching of the values associated with the given keys.

Non-existent entries will not appear in the result. The order of the keys is not retained in the result.

Examples

let mut txn = client.begin_optimistic().await.unwrap();
let keys = vec!["TiKV".to_owned(), "TiDB".to_owned()];
let result: HashMap<Key, Value> = txn
    .batch_get(keys)
    .await
    .unwrap()
    .map(|pair| (pair.0, pair.1))
    .collect();
// Finish the transaction...
txn.commit().await.unwrap();

async fn batch_get_for_update(
    &mut self,
    keys: impl IntoIterator<Item = impl Into<Key>>
) -> Result<impl Iterator<Item = KvPair>>
[src]

Create a new ‘batch get for update’ request.

Once resolved this request will pessimistically lock the keys and fetch the values associated with the given keys.

Note: The behavior of this command does not follow snapshot isolation. It is similar to select for update in TiDB, which is similar to that in MySQL. It reads the latest value (using current timestamp), and the value is not cached in the local buffer. So normal get-like commands after batch_get_for_update will not be influenced, they still read values at start_ts.

Different from batch_get, this request does not distinguish between empty values and non-existent keys , i.e. querying non-existent keys will result in empty values.

It can only be used in pessimistic mode.

Examples

let mut txn = client.begin_pessimistic().await.unwrap();
let keys = vec!["TiKV".to_owned(), "TiDB".to_owned()];
let result: HashMap<Key, Value> = txn
    .batch_get_for_update(keys)
    .await
    .unwrap()
    .map(|pair| (pair.0, pair.1))
    .collect();
// now "TiKV" and "TiDB" are both locked
// Finish the transaction...
txn.commit().await.unwrap();

pub async fn scan(
    &self,
    range: impl Into<BoundRange>,
    limit: u32
) -> Result<impl Iterator<Item = KvPair>>
[src]

Create a new ‘scan’ request.

Once resolved this request will result in a Vec of key-value pairs that lies in the specified range.

If the number of eligible key-value pairs are greater than limit, only the first limit pairs are returned, ordered by the key.

Examples

let mut txn = client.begin_optimistic().await.unwrap();
let key1: Key = b"TiKV".to_vec().into();
let key2: Key = b"TiDB".to_vec().into();
let result: Vec<KvPair> = txn
    .scan(key1..key2, 10)
    .await
    .unwrap()
    .collect();
// Finish the transaction...
txn.commit().await.unwrap();

pub async fn scan_keys(
    &self,
    range: impl Into<BoundRange>,
    limit: u32
) -> Result<impl Iterator<Item = Key>>
[src]

Create a new ‘scan’ request that only returns the keys.

Once resolved this request will result in a Vec of keys that lies in the specified range.

If the number of eligible keys are greater than limit, only the first limit keys are returned, ordered by the key.

Examples

let mut txn = client.begin_optimistic().await.unwrap();
let key1: Key = b"TiKV".to_vec().into();
let key2: Key = b"TiDB".to_vec().into();
let result: Vec<Key> = txn
    .scan_keys(key1..key2, 10)
    .await
    .unwrap()
    .collect();
// Finish the transaction...
txn.commit().await.unwrap();

pub(crate) fn scan_reverse(
    &self,
    _range: impl RangeBounds<Key>
) -> BoxStream<'_, Result<KvPair>>
[src]

Create a ‘scan_reverse’ request.

Similar to scan, but in the reverse direction.

pub async fn put(
    &mut self,
    key: impl Into<Key>,
    value: impl Into<Value>
) -> Result<()>
[src]

Sets the value associated with the given key.

Examples

let mut txn = client.begin_optimistic().await.unwrap();
let key = "TiKV".to_owned();
let val = "TiKV".to_owned();
txn.put(key, val);
// Finish the transaction...
txn.commit().await.unwrap();

pub async fn insert(
    &mut self,
    key: impl Into<Key>,
    value: impl Into<Value>
) -> Result<()>
[src]

Inserts the value associated with the given key. It has a constraint that key should not exist before.

Examples

let mut txn = client.begin_optimistic().await.unwrap();
let key = "TiKV".to_owned();
let val = "TiKV".to_owned();
txn.insert(key, val);
// Finish the transaction...
txn.commit().await.unwrap();

pub async fn delete(&mut self, key: impl Into<Key>) -> Result<()>[src]

Deletes the given key.

Deleting a non-existent key will not result in an error.

Examples

let mut txn = client.begin_optimistic().await.unwrap();
let key = "TiKV".to_owned();
txn.delete(key);
// Finish the transaction...
txn.commit().await.unwrap();

pub async fn lock_keys(
    &mut self,
    keys: impl IntoIterator<Item = impl Into<Key>>
) -> Result<()>
[src]

Lock the given keys without mutating value (at the time of commit).

In optimistic mode, write conflicts are not checked until commit. So use this command to indicate that “I do not want to commit if the value associated with this key has been modified”. It’s useful to avoid write skew anomaly.

In pessimistic mode, it is similar to batch_get_for_update, except that it does not read values.

Examples

let mut txn = client.begin_optimistic().await.unwrap();
txn.lock_keys(vec!["TiKV".to_owned(), "Rust".to_owned()]);
// ... Do some actions.
txn.commit().await.unwrap();

pub async fn commit(&mut self) -> Result<Option<Timestamp>>[src]

Commits the actions of the transaction. On success, we return the commit timestamp (or None if there was nothing to commit).

Examples

let mut txn = client.begin_optimistic().await.unwrap();
// ... Do some actions.
let req = txn.commit();
let result: Timestamp = req.await.unwrap().unwrap();

pub async fn rollback(&mut self) -> Result<()>[src]

Rollback the transaction.

If it succeeds, all mutations made by this transaciton will not take effect.

pub async fn send_heart_beat(&mut self) -> Result<u64>[src]

Send a heart beat message to keep the transaction alive on the server and update its TTL.

Returns the TTL set on the lock by the server.

async fn scan_inner(
    &self,
    range: impl Into<BoundRange>,
    limit: u32,
    key_only: bool
) -> Result<impl Iterator<Item = KvPair>>
[src]

async fn pessimistic_lock(
    &mut self,
    keys: impl IntoIterator<Item = Key>,
    need_value: bool
) -> Result<Vec<Option<Value>>>
[src]

Pessimistically lock the keys.

Once resolved it acquires a lock on the key in TiKV. The lock prevents other transactions from mutating the entry until it is released.

Only valid for pessimistic transactions, panics if called on an optimistic transaction.

async fn check_allow_operation(&self) -> Result<()>[src]

Checks if the transaction can perform arbitrary operations.

fn is_pessimistic(&self) -> bool[src]

async fn start_auto_heartbeat(&mut self)[src]

Trait Implementations

impl<PdC: PdClient> Drop for Transaction<PdC>[src]

Auto Trait Implementations

impl<PdC = PdRpcClient<TikvConnect, Cluster>> !RefUnwindSafe for Transaction<PdC>

impl<PdC> Send for Transaction<PdC>

impl<PdC> Sync for Transaction<PdC>

impl<PdC> Unpin for Transaction<PdC>

impl<PdC = PdRpcClient<TikvConnect, Cluster>> !UnwindSafe for Transaction<PdC>

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<T> From<T> for T[src]

impl<T> Instrument for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.

impl<V, T> VZip<V> for T where
    V: MultiLane<T>, 
[src]