RepairService saves db_iterator instead of reconstructing on every search (#4242)
This commit is contained in:
@ -182,16 +182,10 @@ impl Blocktree {
|
|||||||
self.orphans_cf.get(slot)
|
self.orphans_cf.get(slot)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_next_slot(&self, slot: u64) -> Result<Option<u64>> {
|
pub fn slot_meta_iterator(&self, slot: u64) -> Result<Cursor<cf::SlotMeta>> {
|
||||||
let mut db_iterator = self.db.cursor::<cf::SlotMeta>()?;
|
let mut db_iterator = self.db.cursor::<cf::SlotMeta>()?;
|
||||||
|
db_iterator.seek(slot);
|
||||||
db_iterator.seek(slot + 1);
|
Ok(db_iterator)
|
||||||
if !db_iterator.valid() {
|
|
||||||
Ok(None)
|
|
||||||
} else {
|
|
||||||
let next_slot = db_iterator.key().expect("Expected valid key");
|
|
||||||
Ok(Some(next_slot))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn write_shared_blobs<I>(&self, shared_blobs: I) -> Result<()>
|
pub fn write_shared_blobs<I>(&self, shared_blobs: I) -> Result<()>
|
||||||
|
@ -179,6 +179,7 @@ impl RepairService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Generate repairs for all slots `x` in the repair_range.start <= x <= repair_range.end
|
||||||
fn generate_repairs_in_range(
|
fn generate_repairs_in_range(
|
||||||
blocktree: &Blocktree,
|
blocktree: &Blocktree,
|
||||||
max_repairs: usize,
|
max_repairs: usize,
|
||||||
@ -187,8 +188,11 @@ impl RepairService {
|
|||||||
) -> Result<(Vec<RepairType>)> {
|
) -> Result<(Vec<RepairType>)> {
|
||||||
// Slot height and blob indexes for blobs we want to repair
|
// Slot height and blob indexes for blobs we want to repair
|
||||||
let mut repairs: Vec<RepairType> = vec![];
|
let mut repairs: Vec<RepairType> = vec![];
|
||||||
let mut current_slot = Some(repair_range.start);
|
let mut meta_iter = blocktree
|
||||||
while repairs.len() < max_repairs && current_slot.is_some() {
|
.slot_meta_iterator(repair_range.start)
|
||||||
|
.expect("Couldn't get db iterator");
|
||||||
|
while repairs.len() < max_repairs && meta_iter.valid() {
|
||||||
|
let current_slot = meta_iter.key();
|
||||||
if current_slot.unwrap() > repair_range.end {
|
if current_slot.unwrap() > repair_range.end {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -198,7 +202,7 @@ impl RepairService {
|
|||||||
repair_info.max_slot = current_slot.unwrap();
|
repair_info.max_slot = current_slot.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(slot) = blocktree.meta(current_slot.unwrap())? {
|
if let Some(slot) = meta_iter.value() {
|
||||||
let new_repairs = Self::generate_repairs_for_slot(
|
let new_repairs = Self::generate_repairs_for_slot(
|
||||||
blocktree,
|
blocktree,
|
||||||
current_slot.unwrap(),
|
current_slot.unwrap(),
|
||||||
@ -207,7 +211,7 @@ impl RepairService {
|
|||||||
);
|
);
|
||||||
repairs.extend(new_repairs);
|
repairs.extend(new_repairs);
|
||||||
}
|
}
|
||||||
current_slot = blocktree.get_next_slot(current_slot.unwrap())?;
|
meta_iter.next();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only increment repair_tries if the ledger contains every blob for every slot
|
// Only increment repair_tries if the ledger contains every blob for every slot
|
||||||
@ -321,7 +325,9 @@ impl Service for RepairService {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::blocktree::tests::{make_many_slot_entries, make_slot_entries};
|
use crate::blocktree::tests::{
|
||||||
|
make_chaining_slot_entries, make_many_slot_entries, make_slot_entries,
|
||||||
|
};
|
||||||
use crate::blocktree::{get_tmp_ledger_path, Blocktree};
|
use crate::blocktree::{get_tmp_ledger_path, Blocktree};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -442,6 +448,50 @@ mod test {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
pub fn test_repair_range() {
|
pub fn test_repair_range() {
|
||||||
|
let blocktree_path = get_tmp_ledger_path!();
|
||||||
|
{
|
||||||
|
let blocktree = Blocktree::open(&blocktree_path).unwrap();
|
||||||
|
|
||||||
|
let mut repair_info = RepairInfo::new();
|
||||||
|
|
||||||
|
let slots: Vec<u64> = vec![1, 3, 5, 7, 8];
|
||||||
|
let num_entries_per_slot = 10;
|
||||||
|
|
||||||
|
let blobs = make_chaining_slot_entries(&slots, num_entries_per_slot);
|
||||||
|
for (slot_blobs, _) in blobs.iter() {
|
||||||
|
blocktree.write_blobs(&slot_blobs[1..]).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Iterate through all possible combinations of start..end (inclusive on both
|
||||||
|
// sides of the range)
|
||||||
|
for start in 0..slots.len() {
|
||||||
|
for end in start..slots.len() {
|
||||||
|
let mut repair_slot_range = RepairSlotRange::default();
|
||||||
|
repair_slot_range.start = slots[start];
|
||||||
|
repair_slot_range.end = slots[end];
|
||||||
|
let expected: Vec<RepairType> = slots[start..end + 1]
|
||||||
|
.iter()
|
||||||
|
.map(|slot_index| RepairType::Blob(*slot_index, 0))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
RepairService::generate_repairs_in_range(
|
||||||
|
&blocktree,
|
||||||
|
std::usize::MAX,
|
||||||
|
&mut repair_info,
|
||||||
|
&repair_slot_range
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
expected
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Blocktree::destroy(&blocktree_path).expect("Expected successful database destruction");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
pub fn test_repair_range_highest() {
|
||||||
let blocktree_path = get_tmp_ledger_path!();
|
let blocktree_path = get_tmp_ledger_path!();
|
||||||
{
|
{
|
||||||
let blocktree = Blocktree::open(&blocktree_path).unwrap();
|
let blocktree = Blocktree::open(&blocktree_path).unwrap();
|
||||||
@ -452,6 +502,7 @@ mod test {
|
|||||||
|
|
||||||
let num_slots = 1;
|
let num_slots = 1;
|
||||||
let start = 5;
|
let start = 5;
|
||||||
|
|
||||||
// Create some blobs in slots 0..num_slots
|
// Create some blobs in slots 0..num_slots
|
||||||
for i in start..start + num_slots {
|
for i in start..start + num_slots {
|
||||||
let parent = if i > 0 { i - 1 } else { 0 };
|
let parent = if i > 0 { i - 1 } else { 0 };
|
||||||
|
Reference in New Issue
Block a user