1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
use std::error::Error;
use std::path::PathBuf;

use crate::account::db_state::DBState;
use crate::database::IDB;
use crate::traits::{Decode, Encode, Exception};

use rocksdb::DB as RocksDB;

use starling::traits::Database;

impl<DBType> Database for StateDB<DBType>
where
    DBType: IDB,
{
    type NodeType = DBState;
    type EntryType = (Vec<u8>, Self::NodeType);

    fn open(_path: &PathBuf) -> Result<StateDB<DBType, Self::EntryType>, Box<Error>> {
        return Err(Box::new(Exception::new(
            "Open the database using new, not open",
        )));
    }

    fn get_node(&self, key: &[u8]) -> Result<Option<Self::NodeType>, Box<Error>> {
        let bytes = self.database._get(&key)?;
        Ok(Some(Self::NodeType::decode(&bytes)?))
    }

    fn insert(&mut self, key: &[u8], value: &Self::NodeType) -> Result<(), Box<Error>> {
        self.pending_inserts.push((key.to_vec(), value.clone()));
        Ok(())
    }

    fn remove(&mut self, key: &[u8]) -> Result<(), Box<Error>> {
        self.database.delete(key)?;
        Ok(())
    }

    fn batch_write(&mut self) -> Result<(), Box<Error>> {
        let mut batch = Vec::with_capacity(self.pending_inserts.len());
        while self.pending_inserts.len() > 0 {
            let entry = self.pending_inserts.remove(0);
            let key = entry.0;
            let value = entry.1;
            batch.push((key, value.encode()?));
        }
        self.database.write_batch(batch)?;
        Ok(())
    }
}

pub struct StateDB<DatabaseType = RocksDB, EntryType = (Vec<u8>, DBState)> {
    database: DatabaseType,
    pending_inserts: Vec<EntryType>,
}

impl<DatabaseType, EntryType, OptionType> StateDB<DatabaseType, EntryType>
where
    DatabaseType: IDB<OptionType = OptionType>,
{
    pub fn new(
        path: PathBuf,
        options: Option<OptionType>,
    ) -> Result<StateDB<DatabaseType, EntryType>, Box<Error>> {
        let database = DatabaseType::open(path, options)?;
        let pending_inserts = Vec::with_capacity(40000);
        Ok(StateDB {
            database,
            pending_inserts,
        })
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::database::mock::RocksDBMock;

    #[test]
    fn it_opens_a_state_db() {
        let path = PathBuf::new();
        let _state_db: StateDB<RocksDBMock> = StateDB::new(path, None).unwrap();
    }
}