use crate::ActorDowncast;
use bitfield::BitField;
use cid::Cid;
use clock::ChainEpoch;
use fil_types::deadlines::QuantSpec;
use ipld_amt::{Amt, Error as AmtError};
use ipld_blockstore::BlockStore;
use std::collections::HashMap;
use std::error::Error as StdError;
pub struct BitFieldQueue<'db, BS> {
pub amt: Amt<'db, BitField, BS>,
quant: QuantSpec,
}
impl<'db, BS: BlockStore> BitFieldQueue<'db, BS> {
pub fn new(store: &'db BS, root: &Cid, quant: QuantSpec) -> Result<Self, AmtError> {
Ok(Self {
amt: Amt::load(root, store)?,
quant,
})
}
pub fn add_to_queue(
&mut self,
raw_epoch: ChainEpoch,
values: &BitField,
) -> Result<(), Box<dyn StdError>> {
if values.is_empty() {
return Ok(());
}
let epoch = self.quant.quantize_up(raw_epoch);
let bitfield = self
.amt
.get(epoch as usize)
.map_err(|e| e.downcast_wrap(format!("failed to lookup queue epoch {}", epoch)))?
.cloned()
.unwrap_or_default();
self.amt
.set(epoch as usize, &bitfield | values)
.map_err(|e| e.downcast_wrap(format!("failed to set queue epoch {}", epoch)))?;
Ok(())
}
pub fn add_to_queue_values(
&mut self,
epoch: ChainEpoch,
values: &[usize],
) -> Result<(), Box<dyn StdError>> {
if values.is_empty() {
Ok(())
} else {
self.add_to_queue(epoch, &values.iter().copied().collect())
}
}
pub fn cut(&mut self, to_cut: &BitField) -> Result<(), Box<dyn StdError>> {
let mut epochs_to_remove = Vec::<usize>::new();
self.amt
.for_each_mut(|epoch, bitfield| {
let bf = bitfield.cut(to_cut);
if bf.is_empty() {
epochs_to_remove.push(epoch);
} else {
**bitfield = bf;
}
Ok(())
})
.map_err(|e| e.downcast_wrap("failed to cut from bitfield queue"))?;
self.amt
.batch_delete(epochs_to_remove, true)
.map_err(|e| e.downcast_wrap("failed to remove empty epochs from bitfield queue"))?;
Ok(())
}
pub fn add_many_to_queue_values(
&mut self,
values: &HashMap<ChainEpoch, Vec<usize>>,
) -> Result<(), Box<dyn StdError>> {
let mut quantized_values = HashMap::<ChainEpoch, Vec<usize>>::with_capacity(values.len());
for (&raw_epoch, entries) in values {
let epoch = self.quant.quantize_up(raw_epoch);
quantized_values.entry(epoch).or_default().extend(entries);
}
let mut updated_epochs = Vec::with_capacity(quantized_values.len());
for epoch in quantized_values.keys() {
updated_epochs.push(*epoch);
}
updated_epochs.sort_unstable();
for epoch in updated_epochs {
self.add_to_queue_values(epoch, &quantized_values.remove(&epoch).unwrap_or_default())?;
}
Ok(())
}
pub fn pop_until(&mut self, until: ChainEpoch) -> Result<(BitField, bool), Box<dyn StdError>> {
let mut popped_values = BitField::new();
let mut popped_keys = Vec::<usize>::new();
self.amt.for_each_while(|epoch, bitfield| {
if epoch as ChainEpoch > until {
return Ok(false);
}
popped_keys.push(epoch as usize);
popped_values |= bitfield;
Ok(true)
})?;
if popped_keys.is_empty() {
return Ok((BitField::new(), false));
}
self.amt.batch_delete(popped_keys, true)?;
Ok((popped_values, true))
}
}