#![cfg(any(
feature = "kv-mem",
feature = "kv-rocksdb",
feature = "kv-surrealkv",
feature = "kv-tikv",
))]
use uuid::Uuid;
use super::CreateDs;
use crate::kvs::LockType::*;
use crate::kvs::TransactionType::*;
pub async fn conditional_delete_conflicts_with_conditional_write(new_ds: impl CreateDs) {
let node_id = Uuid::parse_str("2f7c9a1e-3b4d-4c5e-8a6f-0d1e2f3a4b5c").unwrap();
let (ds, _) = new_ds.create_ds(node_id).await;
let tx = ds.transaction(Write, Optimistic).await.unwrap();
tx.set(&"test", &b"0".to_vec()).await.unwrap();
tx.commit().await.unwrap();
let tx1 = ds.transaction(Write, Optimistic).await.unwrap();
tx1.putc(&"test", &b"1".to_vec(), Some(&b"0".to_vec())).await.unwrap();
let tx2 = ds.transaction(Write, Optimistic).await.unwrap();
tx2.delc(&"test", Some(&b"0".to_vec())).await.unwrap();
tx1.commit().await.unwrap();
tx2.commit().await.unwrap_err();
let tx = ds.transaction(Read, Optimistic).await.unwrap();
assert_eq!(tx.get(&"test", None).await.unwrap().unwrap(), b"1");
tx.cancel().await.unwrap();
}
pub async fn conditional_write_is_rejected_after_a_conditional_delete(new_ds: impl CreateDs) {
let node_id = Uuid::parse_str("3a8d0b2f-4c5e-4d6f-9b7a-1e2f3a4b5c6d").unwrap();
let (ds, _) = new_ds.create_ds(node_id).await;
let tx = ds.transaction(Write, Optimistic).await.unwrap();
tx.set(&"test", &b"0".to_vec()).await.unwrap();
tx.commit().await.unwrap();
let tx1 = ds.transaction(Write, Optimistic).await.unwrap();
tx1.putc(&"test", &b"1".to_vec(), Some(&b"0".to_vec())).await.unwrap();
let tx2 = ds.transaction(Write, Optimistic).await.unwrap();
tx2.delc(&"test", Some(&b"0".to_vec())).await.unwrap();
tx2.commit().await.unwrap();
tx1.commit().await.unwrap_err();
let tx = ds.transaction(Read, Optimistic).await.unwrap();
assert!(tx.get(&"test", None).await.unwrap().is_none());
tx.cancel().await.unwrap();
}
pub async fn concurrent_conditional_writes_conflict(new_ds: impl CreateDs) {
let node_id = Uuid::parse_str("4b9e1c30-5d6f-4e70-ac8b-2f3a4b5c6d7e").unwrap();
let (ds, _) = new_ds.create_ds(node_id).await;
let tx = ds.transaction(Write, Optimistic).await.unwrap();
tx.set(&"test", &b"0".to_vec()).await.unwrap();
tx.commit().await.unwrap();
let tx1 = ds.transaction(Write, Optimistic).await.unwrap();
tx1.putc(&"test", &b"1".to_vec(), Some(&b"0".to_vec())).await.unwrap();
let tx2 = ds.transaction(Write, Optimistic).await.unwrap();
tx2.putc(&"test", &b"1".to_vec(), Some(&b"0".to_vec())).await.unwrap();
tx1.commit().await.unwrap();
tx2.commit().await.unwrap_err();
let tx = ds.transaction(Read, Optimistic).await.unwrap();
assert_eq!(tx.get(&"test", None).await.unwrap().unwrap(), b"1");
tx.cancel().await.unwrap();
}
pub async fn a_same_value_conditional_write_loses_to_a_plain_write(new_ds: impl CreateDs) {
let node_id = Uuid::parse_str("5c0f2d41-6e70-4f81-bd9c-3a4b5c6d7e8f").unwrap();
let (ds, _) = new_ds.create_ds(node_id).await;
let tx = ds.transaction(Write, Optimistic).await.unwrap();
tx.set(&"test", &b"0".to_vec()).await.unwrap();
tx.commit().await.unwrap();
let page = ds.transaction(Write, Optimistic).await.unwrap();
page.putc(&"test", &b"0".to_vec(), Some(&b"0".to_vec())).await.unwrap();
let bump = ds.transaction(Write, Optimistic).await.unwrap();
bump.set(&"test", &b"1".to_vec()).await.unwrap();
bump.commit().await.unwrap();
page.commit().await.unwrap_err();
let tx = ds.transaction(Read, Optimistic).await.unwrap();
assert_eq!(tx.get(&"test", None).await.unwrap().unwrap(), b"1");
tx.cancel().await.unwrap();
}
macro_rules! define_tests {
($new_ds:ident) => {
#[tokio::test]
#[serial_test::serial]
async fn conditional_delete_conflicts_with_conditional_write() {
use super::conditional_write_fences as fences;
fences::conditional_delete_conflicts_with_conditional_write($new_ds).await;
}
#[tokio::test]
#[serial_test::serial]
async fn conditional_write_is_rejected_after_a_conditional_delete() {
use super::conditional_write_fences as fences;
fences::conditional_write_is_rejected_after_a_conditional_delete($new_ds).await;
}
#[tokio::test]
#[serial_test::serial]
async fn concurrent_conditional_writes_conflict() {
use super::conditional_write_fences as fences;
fences::concurrent_conditional_writes_conflict($new_ds).await;
}
#[tokio::test]
#[serial_test::serial]
async fn a_same_value_conditional_write_loses_to_a_plain_write() {
use super::conditional_write_fences as fences;
fences::a_same_value_conditional_write_loses_to_a_plain_write($new_ds).await;
}
};
}
pub(crate) use define_tests;