Skip to content
Snippets Groups Projects

Patchable db

Closed inso requested to merge patchable_db into dev
2 files
+ 108
24
Compare changes
  • Side-by-side
  • Inline
Files
2
+ 107
24
@@ -54,7 +54,7 @@ use std::path::PathBuf;
use self::block::DALBlock;
pub struct DuniterDB(pub sqlite::Connection);
pub struct DuniterDB(pub sqlite::Connection, pub usize);
impl Debug for DuniterDB {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
@@ -98,6 +98,69 @@ fn _use_json_macro() -> serde_json::Value {
json!({})
}
fn init_db(db: &DuniterDB) -> Result<&DuniterDB, sqlite::Error> {
db.0
.execute(
"
CREATE TABLE meta (version INTEGER);
CREATE TABLE wot_history (block_number INTEGER, block_hash TEXT, sentries_count INTEGER,
average_density INTEGER, average_distance INTEGER,
distances TEXT, average_connectivity INTEGER, connectivities TEXT,
average_centrality INTEGER, centralities TEXT);
CREATE TABLE blocks (fork INTEGER, isolate INTEGER, version INTEGER, nonce INTEGER, number INTEGER,
pow_min INTEGER, time INTEGER, median_time INTEGER, members_count INTEGER,
monetary_mass INTEGER, unit_base INTEGER, issuers_count INTEGER, issuers_frame INTEGER,
issuers_frame_var INTEGER, median_frame INTEGER, second_tiercile_frame INTEGER,
currency TEXT, issuer TEXT, signature TEXT, hash TEXT, previous_hash TEXT, inner_hash TEXT, dividend INTEGER, identities TEXT, joiners TEXT,
actives TEXT, leavers TEXT, revoked TEXT, excluded TEXT, certifications TEXT,
transactions TEXT);
CREATE TABLE identities (wotb_id INTEGER, uid TEXT, pubkey TEXT, hash TEXT, sig TEXT,
state INTEGER, created_on TEXT, joined_on TEXT, penultimate_renewed_on TEXT, last_renewed_on TEXT,
expires_on INTEGER, revokes_on INTEGER, expired_on TEXT, revoked_on TEXT);
CREATE TABLE certifications (pubkey_from TEXT, pubkey_to TEXT, created_on TEXT,
signature TEXT, written_on TEXT, expires_on INTEGER, chainable_on INTEGER);
INSERT INTO meta VALUES (0);",
)?;
Ok(db)
}
fn patches(
conn: &sqlite::Connection,
) -> (
usize,
Vec<fn(&DuniterDB) -> Result<&DuniterDB, sqlite::Error>>,
) {
let dbpatches: Vec<fn(&DuniterDB) -> Result<&DuniterDB, sqlite::Error>> = vec![init_db];
let version = match conn.prepare("SELECT version FROM meta;") {
Ok(statement) => statement
.cursor()
.next()
.expect("next meta version")
.unwrap_or(&[sqlite::Value::Integer(0)])[0]
.as_integer()
.expect("meta version") as usize,
Err(_) => 0,
};
let ret = dbpatches
.iter()
.enumerate()
.filter(|&(i, _patch)| i >= version)
.map(|(_i, patch)| patch.clone())
.collect::<Vec<fn(&DuniterDB) -> Result<&DuniterDB, sqlite::Error>>>();
(version, ret)
}
fn increment_version(db: &mut DuniterDB) -> Result<&DuniterDB, sqlite::Error> {
db.1 += 1;
db.0
.execute(format!("UPDATE meta SET version={};", db.1))
.expect("Failed to incrmeent version !");
Ok(db)
}
/// Open a database file and patches it
pub fn open_db(db_path: &PathBuf, memory_mode: bool) -> Result<DuniterDB, sqlite::Error> {
let conn: sqlite::Connection;
if memory_mode || !db_path.as_path().exists() {
@@ -106,32 +169,27 @@ pub fn open_db(db_path: &PathBuf, memory_mode: bool) -> Result<DuniterDB, sqlite
} else {
conn = sqlite::open(db_path.as_path())?;
}
//conn.execute("PRAGMA synchronous = 0;")
//.expect("Fail to configure SQLite DB (PRAGMA) !");
conn.execute(
"
CREATE TABLE wot_history (block_number INTEGER, block_hash TEXT, sentries_count INTEGER,
average_density INTEGER, average_distance INTEGER,
distances TEXT, average_connectivity INTEGER, connectivities TEXT,
average_centrality INTEGER, centralities TEXT);
CREATE TABLE blocks (fork INTEGER, isolate INTEGER, version INTEGER, nonce INTEGER, number INTEGER,
pow_min INTEGER, time INTEGER, median_time INTEGER, members_count INTEGER,
monetary_mass INTEGER, unit_base INTEGER, issuers_count INTEGER, issuers_frame INTEGER,
issuers_frame_var INTEGER, median_frame INTEGER, second_tiercile_frame INTEGER,
currency TEXT, issuer TEXT, signature TEXT, hash TEXT, previous_hash TEXT, inner_hash TEXT, dividend INTEGER, identities TEXT, joiners TEXT,
actives TEXT, leavers TEXT, revoked TEXT, excluded TEXT, certifications TEXT,
transactions TEXT);
CREATE TABLE identities (wotb_id INTEGER, uid TEXT, pubkey TEXT, hash TEXT, sig TEXT,
state INTEGER, created_on TEXT, joined_on TEXT, penultimate_renewed_on TEXT, last_renewed_on TEXT,
expires_on INTEGER, revokes_on INTEGER, expired_on TEXT, revoked_on TEXT);
CREATE TABLE certifications (pubkey_from TEXT, pubkey_to TEXT, created_on TEXT,
signature TEXT, written_on TEXT, expires_on INTEGER, chainable_on INTEGER);
",
)?;
//conn.execute("PRAGMA synchronous = 0;")
//.expect("Fail to configure SQLite DB (PRAGMA) !");
} else {
conn = sqlite::open(db_path.as_path())?;
}
Ok(DuniterDB(conn))
let (version, dbpatches) = patches(&conn);
let mut db = DuniterDB(conn, version);
for patch in dbpatches.iter() {
db.0
.execute("BEGIN TRANSACTION;")
.expect("Fail to begin transaction !");
if patch(&db).is_err() || increment_version(&mut db).is_err() {
db.0
.execute("ROLLBACK;")
.expect("Fail to rollback transaction !");
}
db.0
.execute("COMMIT;")
.expect("Fail to commit transaction !");
}
Ok(db)
}
pub fn close_db(db: &DuniterDB) {
@@ -264,3 +322,28 @@ pub enum BlockchainError {
UnexpectedBlockNumber(),
UnknowError(),
}
#[cfg(test)]
mod tests {
use super::*;
use duniter_crypto::keys::{ed25519, Signature};
use std::path::PathBuf;
#[test]
fn test_open_db() {
let pathbuf = PathBuf::new();
let db = open_db(&pathbuf, true).expect("cannot open db");
match db.0.prepare("SELECT version FROM meta;") {
Ok(statement) => assert!(
statement
.cursor()
.next()
.expect("next meta version")
.unwrap_or(&[sqlite::Value::Integer(0)])[0]
.as_integer()
.expect("meta version") as usize > 0
),
Err(_) => assert!(false),
};
}
}
Loading