Feat bulk locking (#1422)

* Feat: Multi-lock capabilities add to config

* wip: RPC.rs fixes, new combinatoric

* wip: changes

* chore: More things that are bulk

* fix: Saving

* chore: Remove a dyn object

* chore: Add tests + remove unused

* Fix/feat  bulk locking (#1427)

* fix: health check

* fix: start/stop service

* fix: install/uninstall services

* chore: Fix the notifications

* fix: Version

* fix: Version as serde

* chore: Update to latest patch db

* chore: Change the htLock to something that makes more sense

* chore: Fix the rest of the ht

* "chore: More ht_lock":
This commit is contained in:
J M
2022-05-09 14:53:39 -06:00
committed by GitHub
parent 5d3bc8cfa5
commit 864555bcf0
26 changed files with 2080 additions and 743 deletions

View File

@@ -2,11 +2,10 @@ use std::cmp::Ordering;
use async_trait::async_trait;
use color_eyre::eyre::eyre;
use patch_db::json_ptr::JsonPointer;
use patch_db::{DbHandle, LockType};
use patch_db::DbHandle;
use rpc_toolkit::command;
use crate::{Error, ResultExt};
use crate::{init::InitReceipts, Error};
mod v0_3_0;
mod v0_3_0_1;
@@ -15,7 +14,7 @@ mod v0_3_0_3;
pub type Current = v0_3_0_3::Version;
#[derive(serde::Serialize, serde::Deserialize)]
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
#[serde(untagged)]
enum Version {
V0_3_0(Wrapper<v0_3_0::Version>),
@@ -25,6 +24,27 @@ enum Version {
Other(emver::Version),
}
impl Version {
fn from_util_version(version: crate::util::Version) -> Self {
serde_json::to_value(version.clone())
.and_then(serde_json::from_value)
.unwrap_or_else(|_e| {
tracing::warn!("Can't deserialize: {:?} and falling back to other", version);
Version::Other(version.into_version())
})
}
#[cfg(test)]
fn as_sem_ver(&self) -> emver::Version {
match self {
Version::V0_3_0(Wrapper(x)) => x.semver(),
Version::V0_3_0_1(Wrapper(x)) => x.semver(),
Version::V0_3_0_2(Wrapper(x)) => x.semver(),
Version::V0_3_0_3(Wrapper(x)) => x.semver(),
Version::Other(x) => x.clone(),
}
}
}
#[async_trait]
pub trait VersionT
where
@@ -36,16 +56,18 @@ where
fn compat(&self) -> &'static emver::VersionRange;
async fn up<Db: DbHandle>(&self, db: &mut Db) -> Result<(), Error>;
async fn down<Db: DbHandle>(&self, db: &mut Db) -> Result<(), Error>;
async fn commit<Db: DbHandle>(&self, db: &mut Db) -> Result<(), Error> {
crate::db::DatabaseModel::new()
.server_info()
.eos_version_compat()
.put(db, &self.compat())
async fn commit<Db: DbHandle>(
&self,
db: &mut Db,
receipts: &InitReceipts,
) -> Result<(), Error> {
receipts
.version_range
.set(db, self.compat().clone())
.await?;
crate::db::DatabaseModel::new()
.server_info()
.version()
.put(db, &self.semver().into())
receipts
.server_version
.set(db, self.semver().into())
.await?;
Ok(())
@@ -54,10 +76,11 @@ where
&self,
version: &V,
db: &mut Db,
receipts: &InitReceipts,
) -> Result<(), Error> {
match self.semver().cmp(&version.semver()) {
Ordering::Greater => self.rollback_to_unchecked(version, db).await,
Ordering::Less => version.migrate_from_unchecked(self, db).await,
Ordering::Greater => self.rollback_to_unchecked(version, db, receipts).await,
Ordering::Less => version.migrate_from_unchecked(self, db, receipts).await,
Ordering::Equal => Ok(()),
}
}
@@ -65,31 +88,38 @@ where
&self,
version: &V,
db: &mut Db,
receipts: &InitReceipts,
) -> Result<(), Error> {
let previous = Self::Previous::new();
if version.semver() != previous.semver() {
previous.migrate_from_unchecked(version, db).await?;
previous
.migrate_from_unchecked(version, db, receipts)
.await?;
}
tracing::info!("{} -> {}", previous.semver(), self.semver(),);
self.up(db).await?;
self.commit(db).await?;
self.commit(db, receipts).await?;
Ok(())
}
async fn rollback_to_unchecked<V: VersionT, Db: DbHandle>(
&self,
version: &V,
db: &mut Db,
receipts: &InitReceipts,
) -> Result<(), Error> {
let previous = Self::Previous::new();
tracing::info!("{} -> {}", self.semver(), previous.semver(),);
self.down(db).await?;
previous.commit(db).await?;
previous.commit(db, receipts).await?;
if version.semver() != previous.semver() {
previous.rollback_to_unchecked(version, db).await?;
previous
.rollback_to_unchecked(version, db, receipts)
.await?;
}
Ok(())
}
}
#[derive(Debug, Clone)]
struct Wrapper<T>(T);
impl<T> serde::Serialize for Wrapper<T>
where
@@ -106,7 +136,7 @@ where
fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
let v = crate::util::Version::deserialize(deserializer)?;
let version = T::new();
if &*v == &version.semver() {
if *v == version.semver() {
Ok(Wrapper(version))
} else {
Err(serde::de::Error::custom("Mismatched Version"))
@@ -114,17 +144,16 @@ where
}
}
pub async fn init<Db: DbHandle>(db: &mut Db) -> Result<(), Error> {
let ptr: JsonPointer = "/server-info/version"
.parse()
.with_kind(crate::ErrorKind::Database)?;
db.lock(ptr.clone(), LockType::Write).await?;
let version: Version = db.get(&ptr).await?;
pub async fn init<Db: DbHandle>(
db: &mut Db,
receipts: &crate::init::InitReceipts,
) -> Result<(), Error> {
let version = Version::from_util_version(receipts.server_version.get(db).await?);
match version {
Version::V0_3_0(v) => v.0.migrate_to(&Current::new(), db).await?,
Version::V0_3_0_1(v) => v.0.migrate_to(&Current::new(), db).await?,
Version::V0_3_0_2(v) => v.0.migrate_to(&Current::new(), db).await?,
Version::V0_3_0_3(v) => v.0.migrate_to(&Current::new(), db).await?,
Version::V0_3_0(v) => v.0.migrate_to(&Current::new(), db, receipts).await?,
Version::V0_3_0_1(v) => v.0.migrate_to(&Current::new(), db, receipts).await?,
Version::V0_3_0_2(v) => v.0.migrate_to(&Current::new(), db, receipts).await?,
Version::V0_3_0_3(v) => v.0.migrate_to(&Current::new(), db, receipts).await?,
Version::Other(_) => {
return Err(Error::new(
eyre!("Cannot downgrade"),
@@ -135,10 +164,47 @@ pub async fn init<Db: DbHandle>(db: &mut Db) -> Result<(), Error> {
Ok(())
}
pub const COMMIT_HASH: &'static str =
pub const COMMIT_HASH: &str =
git_version::git_version!(args = ["--always", "--abbrev=40", "--dirty=-modified"]);
#[command(rename = "git-info", local, metadata(authenticated = false))]
pub fn git_info() -> Result<&'static str, Error> {
Ok(COMMIT_HASH)
}
#[cfg(test)]
mod tests {
use super::*;
use proptest::prelude::*;
fn em_version() -> impl Strategy<Value = emver::Version> {
any::<(usize, usize, usize, usize)>().prop_map(|(major, minor, patch, super_minor)| {
emver::Version::new(major, minor, patch, super_minor)
})
}
fn versions() -> impl Strategy<Value = Version> {
prop_oneof![
Just(Version::V0_3_0(Wrapper(v0_3_0::Version::new()))),
Just(Version::V0_3_0_1(Wrapper(v0_3_0_1::Version::new()))),
Just(Version::V0_3_0_2(Wrapper(v0_3_0_2::Version::new()))),
Just(Version::V0_3_0_3(Wrapper(v0_3_0_3::Version::new()))),
em_version().prop_map(Version::Other),
]
}
proptest! {
#[test]
fn emversion_isomorphic_version(original in em_version()) {
let version = Version::from_util_version(original.clone().into());
let back = version.as_sem_ver();
prop_assert_eq!(original, back, "All versions should round trip");
}
#[test]
fn version_isomorphic_em_version(version in versions()) {
let sem_ver = version.as_sem_ver();
let back = Version::from_util_version(sem_ver.into());
prop_assert_eq!(format!("{:?}",version), format!("{:?}", back), "All versions should round trip");
}
}
}

View File

@@ -14,6 +14,7 @@ lazy_static! {
);
}
#[derive(Debug, Clone)]
pub struct Version;
#[async_trait]
impl VersionT for Version {

View File

@@ -11,6 +11,7 @@ use crate::util::Invoke;
const V0_3_0_1: emver::Version = emver::Version::new(0, 3, 0, 1);
#[derive(Debug, Clone)]
pub struct Version;
#[async_trait]
impl VersionT for Version {

View File

@@ -4,6 +4,7 @@ use super::*;
const V0_3_0_2: emver::Version = emver::Version::new(0, 3, 0, 2);
#[derive(Debug, Clone)]
pub struct Version;
#[async_trait]
impl VersionT for Version {

View File

@@ -4,6 +4,7 @@ use super::*;
const V0_3_0_3: emver::Version = emver::Version::new(0, 3, 0, 3);
#[derive(Clone, Debug)]
pub struct Version;
#[async_trait]
impl VersionT for Version {