Skip to content
Snippets Groups Projects

Patchable db

Closed inso requested to merge patchable_db into dev
2 files
+ 114
24
Compare changes
  • Side-by-side
  • Inline

Files

+ 113
24
@@ -54,7 +54,7 @@ use std::path::PathBuf;
@@ -54,7 +54,7 @@ use std::path::PathBuf;
use self::block::DALBlock;
use self::block::DALBlock;
pub struct DuniterDB(pub sqlite::Connection);
pub struct DuniterDB(pub sqlite::Connection, pub usize);
impl Debug for DuniterDB {
impl Debug for DuniterDB {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
@@ -98,6 +98,68 @@ fn _use_json_macro() -> serde_json::Value {
@@ -98,6 +98,68 @@ fn _use_json_macro() -> serde_json::Value {
json!({})
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> {
pub fn open_db(db_path: &PathBuf, memory_mode: bool) -> Result<DuniterDB, sqlite::Error> {
let conn: sqlite::Connection;
let conn: sqlite::Connection;
if memory_mode || !db_path.as_path().exists() {
if memory_mode || !db_path.as_path().exists() {
@@ -106,32 +168,34 @@ pub fn open_db(db_path: &PathBuf, memory_mode: bool) -> Result<DuniterDB, sqlite
@@ -106,32 +168,34 @@ pub fn open_db(db_path: &PathBuf, memory_mode: bool) -> Result<DuniterDB, sqlite
} else {
} else {
conn = sqlite::open(db_path.as_path())?;
conn = sqlite::open(db_path.as_path())?;
}
}
//conn.execute("PRAGMA synchronous = 0;")
//conn.execute("PRAGMA synchronous = 0;")
//.expect("Fail to configure SQLite DB (PRAGMA) !");
//.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);
",
)?;
} else {
} else {
conn = sqlite::open(db_path.as_path())?;
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 let Err(e) = patch(&db) {
 
db.0
 
.execute("ROLLBACK;")
 
.expect("Fail to rollback transaction !");
 
return Err(e);
 
}
 
if let Err(e) = increment_version(&mut db) {
 
db.0
 
.execute("ROLLBACK;")
 
.expect("Fail to rollback transaction !");
 
return Err(e);
 
}
 
db.0
 
.execute("COMMIT;")
 
.expect("Fail to commit transaction !");
 
}
 
Ok(db)
}
}
pub fn close_db(db: &DuniterDB) {
pub fn close_db(db: &DuniterDB) {
@@ -264,3 +328,28 @@ pub enum BlockchainError {
@@ -264,3 +328,28 @@ pub enum BlockchainError {
UnexpectedBlockNumber(),
UnexpectedBlockNumber(),
UnknowError(),
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