Optimizations for txhashset rewind ()

This commit is contained in:
Gary Yu 2018-09-15 07:51:36 +08:00 committed by Ignotus Peverell
parent d3a5ee130f
commit 26244ef9dd
3 changed files with 96 additions and 13 deletions

View file

@ -140,6 +140,13 @@ impl ChainStore {
}
}
pub fn get_hash_by_height(&self, height: u64) -> Result<Hash, Error> {
option_to_not_found(
self.db.get_ser(&u64_to_key(HEADER_HEIGHT_PREFIX, height)),
&format!("Hash at height: {}", height),
)
}
pub fn get_header_by_height(&self, height: u64) -> Result<BlockHeader, Error> {
option_to_not_found(
self.db.get_ser(&u64_to_key(HEADER_HEIGHT_PREFIX, height)),

View file

@ -1214,8 +1214,8 @@ fn input_pos_to_rewind(
head_header: &BlockHeader,
batch: &Batch,
) -> Result<Bitmap, Error> {
let mut bitmap = Bitmap::create();
let mut current = head_header.hash();
let mut height = head_header.height;
if head_header.height < block_header.height {
debug!(
@ -1224,27 +1224,42 @@ fn input_pos_to_rewind(
head_header.height,
block_header.height
);
return Ok(bitmap);
return Ok(Bitmap::create());
}
//
// TODO - rework this loop to use Bitmap::fast_or() on a vec of bitmaps.
//
loop {
if current == block_header.hash() {
break;
// Batching up the block input bitmaps, and running fast_or() on every batch of 256 bitmaps.
// so to avoid maintaining a huge vec of bitmaps.
let bitmap_fast_or = |b_res, block_input_bitmaps: &mut Vec<Bitmap>| -> Option<Bitmap> {
if let Some(b) = b_res {
block_input_bitmaps.push(b);
if block_input_bitmaps.len() < 256 {
return None;
}
}
let bitmap = Bitmap::fast_or(&block_input_bitmaps.iter().collect::<Vec<&Bitmap>>());
block_input_bitmaps.clear();
block_input_bitmaps.push(bitmap.clone());
Some(bitmap)
};
let mut block_input_bitmaps: Vec<Bitmap> = vec![];
let bh = block_header.hash();
while current != bh {
// We cache recent block headers and block_input_bitmaps
// internally in our db layer (commit_index).
// I/O should be minimized or eliminated here for most
// rewind scenarios.
let current_header = commit_index.get_block_header(&current)?;
let input_bitmap_res = batch.get_block_input_bitmap(&current);
if let Ok(b) = input_bitmap_res {
bitmap.or_inplace(&b);
if let Ok(b_res) = batch.get_block_input_bitmap(&current) {
bitmap_fast_or(Some(b_res), &mut block_input_bitmaps);
}
current = current_header.previous;
if height == 0 {
break;
}
height -= 1;
current = commit_index.get_hash_by_height(height)?;
}
let bitmap = bitmap_fast_or(None, &mut block_input_bitmaps).unwrap();
Ok(bitmap)
}

View file

@ -12,9 +12,11 @@
// See the License for the specific language governing permissions and
// limitations under the License.
extern crate chrono;
extern crate croaring;
extern crate rand;
use chrono::prelude::Utc;
use croaring::Bitmap;
use rand::Rng;
@ -97,3 +99,62 @@ fn test_a_big_bitmap() {
let serialized_buffer = bitmap.serialize();
assert_eq!(serialized_buffer.len(), 230);
}
#[ignore]
#[test]
fn bench_fast_or() {
let nano_to_millis = 1.0 / 1_000_000.0;
let bitmaps_number = 256;
let size_of_each_bitmap = 1_000;
let init_bitmaps = || -> Vec<Bitmap> {
let mut rng = rand::thread_rng();
let mut bitmaps = vec![];
for _ in 0..bitmaps_number {
let mut bitmap = Bitmap::create();
for _ in 0..size_of_each_bitmap {
let n = rng.gen_range(0, 1_000_000);
bitmap.add(n);
}
bitmaps.push(bitmap);
}
bitmaps
};
let mut bitmaps = init_bitmaps();
let mut bitmap = Bitmap::create();
let start = Utc::now().timestamp_nanos();
for _ in 0..bitmaps_number {
bitmap.or_inplace(&bitmaps.pop().unwrap());
}
let fin = Utc::now().timestamp_nanos();
let dur_ms = (fin - start) as f64 * nano_to_millis;
println!(
" or_inplace(): {:9.3?}ms. bitmap cardinality: {}",
dur_ms,
bitmap.cardinality()
);
let bitmaps = init_bitmaps();
let start = Utc::now().timestamp_nanos();
let bitmap = Bitmap::fast_or(&bitmaps.iter().map(|x| x).collect::<Vec<&Bitmap>>());
let fin = Utc::now().timestamp_nanos();
let dur_ms = (fin - start) as f64 * nano_to_millis;
println!(
" fast_or(): {:9.3?}ms. bitmap cardinality: {}",
dur_ms,
bitmap.cardinality()
);
let bitmaps = init_bitmaps();
let start = Utc::now().timestamp_nanos();
let bitmap = Bitmap::fast_or_heap(&bitmaps.iter().map(|x| x).collect::<Vec<&Bitmap>>());
let fin = Utc::now().timestamp_nanos();
let dur_ms = (fin - start) as f64 * nano_to_millis;
println!(
"fast_or_heap(): {:9.3?}ms. bitmap cardinality: {}",
dur_ms,
bitmap.cardinality()
);
}