Skip to content
Snippets Groups Projects
Commit c687d2a7 authored by Éloïs's avatar Éloïs
Browse files

[ref] blockchain-dal: #162: migrate blocks collection in LMDB

parent 6298000d
No related branches found
No related tags found
No related merge requests found
Showing
with 1296 additions and 274 deletions
......@@ -478,6 +478,7 @@ dependencies = [
name = "durs-blockchain-dal"
version = "0.2.0-a"
dependencies = [
"bincode 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"dubp-block-doc 0.1.0",
"dubp-common-doc 0.1.0",
"dubp-currency-params 0.2.0",
......@@ -486,21 +487,36 @@ dependencies = [
"dubp-user-docs-tests-tools 0.1.0",
"dup-crypto 0.7.0",
"dup-crypto-tests-tools 0.1.0",
"durs-common-dal 0.1.0-a",
"durs-common-tests-tools 0.1.0",
"durs-common-tools 0.2.0",
"durs-conf 0.2.0-a",
"durs-module 0.2.0-a",
"durs-wot 0.8.0-a0.9",
"fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
"id_tree 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"rustbreak 2.0.0-rc3 (registry+https://github.com/rust-lang/crates.io-index)",
"rkv 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
"unwrap 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "durs-common-dal"
version = "0.1.0-a"
dependencies = [
"bincode 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"durs-common-tools 0.2.0",
"fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"rkv 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)",
"rustbreak 2.0.0-rc3 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
"unwrap 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "durs-common-tests-tools"
version = "0.1.0"
......@@ -909,14 +925,6 @@ dependencies = [
"uuid 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "id_tree"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"snowflake 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "idna"
version = "0.2.0"
......@@ -994,6 +1002,27 @@ dependencies = [
"vcpkg 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "lmdb-rkv"
version = "0.11.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
"lmdb-rkv-sys 0.8.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "lmdb-rkv-sys"
version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cc 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "log"
version = "0.4.8"
......@@ -1144,6 +1173,14 @@ dependencies = [
"vcpkg 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "ordered-float"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "os_type"
version = "2.2.0"
......@@ -1465,6 +1502,25 @@ dependencies = [
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rkv"
version = "0.9.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
"bincode 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
"failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lmdb-rkv 0.11.4 (registry+https://github.com/rust-lang/crates.io-index)",
"ordered-float 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)",
"url 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"uuid 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rpassword"
version = "1.0.2"
......@@ -1659,11 +1715,6 @@ name = "smallvec"
version = "0.6.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "snowflake"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "strsim"
version = "0.8.0"
......@@ -2024,7 +2075,6 @@ dependencies = [
"checksum hmac 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5dcb5e64cda4c23119ab41ba960d1e170a774c8e4b9d9e6a9bc18aabf5e59695"
"checksum httparse 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cd179ae861f0c2e53da70d892f5f3029f9594be0c41dc5269cd371691b1dc2f9"
"checksum human-panic 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "21638c5955a6daf3ecc42cae702335fc37a72a4abcc6959ce457b31a7d43bbdd"
"checksum id_tree 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1bb51d6d2c77a59bfe64a6e909a00140e680fc9a32c6f383e64ed462b3cab957"
"checksum idna 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "02e2673c30ee86b5b96a9cb52ad15718aa1f966f5ab9ad54a8b95d5ca33120a9"
"checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08"
"checksum itertools 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)" = "0d47946d458e94a1b7bcabbf6521ea7c037062c81f534615abcad76e84d4970d"
......@@ -2034,6 +2084,8 @@ dependencies = [
"checksum lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f"
"checksum libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)" = "34fcd2c08d2f832f376f4173a231990fa5aef4e99fb569867318a227ef4c06ba"
"checksum libz-sys 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)" = "2eb5e43362e38e2bca2fd5f5134c4d4564a23a5c28e9b95411652021a8675ebe"
"checksum lmdb-rkv 0.11.4 (registry+https://github.com/rust-lang/crates.io-index)" = "e25b4069789bf7ac069d6fd58229f18aec20c6f7cc9173cb731d11c10dbb6b6e"
"checksum lmdb-rkv-sys 0.8.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c60e2728ce41a4d4fa4ccf3d07c105bebf198721117e6328a3cf1cb7e4242c70"
"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7"
"checksum maplit 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "08cbb6b4fef96b6d77bfc40ec491b1690c779e77b05cd9f07f787ed376fd4c43"
"checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08"
......@@ -2052,6 +2104,7 @@ dependencies = [
"checksum opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c"
"checksum openssl 0.10.24 (registry+https://github.com/rust-lang/crates.io-index)" = "8152bb5a9b5b721538462336e3bef9a539f892715e5037fda0f984577311af15"
"checksum openssl-sys 0.9.49 (registry+https://github.com/rust-lang/crates.io-index)" = "f4fad9e54bd23bd4cbbe48fdc08a1b8091707ac869ef8508edea2fec77dcc884"
"checksum ordered-float 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "18869315e81473c951eb56ad5558bbc56978562d3ecfb87abb7a1e944cea4518"
"checksum os_type 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7edc011af0ae98b7f88cf7e4a83b70a54a75d2b8cb013d6efd02e5956207e9eb"
"checksum pbkdf2 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "006c038a43a45995a9670da19e67600114740e8511d4333bf97a56e66a7542d9"
"checksum pbr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "deb73390ab68d81992bd994d145f697451bb0b54fd39738e72eef32458ad6907"
......@@ -2088,6 +2141,7 @@ dependencies = [
"checksum regex 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88c3d9193984285d544df4a30c23a4e62ead42edf70a4452ceb76dac1ce05c26"
"checksum regex-syntax 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b143cceb2ca5e56d5671988ef8b15615733e7ee16cd348e064333b251b89343f"
"checksum remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e"
"checksum rkv 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)" = "4f9d6a4dd60be13a62ae1d19df68c0c85d77bbee3749b62bf35c49f207d3d750"
"checksum rpassword 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b273c91bd242ca03ad6d71c143b6f17a48790e61f21a6c78568fa2b6774a24a4"
"checksum rprompt 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1601f32bc5858aae3cbfa1c645c96c4d820cc5c16be0194f089560c00b6eb625"
"checksum rust-argon2 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4ca4eaef519b494d1f2848fc602d18816fed808a981aedf4f1f00ceb7c9d32cf"
......@@ -2111,7 +2165,6 @@ dependencies = [
"checksum simplelog 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e95345f185d5adeb8ec93459d2dc99654e294cc6ccf5b75414d8ea262de9a13"
"checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
"checksum smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ab606a9c5e214920bb66c458cd7be8ef094f813f20fe77a54cc7dbfff220d4b7"
"checksum snowflake 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "27207bb65232eda1f588cf46db2fee75c0808d557f6b3cf19a75f5d6d7c94df1"
"checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
"checksum structopt 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "16c2cdbf9cc375f15d1b4141bc48aeef444806655cd0e904207edc8d68d86ed7"
"checksum structopt-derive 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "53010261a84b37689f9ed7d395165029f9cc7abb9f56bbfe86bee2597ed25107"
......
......@@ -14,6 +14,7 @@ members = [
"lib/dubp/user-docs",
"lib/dubp/wot",
"lib/dunp/network-documents",
"lib/modules-lib/common-dal",
"lib/modules/blockchain/blockchain",
"lib/modules/blockchain/blockchain-dal",
"lib/modules/skeleton",
......
[package]
name = "durs-common-dal"
version = "0.1.0-a"
authors = ["librelois <elois@ifee.fr>"]
description = "Common Data Access Layer for Dunitrust project."
license = "AGPL-3.0"
edition = "2018"
[lib]
path = "src/lib.rs"
[dependencies]
bincode = "1.0.*"
durs-common-tools = { path = "../../tools/common-tools" }
fnv = "1.0.6"
log = "0.4.*"
rkv = "0.9.7"
rustbreak = {version = "2.0.0-rc3", features = ["bin_enc"]}
serde = { version = "1.0.*", features = ["derive"] }
serde_json = "1.0.*"
unwrap = "1.2.1"
[dev-dependencies]
[features]
// Copyright (C) 2017-2019 The AXIOM TEAM Association.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//! Common Datas Access Layer for Dunitrust project
//! Errors manadgment
use rustbreak::error::{RustbreakError, RustbreakErrorKind};
#[derive(Debug)]
/// Data Access Layer Error
pub enum DALError {
/// Abort write transaction
WriteAbort {
/// Reason of transaction abort
reason: String,
},
/// Error in write operation
WriteError,
/// Error in read operation
ReadError,
/// A database is corrupted, you have to reset the data completely
DBCorrupted,
/// Error with the file system
FileSystemError,
/// Serialization/Deserialization error
SerdeError(String),
/// Rkv store error
StoreError(rkv::error::StoreError),
/// Capturing a panic signal during a write operation
WritePanic,
/// Unknown error
UnknowError,
}
impl From<bincode::Error> for DALError {
fn from(e: bincode::Error) -> DALError {
DALError::SerdeError(format!("{}", e))
}
}
impl From<rkv::error::StoreError> for DALError {
fn from(e: rkv::error::StoreError) -> DALError {
DALError::StoreError(e)
}
}
impl<T> From<std::sync::PoisonError<T>> for DALError {
fn from(_: std::sync::PoisonError<T>) -> DALError {
DALError::DBCorrupted
}
}
impl From<RustbreakError> for DALError {
fn from(rust_break_error: RustbreakError) -> DALError {
match rust_break_error.kind() {
RustbreakErrorKind::Serialization => DALError::WriteError,
RustbreakErrorKind::Deserialization => DALError::ReadError,
RustbreakErrorKind::Poison => DALError::DBCorrupted,
RustbreakErrorKind::Backend => DALError::FileSystemError,
RustbreakErrorKind::WritePanic => DALError::WritePanic,
_ => DALError::UnknowError,
}
}
}
// Copyright (C) 2017-2019 The AXIOM TEAM Association.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//! Define free structure database
use crate::errors::DALError;
use rustbreak::backend::{FileBackend, MemoryBackend};
use rustbreak::error::RustbreakError;
use rustbreak::{deser::Bincode, Database, FileDatabase, MemoryDatabase};
use serde::de::DeserializeOwned;
use serde::Serialize;
use std::default::Default;
use std::fmt::Debug;
use std::fs;
use std::panic::UnwindSafe;
use std::path::PathBuf;
/// Open free structured rustbreak memory database
pub fn open_free_struct_memory_db<
D: Serialize + DeserializeOwned + Debug + Default + Clone + Send,
>() -> Result<MemoryDatabase<D, Bincode>, DALError> {
let backend = MemoryBackend::new();
let db = MemoryDatabase::<D, Bincode>::from_parts(D::default(), backend, Bincode);
Ok(db)
}
/// Open free structured rustbreak file database
pub fn open_free_struct_file_db<
D: Serialize + DeserializeOwned + Debug + Default + Clone + Send,
>(
dbs_folder_path: &PathBuf,
db_file_name: &str,
) -> Result<FileDatabase<D, Bincode>, DALError> {
let mut db_path = dbs_folder_path.clone();
db_path.push(db_file_name);
let file_path = db_path.as_path();
if file_path.exists()
&& fs::metadata(file_path)
.expect("fail to get file size")
.len()
> 0
{
let backend = FileBackend::open(db_path.as_path())?;
let db = FileDatabase::<D, Bincode>::from_parts(D::default(), backend, Bincode);
db.load()?;
Ok(db)
} else {
Ok(FileDatabase::<D, Bincode>::from_path(
db_path.as_path(),
D::default(),
)?)
}
}
#[derive(Debug)]
/// Database
pub enum BinFreeStructDb<D: Serialize + DeserializeOwned + Debug + Default + Clone + Send> {
/// File database
File(Database<D, FileBackend, Bincode>),
/// Memory database
Mem(Database<D, MemoryBackend, Bincode>),
}
impl<D: Serialize + DeserializeOwned + Debug + Default + Clone + Send> BinFreeStructDb<D> {
/// Flush the data structure to the backend
pub fn save(&self) -> Result<(), RustbreakError> {
match *self {
BinFreeStructDb::File(ref file_db) => file_db.save(),
BinFreeStructDb::Mem(ref mem_db) => mem_db.save(),
}
}
/// Read lock the database and get write access to the Data container
/// This gives you a read-only lock on the database. You can have as many readers in parallel as you wish.
pub fn read<T, R>(&self, task: T) -> Result<R, RustbreakError>
where
T: FnOnce(&D) -> R,
{
match *self {
BinFreeStructDb::File(ref file_db) => file_db.read(task),
BinFreeStructDb::Mem(ref mem_db) => mem_db.read(task),
}
}
/// Write lock the database and get write access to the Data container
/// This gives you an exclusive lock on the memory object. Trying to open the database in writing will block if it is currently being written to.
pub fn write<T>(&self, task: T) -> Result<(), RustbreakError>
where
T: FnOnce(&mut D),
{
match *self {
BinFreeStructDb::File(ref file_db) => file_db.write(task),
BinFreeStructDb::Mem(ref mem_db) => mem_db.write(task),
}
}
/// Write lock the database and get write access to the Data container in a safe way (clone of the internal data is made).
pub fn write_safe<T>(&self, task: T) -> Result<(), RustbreakError>
where
T: FnOnce(&mut D) + UnwindSafe,
{
match *self {
BinFreeStructDb::File(ref file_db) => file_db.write_safe(task),
BinFreeStructDb::Mem(ref mem_db) => mem_db.write_safe(task),
}
}
/// Load the Data from the backend
pub fn load(&self) -> Result<(), RustbreakError> {
match *self {
BinFreeStructDb::File(ref file_db) => file_db.load(),
BinFreeStructDb::Mem(ref mem_db) => mem_db.load(),
}
}
}
// Copyright (C) 2017-2019 The AXIOM TEAM Association.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//! Define Key-Value database
mod bin_kiv_db;
mod bin_kv_db;
mod file;
mod file_inner_trait;
mod mem;
pub use bin_kiv_db::FileKivDb;
pub use bin_kv_db::FileKvDb;
use crate::errors::DALError;
use durs_common_tools::fatal_error;
use file_inner_trait::FileKvDbInnerTrait;
use log::error;
use rkv::{EnvironmentFlags, IntegerStore, Manager, Rkv, SingleStore, StoreOptions, Value};
use rustbreak::{backend::MemoryBackend, deser::Bincode, MemoryDatabase};
use serde::de::DeserializeOwned;
use serde::Serialize;
use std::collections::HashMap;
use std::fmt::Debug;
use std::path::{Path, PathBuf};
/// Key-value Database with integer key
pub type BinKivDb<V> = KvDbStore<FileKivDb<V>>;
/// Key-value Database
pub type BinKvDb<K, V> = KvDbStore<FileKvDb<K, V>>;
// Key-value database reader
pub struct KvDbReader<'a> {
reader: Option<&'a rkv::Reader<'a>>,
}
/// Key-value database writer
pub struct KvDbWriter<'a> {
writer: Option<rkv::Writer<'a>>,
}
/// Key-value database
pub struct KvDb {
db: KvDbEnum,
}
/// Key-value database enum
enum KvDbEnum {
/// Key-value file Database
File(file::KvFileDb),
/// Key-value memory Database
Mem(mem::KvMemDb),
}
pub struct KvDbRO(KvDb);
impl KvDbRO {
// Try to clone read only handler
pub fn try_clone(&self) -> Result<KvDbRO, DALError> {
Ok(KvDbRO(self.0.try_clone()?))
}
}
impl KvDb {
/// Get read only handler
pub fn get_ro_handler(&self) -> Result<KvDbRO, DALError> {
Ok(KvDbRO(self.try_clone()?))
}
/// Open Key-value database
pub fn open_db(path: Option<&PathBuf>, schema: KbDbSchema) -> Result<KvDb, DALError> {
let db = if let Some(path) = path {
KvDbEnum::File(file::KvFileDb::open_db(path, &schema)?)
} else {
KvDbEnum::Mem(mem::KvMemDb::open_db(&schema)?)
};
Ok(KvDb { db })
}
/// Try to clone database handler
pub fn try_clone(&self) -> Result<KvDb, DALError> {
let db_clone = match &self.db {
KvDbEnum::File(fdb) => KvDbEnum::File(fdb.try_clone()?),
KvDbEnum::Mem(mdb) => KvDbEnum::Mem(mdb.clone()),
};
Ok(KvDb { db: db_clone })
}
}
/// Describe Key-Value database schema
#[derive(Debug, Clone)]
pub struct KbDbSchema {
stores: HashMap<String, KvDbStoreType>,
}
/// Key-value Database
pub enum KvDbStore<S>
where
S: FileKvDbTrait,
{
/// File database
File(S),
/// Memory database
Mem(MemoryDatabase<HashMap<<S as FileKvDbInnerTrait>::K, S::V>, Bincode>),
}
/// Key-value store type (store is like "table" in SGBD)
#[derive(Debug, Clone, Copy)]
pub enum KvDbStoreType {
/// Single valued map
Single,
/// Single valued map with integer key
SingleIntKey,
}
impl<S> KvDbStore<S>
where
S: FileKvDbTrait,
{
/// Get one value
pub fn get(
&self,
reader: &KvDbReader,
k: <S as FileKvDbInnerTrait>::K,
) -> Result<Option<S::V>, DALError> {
match self {
KvDbStore::File(file_kv_db) => file_kv_db.get(reader, k),
KvDbStore::Mem(mem_kv_db) => Ok(mem_kv_db.read(|datas| datas.get(&k).cloned())?),
}
}
/// Put one value
pub fn put(
&self,
writer: &mut KvDbWriter,
k: <S as FileKvDbInnerTrait>::K,
v: &S::V,
) -> Result<(), DALError> {
match self {
KvDbStore::File(file_kv_db) => file_kv_db.put(writer, k, v),
KvDbStore::Mem(mem_kv_db) => Ok(mem_kv_db.write(|datas| {
datas.insert(k, v.clone());
})?),
}
}
/// Delete one value
pub fn delete(
&self,
writer: &mut KvDbWriter,
k: <S as FileKvDbInnerTrait>::K,
) -> Result<(), DALError> {
match self {
KvDbStore::File(file_kv_db) => file_kv_db.delete(writer, k),
KvDbStore::Mem(mem_kv_db) => Ok(mem_kv_db.write(|datas| {
datas.remove(&k);
})?),
}
}
/// Open a Key-Value database
pub fn open(path: Option<&PathBuf>, collection_name: &str) -> Result<Self, DALError> {
if let Some(path) = path {
Ok(KvDbStore::File(S::open(path.as_path(), collection_name)?))
} else {
let backend = MemoryBackend::new();
Ok(KvDbStore::Mem(MemoryDatabase::<
HashMap<<S as FileKvDbInnerTrait>::K, S::V>,
Bincode,
>::from_parts(
HashMap::default(), backend, Bincode
)))
}
}
/// Read datas in transaction database
pub fn read<F, R>(&self, f: F) -> Result<R, DALError>
where
F: FnOnce(KvDbReader) -> Result<R, DALError>,
{
match self {
KvDbStore::File(file_kv_db) => file_kv_db.read(f),
KvDbStore::Mem(_) => f(KvDbReader { reader: None }),
}
}
/// Persist DB datas on disk
pub fn save(&self) -> Result<(), DALError> {
if let KvDbStore::File(file_kv_db) = self {
file_kv_db.save()
} else {
Ok(())
}
}
/// Write datas in database
/// /!\ The written data are visible to readers not persisted on the disk until a save() is performed.
pub fn write<F>(&self, f: F) -> Result<(), DALError>
where
F: FnOnce(KvDbWriter) -> Result<KvDbWriter, DALError>,
{
match self {
KvDbStore::File(file_kv_db) => file_kv_db.write(f),
KvDbStore::Mem(_) => {
f(KvDbWriter { writer: None })?;
Ok(())
}
}
}
}
pub trait FileKvDbTrait: FileKvDbInnerTrait {
/// Value
type V: 'static + Serialize + DeserializeOwned + Debug + Clone + Send;
/// Get one value
fn get(
&self,
reader: &KvDbReader,
k: <Self as FileKvDbInnerTrait>::K,
) -> Result<Option<Self::V>, DALError>;
/// Put one value
fn put(
&self,
writer: &mut KvDbWriter,
k: <Self as FileKvDbInnerTrait>::K,
v: &Self::V,
) -> Result<(), DALError> {
if let Some(ref mut writer) = writer.writer {
self.store_put(writer, k, &Value::Blob(&bincode::serialize(v)?[..]))?;
Ok(())
} else {
fatal_error!("Dev err: writer for file db must have a file writer");
}
}
/// Delete one value
fn delete(
&self,
writer: &mut KvDbWriter,
k: <Self as FileKvDbInnerTrait>::K,
) -> Result<(), DALError> {
if let Some(ref mut writer) = writer.writer {
self.store_delete(writer, k)?;
Ok(())
} else {
fatal_error!("Dev err: writer for file db must have a file writer");
}
}
/// Open a Key-Value database
fn open(path: &Path, collection_name: &str) -> Result<Self, DALError> {
let mut manager = Manager::singleton().write()?;
let mut env = Rkv::environment_builder();
env.set_flags(EnvironmentFlags::NO_SYNC)
.set_max_dbs(64)
.set_map_size(std::u32::MAX as usize);
let arc = manager.get_or_create(path, |path| Rkv::from_env(path, env))?;
Self::store_open(arc, collection_name)
}
/// Read datas in transaction database
fn read<F, D>(&self, f: F) -> Result<D, DALError>
where
F: FnOnce(KvDbReader) -> Result<D, DALError>,
{
Ok(f(KvDbReader {
reader: Some(&self.arc_clone().read()?.read()?),
})?)
}
/// Persist DB datas on disk
fn save(&self) -> Result<(), DALError> {
Ok(self.arc_clone().read()?.sync(true)?)
}
/// Write datas in database
/// /!\ The written data are visible to readers not persisted on the disk until a save() is performed.
fn write<F>(&self, f: F) -> Result<(), DALError>
where
F: FnOnce(KvDbWriter) -> Result<KvDbWriter, DALError>,
{
if let Some(writer) = f(KvDbWriter {
writer: Some(self.arc().read()?.write()?),
})?
.writer
{
writer.commit()?;
}
Ok(())
}
}
// Copyright (C) 2017-2019 The AXIOM TEAM Association.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//! Define Key-Value database with integer key
use super::file_inner_trait::FileKvDbInnerTrait;
use super::{FileKvDbTrait, KvDbReader};
use crate::errors::DALError;
use rkv::{IntegerStore, Rkv, StoreError, StoreOptions, Value};
use serde::de::DeserializeOwned;
use serde::Serialize;
use std::fmt::Debug;
use std::marker::PhantomData;
use std::sync::{Arc, RwLock};
/// Key-Value persisted DB with integer key
pub struct FileKivDb<V>
where
V: 'static + Serialize + DeserializeOwned + Debug + Clone + Send,
{
arc: Arc<RwLock<Rkv>>,
store: IntegerStore<u32>,
//store_name: String,
phantom: PhantomData<V>,
}
impl<V> FileKvDbInnerTrait for FileKivDb<V>
where
V: 'static + Serialize + DeserializeOwned + Debug + Clone + Send,
{
type K = u32;
fn arc(&self) -> &Arc<RwLock<Rkv>> {
&self.arc
}
fn arc_clone(&self) -> Arc<RwLock<Rkv>> {
self.arc().clone()
}
fn store_open(arc: Arc<RwLock<Rkv>>, store_name: &str) -> Result<Self, DALError> {
let store = arc
.clone()
.read()?
.open_integer(store_name, StoreOptions::create())?;
Ok(FileKivDb {
arc,
store,
//store_name: collection_name.to_owned(),
phantom: PhantomData,
})
}
fn store_put(
&self,
writer: &mut rkv::Writer,
k: Self::K,
value: &Value,
) -> Result<(), StoreError> {
self.store.put(writer, k, value)
}
fn store_delete(&self, writer: &mut rkv::Writer, k: Self::K) -> Result<(), StoreError> {
self.store.delete(writer, k)
}
}
impl<V> FileKvDbTrait for FileKivDb<V>
where
V: 'static + Serialize + DeserializeOwned + Debug + Clone + Send,
{
type V = V;
fn get(&self, reader: &KvDbReader, k: u32) -> Result<Option<V>, DALError> {
if let Some(Value::Blob(v)) = self.store.get(
reader
.reader
.expect("Dev err: reader for file db must have a file reader"),
k,
)? {
Ok(Some(bincode::deserialize(&v)?))
} else {
Ok(None)
}
}
}
// Copyright (C) 2017-2019 The AXIOM TEAM Association.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//! Define Key-Value database
use super::file_inner_trait::FileKvDbInnerTrait;
use super::{FileKvDbTrait, KvDbReader};
use crate::errors::DALError;
use rkv::{Rkv, SingleStore, StoreError, StoreOptions, Value};
use serde::de::DeserializeOwned;
use serde::Serialize;
use std::fmt::Debug;
use std::hash::Hash;
use std::marker::PhantomData;
use std::sync::{Arc, RwLock};
/// Key-Value persisted DB
pub struct FileKvDb<K, V>
where
K: 'static + AsRef<[u8]> + Clone + Debug + DeserializeOwned + Eq + Hash + Send + Serialize,
V: 'static + Serialize + DeserializeOwned + Debug + Clone + Send,
{
arc: Arc<RwLock<Rkv>>,
store: SingleStore,
//store_name: String,
phantom_key: PhantomData<K>,
phantom_value: PhantomData<V>,
}
impl<K, V> FileKvDbInnerTrait for FileKvDb<K, V>
where
K: 'static + AsRef<[u8]> + Clone + Debug + DeserializeOwned + Eq + Hash + Send + Serialize,
V: 'static + Serialize + DeserializeOwned + Debug + Clone + Send,
{
type K = K;
fn arc(&self) -> &Arc<RwLock<Rkv>> {
&self.arc
}
fn arc_clone(&self) -> Arc<RwLock<Rkv>> {
self.arc().clone()
}
fn store_open(arc: Arc<RwLock<Rkv>>, store_name: &str) -> Result<Self, DALError> {
let store = arc
.clone()
.read()?
.open_single(store_name, StoreOptions::create())?;
Ok(FileKvDb {
arc,
store,
//store_name: collection_name.to_owned(),
phantom_key: PhantomData,
phantom_value: PhantomData,
})
}
fn store_put(
&self,
writer: &mut rkv::Writer,
k: Self::K,
value: &Value,
) -> Result<(), StoreError> {
self.store.put(writer, k, value)
}
fn store_delete(&self, writer: &mut rkv::Writer, k: Self::K) -> Result<(), StoreError> {
self.store.delete(writer, k)
}
}
impl<K, V> FileKvDbTrait for FileKvDb<K, V>
where
K: 'static + AsRef<[u8]> + Clone + Debug + DeserializeOwned + Eq + Hash + Send + Serialize,
V: 'static + Serialize + DeserializeOwned + Debug + Clone + Send,
{
type V = V;
fn get(&self, reader: &KvDbReader, k: K) -> Result<Option<V>, DALError> {
if let Some(Value::Blob(v)) = self.store.get(
reader
.reader
.expect("Dev err: reader for file db must have a file reader"),
k,
)? {
Ok(Some(bincode::deserialize(&v)?))
} else {
Ok(None)
}
}
}
/*
impl<K, V> FileKvDb<K, V>
where
K: 'static + AsRef<[u8]> + Serialize + DeserializeOwned + Debug + Clone + Send,
V: 'static + Serialize + DeserializeOwned + Debug + Clone + Send,
{
/// Get one value
pub fn get(&self, reader: &KvDbReader, k: K) -> Result<Option<V>, DALError> {
if let Some(Value::Blob(v)) = self.store.get(
reader
.reader
.expect("Dev err: reader for file db must have a file reader"),
k,
)? {
Ok(Some(bincode::deserialize(&v)?))
} else {
Ok(None)
}
}
/// Put one value
pub fn put(&self, writer: &mut KvDbWriter, k: K, v: &V) -> Result<(), DALError> {
if let Some(ref mut writer) = writer.writer {
self.store
.put(writer, k, &Value::Blob(&bincode::serialize(v)?[..]))?;
Ok(())
} else {
fatal_error!("Dev err: writer for file db must have a file writer");
}
}
/// Delete one value
pub fn delete(&self, writer: &mut KvDbWriter, k: K) -> Result<(), DALError> {
if let Some(ref mut writer) = writer.writer {
self.store.delete(writer, k)?;
Ok(())
} else {
fatal_error!("Dev err: writer for file db must have a file writer");
}
}
/// Open a Key-Value database
pub fn open(path: &Path, collection_name: &str) -> Result<Self, DALError> {
let mut manager = Manager::singleton().write()?;
let mut env = Rkv::environment_builder();
env.set_flags(EnvironmentFlags::NO_SYNC)
.set_max_dbs(64)
.set_map_size(std::u32::MAX as usize);
let arc = manager.get_or_create(path, |path| Rkv::from_env(path, env))?;
let store = arc
.clone()
.read()?
.open_single(collection_name, StoreOptions::create())?;
Ok(FileKvDb {
arc,
store,
//store_name: collection_name.to_owned(),
phantom_key: PhantomData,
phantom_value: PhantomData,
})
}
/// Read datas in transaction database
pub fn read<F, D>(&self, f: F) -> Result<D, DALError>
where
F: FnOnce(KvDbReader) -> Result<D, DALError>,
{
Ok(f(KvDbReader {
reader: Some(&self.arc.clone().read()?.read()?),
})?)
}
/// Persist DB datas on disk
pub fn save(&self) -> Result<(), DALError> {
Ok(self.arc.clone().read()?.sync(true)?)
}
/// Write datas in database
/// /!\ The written data are visible to readers not persisted on the disk until a save() is performed.
pub fn write<F>(&self, f: F) -> Result<(), DALError>
where
F: FnOnce(KvDbWriter) -> Result<KvDbWriter, DALError>,
{
if let Some(writer) = f(KvDbWriter {
writer: Some(self.arc.read()?.write()?),
})?
.writer
{
writer.commit()?;
}
Ok(())
}
}
*/
// Copyright (C) 2017-2019 The AXIOM TEAM Association.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//! Define Key-Value file database
use super::{KbDbSchema, KvDbStoreType};
use crate::errors::DALError;
//se durs_common_tools::fatal_error;
//use log::error;
use rkv::{
DatabaseFlags, EnvironmentFlags, IntegerStore, Manager, Rkv, SingleStore, StoreOptions, Value,
};
use serde::de::DeserializeOwned;
use serde::Serialize;
use std::collections::HashMap;
use std::fmt::Debug;
use std::path::{Path, PathBuf};
/// Key-value file Database
pub struct KvFileDb {
path: PathBuf,
schema: KbDbSchema,
stores: HashMap<String, KvFileDbStore>,
}
/// Key-value file DB store (store is like "table" in SGBD)
enum KvFileDbStore {
/// Single valued map
Single(SingleStore),
/// Single valued map with integer key
SingleIntKey(IntegerStore<u32>),
}
impl KvFileDb {
/// Open Key-value file Database
pub fn open_db(path: &PathBuf, schema: &KbDbSchema) -> Result<KvFileDb, DALError> {
KvFileDb::open_db_inner(path, schema, true)
}
fn open_db_inner(
path: &PathBuf,
schema: &KbDbSchema,
first_open: bool,
) -> Result<KvFileDb, DALError> {
let mut manager = Manager::singleton().write()?;
let mut env = Rkv::environment_builder();
env.set_flags(EnvironmentFlags::NO_SYNC)
.set_max_dbs(64)
.set_map_size(std::u32::MAX as usize);
let arc = manager.get_or_create(path.as_path(), |path| Rkv::from_env(path, env))?;
let mut stores = HashMap::new();
for (store_name, store_type) in &schema.stores {
let store = match store_type {
KvDbStoreType::Single => KvFileDbStore::Single(arc.clone().read()?.open_single(
store_name.as_str(),
StoreOptions {
create: first_open,
flags: DatabaseFlags::empty(),
},
)?),
KvDbStoreType::SingleIntKey => {
KvFileDbStore::SingleIntKey(arc.clone().read()?.open_integer(
store_name.as_str(),
StoreOptions {
create: first_open,
flags: DatabaseFlags::empty(),
},
)?)
}
};
stores.insert(store_name.to_owned(), store);
}
Ok(KvFileDb {
path: path.clone(),
schema: schema.clone(),
stores,
})
}
/// Try to clone database handler
pub fn try_clone(&self) -> Result<KvFileDb, DALError> {
KvFileDb::open_db_inner(&self.path, &self.schema, false)
}
}
// Copyright (C) 2017-2019 The AXIOM TEAM Association.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//! Define inner trait must be implemented by all Key-Value databases
//! This inner trait is not public for other crates.
use crate::errors::DALError;
use rkv::{Rkv, StoreError, Value};
use serde::de::DeserializeOwned;
use serde::Serialize;
use std::fmt::Debug;
use std::hash::Hash;
use std::sync::{Arc, RwLock};
pub trait FileKvDbInnerTrait: Sized {
type K: 'static + Clone + Debug + DeserializeOwned + Eq + Hash + Send + Serialize;
fn arc(&self) -> &Arc<RwLock<Rkv>>;
fn arc_clone(&self) -> Arc<RwLock<Rkv>>;
fn store_open(arc: Arc<RwLock<Rkv>>, store_name: &str) -> Result<Self, DALError>;
fn store_put(
&self,
writer: &mut rkv::Writer,
k: Self::K,
value: &Value,
) -> Result<(), StoreError>;
fn store_delete(&self, writer: &mut rkv::Writer, k: Self::K) -> Result<(), StoreError>;
}
// Copyright (C) 2017-2019 The AXIOM TEAM Association.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//! Define Key-Value memory database
use super::{KbDbSchema, KvDbStoreType};
use crate::errors::DALError;
use rustbreak::{backend::MemoryBackend, deser::Bincode, MemoryDatabase};
use std::collections::HashMap;
use std::sync::Arc;
/// Key-value file Database
#[derive(Clone)]
pub struct KvMemDb {
stores: HashMap<String, KvMemDbStore>,
}
type KvMemDbSingleStore = MemoryDatabase<HashMap<Vec<u8>, Vec<u8>>, Bincode>;
type KvMemDbIntegerStore = MemoryDatabase<HashMap<u32, Vec<u8>>, Bincode>;
/// Key-value file DB store (store is like "table" in SGBD)
#[derive(Clone)]
enum KvMemDbStore {
/// Single valued map
Single(Arc<KvMemDbSingleStore>),
/// Single valued map with integer key
SingleIntKey(Arc<KvMemDbIntegerStore>),
}
impl KvMemDb {
/// Open Key-value file Database
pub fn open_db(schema: &KbDbSchema) -> Result<KvMemDb, DALError> {
let mut stores = HashMap::new();
for (store_name, store_type) in &schema.stores {
let backend = MemoryBackend::new();
let store = match store_type {
KvDbStoreType::Single => {
KvMemDbStore::Single(Arc::new(MemoryDatabase::<
HashMap<Vec<u8>, Vec<u8>>,
Bincode,
>::from_parts(
HashMap::default(), backend, Bincode
)))
}
KvDbStoreType::SingleIntKey => {
KvMemDbStore::SingleIntKey(Arc::new(MemoryDatabase::<
HashMap<u32, Vec<u8>>,
Bincode,
>::from_parts(
HashMap::default(), backend, Bincode
)))
}
};
stores.insert(store_name.to_owned(), store);
}
Ok(KvMemDb { stores })
}
}
// Copyright (C) 2017-2019 The AXIOM TEAM Association.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//! Common Datas Access Layer for Dunitrust project
#![allow(dead_code, unused_imports, clippy::large_enum_variant)]
#![deny(
missing_docs,
missing_copy_implementations,
trivial_casts,
trivial_numeric_casts,
unsafe_code,
unstable_features,
unused_import_braces,
unused_qualifications
)]
mod errors;
mod free_struct_db;
mod kv_db;
pub use errors::DALError;
pub use free_struct_db::{open_free_struct_file_db, open_free_struct_memory_db, BinFreeStructDb};
pub use kv_db::{BinKivDb, BinKvDb};
use serde::de::DeserializeOwned;
use serde::Serialize;
use std::default::Default;
use std::fmt::Debug;
use std::path::PathBuf;
/// Open free structured database
pub fn open_free_struct_db<D: Serialize + DeserializeOwned + Debug + Default + Clone + Send>(
dbs_folder_path: Option<&PathBuf>,
db_file_name: &str,
) -> Result<BinFreeStructDb<D>, DALError> {
if let Some(dbs_folder_path) = dbs_folder_path {
Ok(BinFreeStructDb::File(open_free_struct_file_db::<D>(
dbs_folder_path,
db_file_name,
)?))
} else {
Ok(BinFreeStructDb::Mem(open_free_struct_memory_db::<D>()?))
}
}
......@@ -10,6 +10,7 @@ edition = "2018"
path = "src/lib.rs"
[dependencies]
bincode = "1.0.*"
dubp-block-doc = { path = "../../../dubp/block-doc"} #, version = "0.1.0" }
dubp-common-doc = { path = "../../../dubp/common-doc"} #, version = "0.1.0" }
dubp-indexes = { path = "../../../dubp/indexes"} #, version = "0.1.0" }
......@@ -18,12 +19,12 @@ dubp-currency-params = { path = "../../../dubp/currency-params" }
dubp-user-docs= { path = "../../../dubp/user-docs" }
durs-conf = { path = "../../../core/conf" }
durs-module = { path = "../../../core/module" }
durs-common-dal = { path = "../../../modules-lib/common-dal" }
durs-common-tools = { path = "../../../tools/common-tools" }
durs-wot = { path = "../../../dubp/wot" }
fnv = "1.0.6"
id_tree = "1.3.0"
log = "0.4.*"
rustbreak = {version = "2.0.0-rc3", features = ["bin_enc"]}
rkv = "0.9.7"
serde = "1.0.*"
serde_derive = "1.0.*"
serde_json = "1.0.*"
......
......@@ -18,3 +18,6 @@ pub static DEFAULT_PAGE_SIZE: &'static usize = &50;
/// Currency parameters DB name
pub const CURRENCY_PARAMS_DB_NAME: &str = "params.db";
/// Local blockchain collection name
pub static LOCAL_BLOCKCHAIN_COLLECTION_NAME: &'static str = "bc";
......@@ -112,6 +112,7 @@ impl TreeNode {
#[derive(Debug, Clone, Serialize, Deserialize)]
/// Tree store all forks branchs
pub struct ForkTree {
current_blockstamp: Option<Blockstamp>,
main_branch: HashMap<BlockNumber, TreeNodeId>,
max_depth: usize,
nodes: Vec<Option<TreeNode>>,
......@@ -132,6 +133,7 @@ impl ForkTree {
#[inline]
pub fn new(max_depth: usize) -> Self {
ForkTree {
current_blockstamp: None,
main_branch: HashMap::with_capacity(max_depth + 1),
max_depth,
nodes: Vec::with_capacity(max_depth * 2),
......@@ -140,6 +142,11 @@ impl ForkTree {
sheets: HashSet::new(),
}
}
/// Get tree size
#[inline]
pub fn get_current_blockstamp(&self) -> Option<Blockstamp> {
self.current_blockstamp
}
/// Set max depth
#[inline]
pub fn set_max_depth(&mut self, max_depth: usize) {
......@@ -329,6 +336,9 @@ impl ForkTree {
self.pruning();
}
}
// Update current blockstamp
self.current_blockstamp = Some(new_current_blockstamp);
}
/// Find node with specific blockstamp
pub fn find_node_with_blockstamp(&self, blockstamp: &Blockstamp) -> Option<TreeNodeId> {
......@@ -377,6 +387,7 @@ impl ForkTree {
self.removed_blockstamps.clear();
if main_branch {
self.main_branch.insert(data.id, new_node_id);
self.current_blockstamp = Some(data);
if self.main_branch.len() > self.max_depth {
self.pruning();
}
......
......@@ -18,7 +18,6 @@
#![allow(clippy::large_enum_variant)]
#![deny(
missing_docs,
missing_debug_implementations,
missing_copy_implementations,
trivial_casts,
trivial_numeric_casts,
......@@ -45,39 +44,39 @@ pub mod filters;
/// Contains all read databases functions
pub mod readers;
//pub mod storage;
/// Tools
pub mod tools;
/// Contains all write databases functions
pub mod writers;
pub use durs_common_dal::{
open_free_struct_db, open_free_struct_file_db, open_free_struct_memory_db,
};
pub use durs_common_dal::{BinFreeStructDb, BinKivDb, DALError};
use crate::constants::LOCAL_BLOCKCHAIN_COLLECTION_NAME;
use crate::entities::block::DALBlock;
use crate::entities::identity::DALIdentity;
use crate::entities::sources::{SourceAmount, UTXOContentV10};
use crate::writers::transaction::DALTxV10;
use dubp_common_doc::{BlockNumber, Blockstamp, PreviousBlockstamp};
use dubp_indexes::sindex::UniqueIdUTXOv10;
use dubp_user_docs::documents::transaction::*;
use dup_crypto::hashs::Hash;
use dup_crypto::keys::*;
use durs_common_tools::fatal_error;
use durs_wot::data::{rusty::RustyWebOfTrust, NodeId};
use fnv::FnvHashMap;
use rustbreak::backend::{FileBackend, MemoryBackend};
use rustbreak::error::{RustbreakError, RustbreakErrorKind};
use rustbreak::{deser::Bincode, Database, FileDatabase, MemoryDatabase};
use serde::de::DeserializeOwned;
//use rkv::{IntegerStore, Value};
use serde::Serialize;
use std::collections::{HashMap, HashSet};
use std::default::Default;
use std::fmt::Debug;
use std::fs;
use std::panic::UnwindSafe;
use std::path::PathBuf;
use crate::entities::block::DALBlock;
use crate::entities::identity::DALIdentity;
use crate::entities::sources::{SourceAmount, UTXOContentV10};
use crate::writers::transaction::DALTxV10;
use dubp_indexes::sindex::UniqueIdUTXOv10;
/// All blocks of local blockchain indexed by block number
pub type LocalBlockchainV10Datas = FnvHashMap<BlockNumber, DALBlock>;
/// All blocks of local blockchain are stored in a key-value Db with integer key (block number)
pub type LocalBcDbV10 = BinKivDb<DALBlock>;
/// Forks tree meta datas (block number and hash only)
pub type ForksTreeV10Datas = entities::fork_tree::ForkTree;
/// Forks blocks referenced in tree indexed by their blockstamp
......@@ -101,77 +100,18 @@ pub type UDsV10Datas = HashMap<PubKey, HashSet<BlockNumber>>;
/// V10 Balances accounts
pub type BalancesV10Datas = HashMap<UTXOConditionsGroup, (SourceAmount, HashSet<UniqueIdUTXOv10>)>;
#[derive(Debug)]
/// Database
pub enum BinDB<D: Serialize + DeserializeOwned + Debug + Default + Clone + Send> {
/// File database
File(Database<D, FileBackend, Bincode>),
/// Memory database
Mem(Database<D, MemoryBackend, Bincode>),
}
impl<D: Serialize + DeserializeOwned + Debug + Default + Clone + Send> BinDB<D> {
/// Flush the data structure to the backend
pub fn save(&self) -> Result<(), RustbreakError> {
match *self {
BinDB::File(ref file_db) => file_db.save(),
BinDB::Mem(ref mem_db) => mem_db.save(),
}
}
/// Read lock the database and get write access to the Data container
/// This gives you a read-only lock on the database. You can have as many readers in parallel as you wish.
pub fn read<T, R>(&self, task: T) -> Result<R, RustbreakError>
where
T: FnOnce(&D) -> R,
{
match *self {
BinDB::File(ref file_db) => file_db.read(task),
BinDB::Mem(ref mem_db) => mem_db.read(task),
}
}
/// Write lock the database and get write access to the Data container
/// This gives you an exclusive lock on the memory object. Trying to open the database in writing will block if it is currently being written to.
pub fn write<T>(&self, task: T) -> Result<(), RustbreakError>
where
T: FnOnce(&mut D),
{
match *self {
BinDB::File(ref file_db) => file_db.write(task),
BinDB::Mem(ref mem_db) => mem_db.write(task),
}
}
/// Write lock the database and get write access to the Data container in a safe way (clone of the internal data is made).
pub fn write_safe<T>(&self, task: T) -> Result<(), RustbreakError>
where
T: FnOnce(&mut D) + UnwindSafe,
{
match *self {
BinDB::File(ref file_db) => file_db.write_safe(task),
BinDB::Mem(ref mem_db) => mem_db.write_safe(task),
}
}
/// Load the Data from the backend
pub fn load(&self) -> Result<(), RustbreakError> {
match *self {
BinDB::File(ref file_db) => file_db.load(),
BinDB::Mem(ref mem_db) => mem_db.load(),
}
}
}
#[derive(Debug)]
/// Set of databases storing block information
pub struct BlocksV10DBs {
/// Local blockchain database
pub blockchain_db: BinDB<LocalBlockchainV10Datas>,
pub blockchain_db: LocalBcDbV10,
}
impl BlocksV10DBs {
/// Open blocks databases from their respective files
pub fn open(db_path: Option<&PathBuf>) -> BlocksV10DBs {
BlocksV10DBs {
blockchain_db: open_db::<LocalBlockchainV10Datas>(db_path, "blockchain.db")
.expect("Fail to open LocalBlockchainV10DB"),
blockchain_db: LocalBcDbV10::open(db_path, LOCAL_BLOCKCHAIN_COLLECTION_NAME)
.expect("fail to open LocalBcDbV10"),
}
}
/// Save blocks databases in their respective files
......@@ -179,7 +119,7 @@ impl BlocksV10DBs {
info!("BLOCKCHAIN-DAL: Save LocalBlockchainV10DB.");
self.blockchain_db
.save()
.expect("Fatal error : fail to save LocalBlockchainV10DB !");
.expect("Fatal error : fail to save LocalBcDbV10 !");
}
}
......@@ -187,22 +127,25 @@ impl BlocksV10DBs {
/// Set of databases storing forks informations
pub struct ForksDBs {
/// Fork tree (store only blockstamp)
pub fork_tree_db: BinDB<ForksTreeV10Datas>,
pub fork_tree_db: BinFreeStructDb<ForksTreeV10Datas>,
/// Blocks in fork tree
pub fork_blocks_db: BinDB<ForksBlocksV10Datas>,
pub fork_blocks_db: BinFreeStructDb<ForksBlocksV10Datas>,
/// Orphan blocks
pub orphan_blocks_db: BinDB<OrphanBlocksV10Datas>,
pub orphan_blocks_db: BinFreeStructDb<OrphanBlocksV10Datas>,
}
impl ForksDBs {
/// Open fork databases from their respective files
pub fn open(db_path: Option<&PathBuf>) -> ForksDBs {
ForksDBs {
fork_tree_db: open_db::<ForksTreeV10Datas>(db_path, "fork_tree.db")
fork_tree_db: open_free_struct_db::<ForksTreeV10Datas>(db_path, "fork_tree.db")
.expect("Fail to open ForksTreeV10Datas"),
fork_blocks_db: open_db::<ForksBlocksV10Datas>(db_path, "fork_blocks.db")
fork_blocks_db: open_free_struct_db::<ForksBlocksV10Datas>(db_path, "fork_blocks.db")
.expect("Fail to open ForkForksBlocksV10DatassV10DB"),
orphan_blocks_db: open_db::<OrphanBlocksV10Datas>(db_path, "orphan_blocks.db")
orphan_blocks_db: open_free_struct_db::<OrphanBlocksV10Datas>(
db_path,
"orphan_blocks.db",
)
.expect("Fail to open OrphanBlocksV10Datas"),
}
}
......@@ -225,24 +168,26 @@ impl ForksDBs {
/// Set of databases storing web of trust information
pub struct WotsV10DBs {
/// Store wot graph
pub wot_db: BinDB<WotDB>,
pub wot_db: BinFreeStructDb<WotDB>,
/// Store idrntities
pub identities_db: BinDB<IdentitiesV10Datas>,
pub identities_db: BinFreeStructDb<IdentitiesV10Datas>,
/// Store memberships created_block_id (Use only to detect expirations)
pub ms_db: BinDB<MsExpirV10Datas>,
pub ms_db: BinFreeStructDb<MsExpirV10Datas>,
/// Store certifications created_block_id (Use only to detect expirations)
pub certs_db: BinDB<CertsExpirV10Datas>,
pub certs_db: BinFreeStructDb<CertsExpirV10Datas>,
}
impl WotsV10DBs {
/// Open wot databases from their respective files
pub fn open(db_path: Option<&PathBuf>) -> WotsV10DBs {
WotsV10DBs {
wot_db: open_db::<RustyWebOfTrust>(db_path, "wot.db").expect("Fail to open WotDB"),
identities_db: open_db::<IdentitiesV10Datas>(db_path, "identities.db")
wot_db: open_free_struct_db::<RustyWebOfTrust>(db_path, "wot.db")
.expect("Fail to open WotDB"),
identities_db: open_free_struct_db::<IdentitiesV10Datas>(db_path, "identities.db")
.expect("Fail to open IdentitiesV10DB"),
ms_db: open_db::<MsExpirV10Datas>(db_path, "ms.db").expect("Fail to open MsExpirV10DB"),
certs_db: open_db::<CertsExpirV10Datas>(db_path, "certs.db")
ms_db: open_free_struct_db::<MsExpirV10Datas>(db_path, "ms.db")
.expect("Fail to open MsExpirV10DB"),
certs_db: open_free_struct_db::<CertsExpirV10Datas>(db_path, "certs.db")
.expect("Fail to open CertsExpirV10DB"),
}
}
......@@ -272,25 +217,26 @@ impl WotsV10DBs {
/// Set of databases storing currency information
pub struct CurrencyV10DBs {
/// Store all UD sources
pub du_db: BinDB<UDsV10Datas>,
pub du_db: BinFreeStructDb<UDsV10Datas>,
/// Store all Transactions
pub tx_db: BinDB<TxV10Datas>,
pub tx_db: BinFreeStructDb<TxV10Datas>,
/// Store all UTXOs
pub utxos_db: BinDB<UTXOsV10Datas>,
pub utxos_db: BinFreeStructDb<UTXOsV10Datas>,
/// Store balances of all address (and theirs UTXOs indexs)
pub balances_db: BinDB<BalancesV10Datas>,
pub balances_db: BinFreeStructDb<BalancesV10Datas>,
}
impl CurrencyV10DBs {
/// Open currency databases from their respective files
pub fn open(db_path: Option<&PathBuf>) -> CurrencyV10DBs {
CurrencyV10DBs {
du_db: open_db::<UDsV10Datas>(db_path, "du.db").expect("Fail to open UDsV10DB"),
tx_db: open_db::<TxV10Datas>(db_path, "tx.db")
du_db: open_free_struct_db::<UDsV10Datas>(db_path, "du.db")
.expect("Fail to open UDsV10DB"),
tx_db: open_free_struct_db::<TxV10Datas>(db_path, "tx.db")
.unwrap_or_else(|_| fatal_error!("Fail to open TxV10DB")),
utxos_db: open_db::<UTXOsV10Datas>(db_path, "sources.db")
utxos_db: open_free_struct_db::<UTXOsV10Datas>(db_path, "sources.db")
.expect("Fail to open UTXOsV10DB"),
balances_db: open_db::<BalancesV10Datas>(db_path, "balances.db")
balances_db: open_free_struct_db::<BalancesV10Datas>(db_path, "balances.db")
.expect("Fail to open BalancesV10DB"),
}
}
......@@ -316,36 +262,6 @@ impl CurrencyV10DBs {
}
}
#[derive(Debug, Deserialize, Copy, Clone, PartialEq, Eq, Hash, Serialize)]
/// Data Access Layer Error
pub enum DALError {
/// Error in write operation
WriteError,
/// Error in read operation
ReadError,
/// A database is corrupted, you have to reset the data completely
DBCorrupted,
/// Error with the file system
FileSystemError,
/// Capturing a panic signal during a write operation
WritePanic,
/// Unknown error
UnknowError,
}
impl From<RustbreakError> for DALError {
fn from(rust_break_error: RustbreakError) -> DALError {
match rust_break_error.kind() {
RustbreakErrorKind::Serialization => DALError::WriteError,
RustbreakErrorKind::Deserialization => DALError::ReadError,
RustbreakErrorKind::Poison => DALError::DBCorrupted,
RustbreakErrorKind::Backend => DALError::FileSystemError,
RustbreakErrorKind::WritePanic => DALError::WritePanic,
_ => DALError::UnknowError,
}
}
}
/*#[derive(Debug, Clone)]
pub struct WotStats {
pub block_number: u32,
......@@ -359,52 +275,3 @@ pub struct WotStats {
pub average_centrality: usize,
pub centralities: Vec<u64>,
}*/
/// Open Rustbreak database
pub fn open_db<D: Serialize + DeserializeOwned + Debug + Default + Clone + Send>(
dbs_folder_path: Option<&PathBuf>,
db_file_name: &str,
) -> Result<BinDB<D>, DALError> {
if let Some(dbs_folder_path) = dbs_folder_path {
Ok(BinDB::File(open_file_db::<D>(
dbs_folder_path,
db_file_name,
)?))
} else {
Ok(BinDB::Mem(open_memory_db::<D>()?))
}
}
/// Open Rustbreak memory database
pub fn open_memory_db<D: Serialize + DeserializeOwned + Debug + Default + Clone + Send>(
) -> Result<MemoryDatabase<D, Bincode>, DALError> {
let backend = MemoryBackend::new();
let db = MemoryDatabase::<D, Bincode>::from_parts(D::default(), backend, Bincode);
Ok(db)
}
/// Open Rustbreak file database
pub fn open_file_db<D: Serialize + DeserializeOwned + Debug + Default + Clone + Send>(
dbs_folder_path: &PathBuf,
db_file_name: &str,
) -> Result<FileDatabase<D, Bincode>, DALError> {
let mut db_path = dbs_folder_path.clone();
db_path.push(db_file_name);
let file_path = db_path.as_path();
if file_path.exists()
&& fs::metadata(file_path)
.expect("fail to get file size")
.len()
> 0
{
let backend = FileBackend::open(db_path.as_path())?;
let db = FileDatabase::<D, Bincode>::from_parts(D::default(), backend, Bincode);
db.load()?;
Ok(db)
} else {
Ok(FileDatabase::<D, Bincode>::from_path(
db_path.as_path(),
D::default(),
)?)
}
}
......@@ -18,7 +18,7 @@ use crate::*;
/// Get address balance
pub fn get_address_balance(
balances_db: &BinDB<BalancesV10Datas>,
balances_db: &BinFreeStructDb<BalancesV10Datas>,
address: &UTXOConditionsGroup,
) -> Result<Option<SourceAmount>, DALError> {
Ok(balances_db.read(|db| {
......
......@@ -21,36 +21,22 @@ use dup_crypto::keys::*;
use std::collections::HashMap;
use unwrap::unwrap;
/// get current blockstamp
pub fn get_current_blockstamp(blocks_db: &BlocksV10DBs) -> Result<Option<Blockstamp>, DALError> {
Ok(blocks_db.blockchain_db.read(|db| {
let blockchain_len = db.len() as u32;
if blockchain_len == 0 {
None
} else if let Some(dal_block) = db.get(&BlockNumber(blockchain_len - 1)) {
Some(dal_block.blockstamp())
} else {
None
}
})?)
}
/// Get block hash
pub fn get_block_hash(
db: &BinDB<LocalBlockchainV10Datas>,
bc_backend: &LocalBcDbV10,
block_number: BlockNumber,
) -> Result<Option<BlockHash>, DALError> {
Ok(db.read(|db| {
if let Some(dal_block) = db.get(&block_number) {
dal_block.block.hash()
Ok(
if let Some(block) = get_block_in_local_blockchain(bc_backend, block_number)? {
block.hash()
} else {
None
}
})?)
},
)
}
/// Return true if the node already knows this block
pub fn already_have_block(
blockchain_db: &BinDB<LocalBlockchainV10Datas>,
blockchain_db: &LocalBcDbV10,
forks_dbs: &ForksDBs,
blockstamp: Blockstamp,
previous_hash: Option<Hash>,
......@@ -84,14 +70,7 @@ pub fn already_have_block(
}
}
} else {
return Ok(blockchain_db.read(|db| {
if let Some(dal_block) = db.get(&blockstamp.id) {
if dal_block.block.hash().unwrap_or_default() == blockstamp.hash {
return true;
}
}
false
})?);
return Ok(get_block_in_local_blockchain(blockchain_db, blockstamp.id)?.is_some());
}
Ok(false)
......@@ -99,76 +78,110 @@ pub fn already_have_block(
/// Get block
pub fn get_block(
blockchain_db: &BinDB<LocalBlockchainV10Datas>,
forks_blocks_db: Option<&BinDB<ForksBlocksV10Datas>>,
blockchain_db: &LocalBcDbV10,
forks_blocks_db: Option<&BinFreeStructDb<ForksBlocksV10Datas>>,
blockstamp: &Blockstamp,
) -> Result<Option<DALBlock>, DALError> {
let dal_block = blockchain_db.read(|db| db.get(&blockstamp.id).cloned())?;
if dal_block.is_none() && forks_blocks_db.is_some() {
let opt_dal_block = get_dal_block_in_local_blockchain(blockchain_db, blockstamp.id)?;
if opt_dal_block.is_none() && forks_blocks_db.is_some() {
Ok(forks_blocks_db
.expect("safe unwrap")
.read(|db| db.get(&blockstamp).cloned())?)
} else {
Ok(dal_block)
Ok(opt_dal_block)
}
}
/// Get block in local blockchain
#[inline]
pub fn get_block_in_local_blockchain(
db: &BinDB<LocalBlockchainV10Datas>,
block_id: BlockNumber,
db: &LocalBcDbV10,
block_number: BlockNumber,
) -> Result<Option<BlockDocument>, DALError> {
Ok(db.read(|db| {
if let Some(dal_block) = db.get(&block_id) {
Some(dal_block.block.clone())
} else {
None
Ok(get_dal_block_in_local_blockchain(db, block_number)?.map(|dal_block| dal_block.block))
}
/// Get block in local blockchain
pub fn get_dal_block_in_local_blockchain(
local_bc_db: &LocalBcDbV10,
block_number: BlockNumber,
) -> Result<Option<DALBlock>, DALError> {
local_bc_db.read(|r| local_bc_db.get(&r, block_number.0))
/*Ok(match bc_backend {
LocalBcDbV10::File { db, store } => {
db.read(|reader| to_dal_block(store.get(reader, block_number.0)?))?
}
})?)
LocalBcDbV10::Mem(bc) => bc.get(&block_number).cloned(),
})*/
}
/// Get several blocks in local blockchain
#[inline]
pub fn get_blocks_in_local_blockchain(
db: &BinDB<LocalBlockchainV10Datas>,
bc_db: &LocalBcDbV10,
first_block_number: BlockNumber,
count: u32,
mut count: u32,
) -> Result<Vec<BlockDocument>, DALError> {
Ok(db.read(|db| {
bc_db.read(|r| {
let mut blocks = Vec::with_capacity(count as usize);
let mut current_block_number = first_block_number;
while let Some(dal_block) = db.get(&current_block_number) {
while let Some(dal_block) = bc_db.get(&r, current_block_number.0)? {
blocks.push(dal_block.block);
count -= 1;
if count > 0 {
current_block_number = BlockNumber(current_block_number.0 + 1);
} else {
return Ok(blocks);
}
}
Ok(blocks)
})
/*match bc_backend {
LocalBcDbV10::File { db, store } => {
while let Some(dal_block) =
db.read(|reader| to_dal_block(store.get(reader, current_block_number.0)?))?
{
blocks.push(dal_block.block);
count -= 1;
if count > 0 {
current_block_number = BlockNumber(current_block_number.0 + 1);
} else {
return Ok(blocks);
}
}
}
LocalBcDbV10::Mem(bc) => {
while let Some(dal_block) = bc.get(&current_block_number) {
blocks.push(dal_block.block.clone());
current_block_number = BlockNumber(current_block_number.0 + 1);
}
blocks
})?)
}
}*/
}
/// Get current frame of calculating members
pub fn get_current_frame(
current_block: &DALBlock,
db: &BinDB<LocalBlockchainV10Datas>,
db: &LocalBcDbV10,
) -> Result<HashMap<PubKey, usize>, DALError> {
let frame_begin =
current_block.block.number().0 - current_block.block.current_frame_size() as u32;
Ok(db.read(|db| {
let blocks = get_blocks_in_local_blockchain(
db,
BlockNumber(frame_begin),
current_block.block.current_frame_size() as u32,
)?;
let mut current_frame: HashMap<PubKey, usize> = HashMap::new();
for block_number in frame_begin..current_block.block.number().0 {
let issuer = db
.get(&BlockNumber(block_number))
.unwrap_or_else(|| fatal_error!("Fail to get block #{} !", block_number))
.block
.issuers()[0];
let issuer_count_blocks = if let Some(issuer_count_blocks) = current_frame.get(&issuer)
{
for block in blocks {
let issuer = block.issuers()[0];
let issuer_count_blocks = if let Some(issuer_count_blocks) = current_frame.get(&issuer) {
issuer_count_blocks + 1
} else {
1
};
current_frame.insert(issuer, issuer_count_blocks);
}
current_frame
})?)
Ok(current_frame)
}
......@@ -13,14 +13,14 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
use crate::{BinDB, CertsExpirV10Datas, DALError};
use crate::{BinFreeStructDb, CertsExpirV10Datas, DALError};
use dubp_common_doc::BlockNumber;
use durs_wot::NodeId;
use std::collections::HashMap;
/// Find certifications that emitted in indicated blocks expiring
pub fn find_expire_certs(
certs_db: &BinDB<CertsExpirV10Datas>,
certs_db: &BinFreeStructDb<CertsExpirV10Datas>,
blocks_expiring: Vec<BlockNumber>,
) -> Result<HashMap<(NodeId, NodeId), BlockNumber>, DALError> {
Ok(certs_db.read(|db| {
......
......@@ -16,6 +16,13 @@
use crate::*;
use dubp_common_doc::Blockstamp;
/// get current blockstamp
pub fn get_current_blockstamp(forks_dbs: &ForksDBs) -> Result<Option<Blockstamp>, DALError> {
Ok(forks_dbs
.fork_tree_db
.read(|fork_tree| fork_tree.get_current_blockstamp())?)
}
/// Get stackables blocks
pub fn get_stackables_blocks(
forks_dbs: &ForksDBs,
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment