Use non-monotonic versionstamps with TiKV by default (#2343)
This commit is contained in:
parent
5f0aaa0973
commit
89a9ac4168
4 changed files with 90 additions and 11 deletions
|
@ -14,6 +14,7 @@ use crate::key::root::hb::Hb;
|
||||||
use crate::sql;
|
use crate::sql;
|
||||||
use crate::sql::Value;
|
use crate::sql::Value;
|
||||||
use crate::sql::{Query, Uuid};
|
use crate::sql::{Query, Uuid};
|
||||||
|
use crate::vs;
|
||||||
use channel::Receiver;
|
use channel::Receiver;
|
||||||
use channel::Sender;
|
use channel::Sender;
|
||||||
use futures::lock::Mutex;
|
use futures::lock::Mutex;
|
||||||
|
@ -47,6 +48,9 @@ pub struct Datastore {
|
||||||
query_timeout: Option<Duration>,
|
query_timeout: Option<Duration>,
|
||||||
// The maximum duration timeout for running multiple statements in a transaction
|
// The maximum duration timeout for running multiple statements in a transaction
|
||||||
transaction_timeout: Option<Duration>,
|
transaction_timeout: Option<Duration>,
|
||||||
|
// The versionstamp oracle for this datastore.
|
||||||
|
// Used only in some datastores, such as tikv.
|
||||||
|
vso: Arc<Mutex<vs::Oracle>>,
|
||||||
// Whether this datastore enables live query notifications to subscribers
|
// Whether this datastore enables live query notifications to subscribers
|
||||||
notification_channel: Option<(Sender<Notification>, Receiver<Notification>)>,
|
notification_channel: Option<(Sender<Notification>, Receiver<Notification>)>,
|
||||||
}
|
}
|
||||||
|
@ -244,6 +248,7 @@ impl Datastore {
|
||||||
strict: false,
|
strict: false,
|
||||||
query_timeout: None,
|
query_timeout: None,
|
||||||
transaction_timeout: None,
|
transaction_timeout: None,
|
||||||
|
vso: Arc::new(Mutex::new(vs::Oracle::systime_counter())),
|
||||||
notification_channel: None,
|
notification_channel: None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -531,6 +536,7 @@ impl Datastore {
|
||||||
inner,
|
inner,
|
||||||
cache: super::cache::Cache::default(),
|
cache: super::cache::Cache::default(),
|
||||||
cf: cf::Writer::new(),
|
cf: cf::Writer::new(),
|
||||||
|
vso: self.vso.clone(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -137,6 +137,7 @@ impl Transaction {
|
||||||
Ok(u64_to_versionstamp(ver))
|
Ok(u64_to_versionstamp(ver))
|
||||||
}
|
}
|
||||||
/// Obtain a new key that is suffixed with the change timestamp
|
/// Obtain a new key that is suffixed with the change timestamp
|
||||||
|
#[allow(unused)]
|
||||||
pub async fn get_versionstamped_key<K>(
|
pub async fn get_versionstamped_key<K>(
|
||||||
&mut self,
|
&mut self,
|
||||||
ts_key: K,
|
ts_key: K,
|
||||||
|
|
|
@ -16,8 +16,10 @@ use crate::sql::paths::OUT;
|
||||||
use crate::sql::thing::Thing;
|
use crate::sql::thing::Thing;
|
||||||
use crate::sql::Strand;
|
use crate::sql::Strand;
|
||||||
use crate::sql::Value;
|
use crate::sql::Value;
|
||||||
|
use crate::vs::Oracle;
|
||||||
use crate::vs::Versionstamp;
|
use crate::vs::Versionstamp;
|
||||||
use channel::Sender;
|
use channel::Sender;
|
||||||
|
use futures::lock::Mutex;
|
||||||
use sql::permission::Permissions;
|
use sql::permission::Permissions;
|
||||||
use sql::statements::DefineAnalyzerStatement;
|
use sql::statements::DefineAnalyzerStatement;
|
||||||
use sql::statements::DefineDatabaseStatement;
|
use sql::statements::DefineDatabaseStatement;
|
||||||
|
@ -46,6 +48,7 @@ pub struct Transaction {
|
||||||
pub(super) inner: Inner,
|
pub(super) inner: Inner,
|
||||||
pub(super) cache: Cache,
|
pub(super) cache: Cache,
|
||||||
pub(super) cf: cf::Writer,
|
pub(super) cf: cf::Writer,
|
||||||
|
pub(super) vso: Arc<Mutex<Oracle>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::large_enum_variant)]
|
#[allow(clippy::large_enum_variant)]
|
||||||
|
@ -409,6 +412,21 @@ impl Transaction {
|
||||||
{
|
{
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
trace!("Get Timestamp {:?}", key);
|
trace!("Get Timestamp {:?}", key);
|
||||||
|
let use_nonmonontonic = match self {
|
||||||
|
#[cfg(feature = "kv-tikv")]
|
||||||
|
Transaction {
|
||||||
|
inner: Inner::TiKV(v),
|
||||||
|
..
|
||||||
|
} => true,
|
||||||
|
_ => false,
|
||||||
|
};
|
||||||
|
let nonmonotonic_vs = if use_nonmonontonic {
|
||||||
|
self.get_non_monotonic_versionstamp().await
|
||||||
|
} else {
|
||||||
|
Err(Error::Internal(
|
||||||
|
"Non-monotonic versionstamps are only supported on TiKV".to_string(),
|
||||||
|
))
|
||||||
|
};
|
||||||
match self {
|
match self {
|
||||||
#[cfg(feature = "kv-mem")]
|
#[cfg(feature = "kv-mem")]
|
||||||
Transaction {
|
Transaction {
|
||||||
|
@ -429,7 +447,11 @@ impl Transaction {
|
||||||
Transaction {
|
Transaction {
|
||||||
inner: Inner::TiKV(v),
|
inner: Inner::TiKV(v),
|
||||||
..
|
..
|
||||||
} => v.get_timestamp(key, lock).await,
|
} => {
|
||||||
|
// TODO Make it configurable to use monotonic or non-monotonic versionstamps
|
||||||
|
// v.get_timestamp(key, lock).await
|
||||||
|
nonmonotonic_vs
|
||||||
|
}
|
||||||
#[cfg(feature = "kv-fdb")]
|
#[cfg(feature = "kv-fdb")]
|
||||||
Transaction {
|
Transaction {
|
||||||
inner: Inner::FoundationDB(v),
|
inner: Inner::FoundationDB(v),
|
||||||
|
@ -445,6 +467,29 @@ impl Transaction {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
|
async fn get_non_monotonic_versionstamp(&mut self) -> Result<Versionstamp, Error> {
|
||||||
|
Ok(self.vso.lock().await.now())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
|
async fn get_non_monotonic_versionstamped_key<K>(
|
||||||
|
&mut self,
|
||||||
|
prefix: K,
|
||||||
|
suffix: K,
|
||||||
|
) -> Result<Vec<u8>, Error>
|
||||||
|
where
|
||||||
|
K: Into<Key>,
|
||||||
|
{
|
||||||
|
let prefix: Key = prefix.into();
|
||||||
|
let suffix: Key = suffix.into();
|
||||||
|
let ts = self.get_non_monotonic_versionstamp().await?;
|
||||||
|
let mut k: Vec<u8> = prefix.clone();
|
||||||
|
k.append(&mut ts.to_vec());
|
||||||
|
k.append(&mut suffix.clone());
|
||||||
|
Ok(k)
|
||||||
|
}
|
||||||
|
|
||||||
/// Insert or update a key in the datastore.
|
/// Insert or update a key in the datastore.
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
pub async fn set_versionstamped_key<K, V>(
|
pub async fn set_versionstamped_key<K, V>(
|
||||||
|
@ -455,11 +500,25 @@ impl Transaction {
|
||||||
val: V,
|
val: V,
|
||||||
) -> Result<(), Error>
|
) -> Result<(), Error>
|
||||||
where
|
where
|
||||||
K: Into<Key> + Debug,
|
K: Into<Key> + Debug + Clone,
|
||||||
V: Into<Val> + Debug,
|
V: Into<Val> + Debug,
|
||||||
{
|
{
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
trace!("Set {:?} <ts> {:?} => {:?}", prefix, suffix, val);
|
trace!("Set {:?} <ts> {:?} => {:?}", prefix, suffix, val);
|
||||||
|
let nonmonotonic_key: Result<Vec<u8>, Error> = match self {
|
||||||
|
#[cfg(feature = "kv-tikv")]
|
||||||
|
Transaction {
|
||||||
|
inner: Inner::TiKV(v),
|
||||||
|
..
|
||||||
|
} => self.get_non_monotonic_versionstamped_key(prefix.clone(), suffix.clone()).await,
|
||||||
|
// We need this to make the compiler happy.
|
||||||
|
// The below is unreachable only when only the tikv feature is enabled.
|
||||||
|
// It's still reachable if we enabled more than one kv feature.
|
||||||
|
#[allow(unreachable_patterns)]
|
||||||
|
_ => Err(Error::Internal(
|
||||||
|
"Non-monotonic versionstamps are only supported on TiKV".to_string(),
|
||||||
|
)),
|
||||||
|
};
|
||||||
match self {
|
match self {
|
||||||
#[cfg(feature = "kv-mem")]
|
#[cfg(feature = "kv-mem")]
|
||||||
Transaction {
|
Transaction {
|
||||||
|
@ -490,7 +549,10 @@ impl Transaction {
|
||||||
inner: Inner::TiKV(v),
|
inner: Inner::TiKV(v),
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
let k = v.get_versionstamped_key(ts_key, prefix, suffix).await?;
|
// TODO Maybe make it configurable to use monotonic or non-monotonic versionstamps
|
||||||
|
// at the database definition time?
|
||||||
|
// let k = v.get_versionstamped_key(ts_key, prefix, suffix).await?;
|
||||||
|
let k = nonmonotonic_key?;
|
||||||
v.set(k, val).await
|
v.set(k, val).await
|
||||||
}
|
}
|
||||||
#[cfg(feature = "kv-fdb")]
|
#[cfg(feature = "kv-fdb")]
|
||||||
|
|
|
@ -52,6 +52,22 @@ pub enum Oracle {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Oracle {
|
impl Oracle {
|
||||||
|
#[allow(unused)]
|
||||||
|
pub fn systime_counter() -> Self {
|
||||||
|
Oracle::SysTimeCounter(SysTimeCounter {
|
||||||
|
state: Mutex::new((0, 0)),
|
||||||
|
stale: (0, 0),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
|
pub fn epoch_counter() -> Self {
|
||||||
|
Oracle::EpochCounter(EpochCounter {
|
||||||
|
epoch: 0,
|
||||||
|
counter: AtomicU64::new(0),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
pub fn now(&mut self) -> Versionstamp {
|
pub fn now(&mut self) -> Versionstamp {
|
||||||
match self {
|
match self {
|
||||||
|
@ -141,10 +157,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn systime_counter() {
|
fn systime_counter() {
|
||||||
let mut o = Oracle::SysTimeCounter(SysTimeCounter {
|
let mut o = Oracle::systime_counter();
|
||||||
state: Mutex::new((0, 0)),
|
|
||||||
stale: (0, 0),
|
|
||||||
});
|
|
||||||
let a = to_u128_be(o.now());
|
let a = to_u128_be(o.now());
|
||||||
let b = to_u128_be(o.now());
|
let b = to_u128_be(o.now());
|
||||||
assert!(a < b, "a = {}, b = {}", a, b);
|
assert!(a < b, "a = {}, b = {}", a, b);
|
||||||
|
@ -152,10 +165,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn epoch_counter() {
|
fn epoch_counter() {
|
||||||
let mut o1 = Oracle::EpochCounter(EpochCounter {
|
let mut o1 = Oracle::epoch_counter();
|
||||||
epoch: 0,
|
|
||||||
counter: AtomicU64::new(0),
|
|
||||||
});
|
|
||||||
let a = to_u128_be(o1.now());
|
let a = to_u128_be(o1.now());
|
||||||
let b = to_u128_be(o1.now());
|
let b = to_u128_be(o1.now());
|
||||||
assert!(a < b, "a = {}, b = {}", a, b);
|
assert!(a < b, "a = {}, b = {}", a, b);
|
||||||
|
|
Loading…
Reference in a new issue