|
| 1 | +// Copyright 2019 Kodebox, Inc. |
| 2 | +// This file is part of CodeChain. |
| 3 | +// |
| 4 | +// This program is free software: you can redistribute it and/or modify |
| 5 | +// it under the terms of the GNU Affero General Public License as |
| 6 | +// published by the Free Software Foundation, either version 3 of the |
| 7 | +// License, or (at your option) any later version. |
| 8 | +// |
| 9 | +// This program is distributed in the hope that it will be useful, |
| 10 | +// but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 11 | +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 12 | +// GNU Affero General Public License for more details. |
| 13 | +// |
| 14 | +// You should have received a copy of the GNU Affero General Public License |
| 15 | +// along with this program. If not, see <https://www.gnu.org/licenses/>. |
| 16 | + |
| 17 | +#![feature(test)] |
| 18 | + |
| 19 | +extern crate codechain_merkle as cmerkle; |
| 20 | +extern crate hashdb; |
| 21 | +extern crate journaldb; |
| 22 | +extern crate kvdb; |
| 23 | +extern crate kvdb_rocksdb as rocksdb; |
| 24 | +extern crate primitives; |
| 25 | +extern crate rand; |
| 26 | +extern crate tempfile; |
| 27 | +extern crate test; |
| 28 | + |
| 29 | +use std::path::Path; |
| 30 | +use std::sync::Arc; |
| 31 | + |
| 32 | +use cmerkle::{Trie, TrieDB, TrieDBMut, TrieMut}; |
| 33 | +use kvdb::DBTransaction; |
| 34 | +use primitives::H256; |
| 35 | +use rand::random; |
| 36 | +use rocksdb::{CompactionProfile, Database, DatabaseConfig}; |
| 37 | +use tempfile::{tempdir, TempDir}; |
| 38 | +use test::Bencher; |
| 39 | + |
| 40 | +struct TestDB { |
| 41 | + _dir: TempDir, |
| 42 | + db: Arc<Database>, |
| 43 | + journal: Box<dyn journaldb::JournalDB>, |
| 44 | + root: H256, |
| 45 | +} |
| 46 | + |
| 47 | +impl TestDB { |
| 48 | + // Replicate CodeChain's db config |
| 49 | + fn config(path: &Path) -> DatabaseConfig { |
| 50 | + let mut config = DatabaseConfig::with_columns(Some(1)); |
| 51 | + config.memory_budget = Default::default(); |
| 52 | + config.compaction = CompactionProfile::auto(path); |
| 53 | + config.wal = true; |
| 54 | + config |
| 55 | + } |
| 56 | + |
| 57 | + fn populate(path: &Path, size: usize) -> H256 { |
| 58 | + // Create database |
| 59 | + let config = Self::config(path); |
| 60 | + let db = Arc::new(Database::open(&config, path.to_str().unwrap()).unwrap()); |
| 61 | + let mut journal = journaldb::new(db.clone(), journaldb::Algorithm::Archive, Some(0)); |
| 62 | + let mut root = H256::new(); |
| 63 | + { |
| 64 | + let hashdb = journal.as_hashdb_mut(); |
| 65 | + let mut trie = TrieDBMut::new(hashdb, &mut root); |
| 66 | + for i in 0..size { |
| 67 | + trie.insert(&i.to_be_bytes(), &i.to_be_bytes()).unwrap(); |
| 68 | + } |
| 69 | + } |
| 70 | + let mut batch = DBTransaction::new(); |
| 71 | + journal.journal_under(&mut batch, 0, &H256::new()).unwrap(); |
| 72 | + db.write_buffered(batch); |
| 73 | + db.flush().unwrap(); |
| 74 | + |
| 75 | + root |
| 76 | + } |
| 77 | + |
| 78 | + fn new(size: usize) -> Self { |
| 79 | + // Create temporary directory |
| 80 | + let dir = tempdir().unwrap(); |
| 81 | + let root = Self::populate(dir.path(), size); |
| 82 | + |
| 83 | + // Create database |
| 84 | + let config = Self::config(dir.path()); |
| 85 | + let db = Arc::new(Database::open(&config, dir.path().to_str().unwrap()).unwrap()); |
| 86 | + let journal = journaldb::new(db.clone(), journaldb::Algorithm::Archive, Some(0)); |
| 87 | + |
| 88 | + Self { |
| 89 | + _dir: dir, |
| 90 | + db, |
| 91 | + journal, |
| 92 | + root, |
| 93 | + } |
| 94 | + } |
| 95 | + |
| 96 | + fn trie(&self) -> TrieDB { |
| 97 | + let hashdb = self.journal.as_hashdb(); |
| 98 | + TrieDB::try_new(hashdb, &self.root).unwrap() |
| 99 | + } |
| 100 | + |
| 101 | + fn trie_mut(&mut self) -> TrieDBMut { |
| 102 | + let hashdb = self.journal.as_hashdb_mut(); |
| 103 | + TrieDBMut::new(hashdb, &mut self.root) |
| 104 | + } |
| 105 | + |
| 106 | + fn flush(&mut self) { |
| 107 | + let mut batch = DBTransaction::new(); |
| 108 | + self.journal.journal_under(&mut batch, 0, &H256::new()).unwrap(); |
| 109 | + self.db.write_buffered(batch); |
| 110 | + self.db.flush().unwrap(); |
| 111 | + } |
| 112 | +} |
| 113 | + |
| 114 | +const DB_SIZE: usize = 10000; |
| 115 | +const BATCH: usize = 10000; |
| 116 | + |
| 117 | +#[bench] |
| 118 | +fn bench_read_single(b: &mut Bencher) { |
| 119 | + let db = TestDB::new(DB_SIZE); |
| 120 | + b.iter(|| { |
| 121 | + let trie = db.trie(); |
| 122 | + let item = random::<usize>() % DB_SIZE; |
| 123 | + let _ = trie.get(&item.to_be_bytes()).unwrap().unwrap(); |
| 124 | + }); |
| 125 | +} |
| 126 | + |
| 127 | +#[bench] |
| 128 | +fn bench_read_multiple(b: &mut Bencher) { |
| 129 | + let db = TestDB::new(DB_SIZE); |
| 130 | + b.iter(|| { |
| 131 | + let trie = db.trie(); |
| 132 | + for _ in 0..BATCH { |
| 133 | + let item = random::<usize>() % DB_SIZE; |
| 134 | + let _ = trie.get(&item.to_be_bytes()).unwrap().unwrap(); |
| 135 | + } |
| 136 | + }); |
| 137 | +} |
| 138 | + |
| 139 | +#[bench] |
| 140 | +fn bench_write_single(b: &mut Bencher) { |
| 141 | + let mut db = TestDB::new(DB_SIZE); |
| 142 | + b.iter(|| { |
| 143 | + let mut trie = db.trie_mut(); |
| 144 | + let item = random::<usize>() % DB_SIZE + DB_SIZE; |
| 145 | + let _ = trie.insert(&item.to_be_bytes(), &item.to_be_bytes()).unwrap(); |
| 146 | + db.flush(); |
| 147 | + }); |
| 148 | +} |
| 149 | + |
| 150 | +#[bench] |
| 151 | +fn bench_write_multiple(b: &mut Bencher) { |
| 152 | + let mut db = TestDB::new(DB_SIZE); |
| 153 | + b.iter(|| { |
| 154 | + let mut trie = db.trie_mut(); |
| 155 | + for _ in 0..BATCH { |
| 156 | + let item = random::<usize>() % DB_SIZE + DB_SIZE; |
| 157 | + let _ = trie.insert(&item.to_be_bytes(), &item.to_be_bytes()).unwrap(); |
| 158 | + } |
| 159 | + db.flush(); |
| 160 | + }); |
| 161 | +} |
0 commit comments