|
@@ -1,5 +1,7 @@
|
|
|
|
+use std::collections::HashMap;
|
|
|
|
+
|
|
use crate::{
|
|
use crate::{
|
|
- db::ConnectionLease,
|
|
|
|
|
|
+ db::{ConnectionLease, Transaction},
|
|
query::{Insertable, Queryable},
|
|
query::{Insertable, Queryable},
|
|
schema::{
|
|
schema::{
|
|
collect::{EntityStateContainer, PartType},
|
|
collect::{EntityStateContainer, PartType},
|
|
@@ -9,6 +11,8 @@ use crate::{
|
|
DBResult,
|
|
DBResult,
|
|
};
|
|
};
|
|
|
|
|
|
|
|
+use sha2::Digest;
|
|
|
|
+
|
|
use super::Schema;
|
|
use super::Schema;
|
|
|
|
|
|
#[derive(Debug)]
|
|
#[derive(Debug)]
|
|
@@ -92,13 +96,27 @@ impl IndexInfo {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+#[derive(Debug)]
|
|
pub(crate) struct DatabaseSchema {
|
|
pub(crate) struct DatabaseSchema {
|
|
- signature: u64,
|
|
|
|
- queries: Vec<String>,
|
|
|
|
|
|
+ signature: String,
|
|
|
|
+ table_queries: HashMap<String, String>,
|
|
|
|
+ index_queries: HashMap<String, String>,
|
|
}
|
|
}
|
|
|
|
|
|
impl DatabaseSchema {
|
|
impl DatabaseSchema {
|
|
- const SCHEMA_SIGNATURE_KEY: &'static str = "schema_signature";
|
|
|
|
|
|
+ pub(crate) const SCHEMA_SIGNATURE_KEY: &'static str = "schema_signature";
|
|
|
|
+
|
|
|
|
+ pub fn signature(&self) -> &str {
|
|
|
|
+ self.signature.as_str()
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ pub fn table_queries(&self) -> &HashMap<String, String> {
|
|
|
|
+ &self.table_queries
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ pub fn index_queries(&self) -> &HashMap<String, String> {
|
|
|
|
+ &self.index_queries
|
|
|
|
+ }
|
|
|
|
|
|
/// Three possible results:
|
|
/// Three possible results:
|
|
/// - yes, this is a schema match (true)
|
|
/// - yes, this is a schema match (true)
|
|
@@ -106,7 +124,7 @@ impl DatabaseSchema {
|
|
/// - there is no schema that we know of (None)
|
|
/// - there is no schema that we know of (None)
|
|
pub fn check(&self, lease: &mut ConnectionLease) -> Option<bool> {
|
|
pub fn check(&self, lease: &mut ConnectionLease) -> Option<bool> {
|
|
// attempt to use connection as a MetadataDB database
|
|
// attempt to use connection as a MetadataDB database
|
|
- let metadb = meta::MetadataDB::build();
|
|
|
|
|
|
+ let metadb = meta::MetadataDB::default();
|
|
|
|
|
|
// check to see if the signature exists and matches
|
|
// check to see if the signature exists and matches
|
|
metadb
|
|
metadb
|
|
@@ -115,39 +133,47 @@ impl DatabaseSchema {
|
|
.get(lease)
|
|
.get(lease)
|
|
.ok()
|
|
.ok()
|
|
.flatten()
|
|
.flatten()
|
|
- .map(|kv| kv.value.parse::<u64>().unwrap_or(0) == self.signature)
|
|
|
|
|
|
+ .map(|kv| kv.value == self.signature)
|
|
|
|
+ // .map(|kv| kv.value.parse::<u64>().unwrap_or(0) == self.signature)
|
|
}
|
|
}
|
|
|
|
|
|
pub fn create(&self, lease: &mut ConnectionLease) -> DBResult<()> {
|
|
pub fn create(&self, lease: &mut ConnectionLease) -> DBResult<()> {
|
|
- lease.execute_raw_sql("BEGIN TRANSACTION")?;
|
|
|
|
- for query in self.queries.iter() {
|
|
|
|
- log::trace!("Running creation query {query}");
|
|
|
|
- lease.execute_raw_sql(query)?;
|
|
|
|
|
|
+ let mut txn = Transaction::new(lease, "_microrm_create")?;
|
|
|
|
+ for query in self.table_queries.iter() {
|
|
|
|
+ log::trace!("Running creation query {}", query.1);
|
|
|
|
+ txn.lease().execute_raw_sql(query.1)?;
|
|
|
|
+ }
|
|
|
|
+ for query in self.index_queries.iter() {
|
|
|
|
+ log::trace!("Running creation query {}", query.1);
|
|
|
|
+ txn.lease().execute_raw_sql(query.1)?;
|
|
}
|
|
}
|
|
|
|
|
|
// attempt to use connection as a MetadataDB database
|
|
// attempt to use connection as a MetadataDB database
|
|
- let metadb = meta::MetadataDB::build();
|
|
|
|
|
|
+ let metadb = meta::MetadataDB::default();
|
|
|
|
|
|
- for query in collect_from_database::<meta::MetadataDB>().queries.iter() {
|
|
|
|
- lease.execute_raw_sql(query)?;
|
|
|
|
|
|
+ for query in collect_from_database(&meta::MetadataDB::default())
|
|
|
|
+ .table_queries
|
|
|
|
+ .iter()
|
|
|
|
+ {
|
|
|
|
+ txn.lease().execute_raw_sql(query.1)?;
|
|
}
|
|
}
|
|
|
|
|
|
- lease.execute_raw_sql("COMMIT")?;
|
|
|
|
-
|
|
|
|
// store signature
|
|
// store signature
|
|
metadb.metastore.insert(
|
|
metadb.metastore.insert(
|
|
- lease,
|
|
|
|
|
|
+ txn.lease(),
|
|
meta::MicrormMeta {
|
|
meta::MicrormMeta {
|
|
key: Self::SCHEMA_SIGNATURE_KEY.into(),
|
|
key: Self::SCHEMA_SIGNATURE_KEY.into(),
|
|
value: format!("{}", self.signature),
|
|
value: format!("{}", self.signature),
|
|
},
|
|
},
|
|
)?;
|
|
)?;
|
|
|
|
|
|
|
|
+ txn.commit()?;
|
|
|
|
+
|
|
Ok(())
|
|
Ok(())
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-pub(crate) fn collect_from_database<DB: Schema>() -> DatabaseSchema {
|
|
|
|
|
|
+pub(crate) fn collect_from_database<DB: Schema>(schema: &DB) -> DatabaseSchema {
|
|
struct IV(EntityStateContainer, Vec<IndexInfo>);
|
|
struct IV(EntityStateContainer, Vec<IndexInfo>);
|
|
|
|
|
|
impl DatabaseItemVisitor for IV {
|
|
impl DatabaseItemVisitor for IV {
|
|
@@ -183,7 +209,7 @@ pub(crate) fn collect_from_database<DB: Schema>() -> DatabaseSchema {
|
|
|
|
|
|
let mut iv = IV(EntityStateContainer::default(), Default::default());
|
|
let mut iv = IV(EntityStateContainer::default(), Default::default());
|
|
|
|
|
|
- DB::accept_item_visitor(&mut iv);
|
|
|
|
|
|
+ schema.accept_item_visitor(&mut iv);
|
|
|
|
|
|
// now to turn all that into a set of tables
|
|
// now to turn all that into a set of tables
|
|
let mut tables = std::collections::HashMap::new();
|
|
let mut tables = std::collections::HashMap::new();
|
|
@@ -280,13 +306,11 @@ pub(crate) fn collect_from_database<DB: Schema>() -> DatabaseSchema {
|
|
tables.insert(table_name, table);
|
|
tables.insert(table_name, table);
|
|
}
|
|
}
|
|
|
|
|
|
- // this must be a stable hash function, so we very explicitly want to use a SipHasher with
|
|
|
|
- // known parameters
|
|
|
|
- #[allow(deprecated)]
|
|
|
|
- let mut signature_hasher = std::hash::SipHasher::new();
|
|
|
|
- use std::hash::{Hash, Hasher};
|
|
|
|
|
|
+ // this must be a stable hash function, so we use sha2
|
|
|
|
+ let mut hasher = sha2::Sha256::new();
|
|
|
|
|
|
- let mut queries = vec![];
|
|
|
|
|
|
+ let mut table_queries = vec![];
|
|
|
|
+ let mut index_queries = vec![];
|
|
|
|
|
|
// create sorted table list
|
|
// create sorted table list
|
|
let mut sorted_tables: Vec<_> = tables.into_iter().collect();
|
|
let mut sorted_tables: Vec<_> = tables.into_iter().collect();
|
|
@@ -295,19 +319,23 @@ pub(crate) fn collect_from_database<DB: Schema>() -> DatabaseSchema {
|
|
for (table_name, table) in sorted_tables {
|
|
for (table_name, table) in sorted_tables {
|
|
let create_sql = table.build_creation_query();
|
|
let create_sql = table.build_creation_query();
|
|
|
|
|
|
- table_name.hash(&mut signature_hasher);
|
|
|
|
- create_sql.hash(&mut signature_hasher);
|
|
|
|
- queries.push(create_sql);
|
|
|
|
|
|
+ hasher.update(&table_name);
|
|
|
|
+ hasher.update(&create_sql);
|
|
|
|
+ table_queries.push((table_name, create_sql));
|
|
}
|
|
}
|
|
|
|
|
|
for iinfo in iv.1.into_iter() {
|
|
for iinfo in iv.1.into_iter() {
|
|
- iinfo.hash(&mut signature_hasher);
|
|
|
|
- queries.push(iinfo.build_creation_query());
|
|
|
|
|
|
+ hasher.update(&iinfo.table_name);
|
|
|
|
+ let query = iinfo.build_creation_query();
|
|
|
|
+ hasher.update(&query);
|
|
|
|
+ index_queries.push((iinfo.table_name, query));
|
|
}
|
|
}
|
|
|
|
|
|
- let signature = signature_hasher.finish();
|
|
|
|
-
|
|
|
|
- log::trace!("Schema signature: {signature:x}");
|
|
|
|
|
|
+ let digest = hasher.finalize();
|
|
|
|
|
|
- DatabaseSchema { signature, queries }
|
|
|
|
|
|
+ DatabaseSchema {
|
|
|
|
+ signature: digest.into_iter().map(|v| format!("{:02x}", v)).collect(),
|
|
|
|
+ table_queries: HashMap::from_iter(table_queries.into_iter()),
|
|
|
|
+ index_queries: HashMap::from_iter(index_queries.into_iter()),
|
|
|
|
+ }
|
|
}
|
|
}
|