rostrum 8.0.0

An efficient implementation of Electrum Server with token support
Documentation
use std::sync::{Mutex, MutexGuard};

use rayon::prelude::*;

use crate::{
    indexes::{
        cashaccount::TxCashAccountRow, headerindex::HeaderRow, heightindex::HeightIndexRow,
        inputindex::InputIndexRow, outputindex::OutputIndexRow,
        outputtokenindex::OutputTokenIndexRow, scripthashindex::ScriptHashIndexRow,
        tokenoutputindex::TokenOutputIndexRow, DBRow,
    },
    store::{Row, COLUMN_FAMILIES, META_CF},
};

/**
 * For collecting multiple database entries and batch writing them in one transaction.
 */
pub struct WriteBatch {
    metadata: Mutex<Vec<Row>>,
    cashaccount: Mutex<Vec<Row>>,
    header: Mutex<Vec<Row>>,
    height: Mutex<Vec<Row>>,
    input: Mutex<Vec<Row>>,
    output: Mutex<Vec<Row>>,
    output_token: Mutex<Vec<Row>>,
    scripthash: Mutex<Vec<Row>>,
    token_output: Mutex<Vec<Row>>,
}

impl WriteBatch {
    pub fn new() -> Self {
        WriteBatch {
            metadata: Default::default(),
            cashaccount: Default::default(),
            header: Default::default(),
            height: Default::default(),
            input: Default::default(),
            output: Default::default(),
            output_token: Default::default(),
            scripthash: Default::default(),
            token_output: Default::default(),
        }
    }

    pub fn cf_to_vec_tuples<'a>(&'a self) -> Vec<(&'static str, &'a Mutex<Vec<Row>>)> {
        let map = vec![
            (META_CF, &self.metadata),
            (TxCashAccountRow::CF, &self.cashaccount),
            (HeaderRow::CF, &self.header),
            (HeightIndexRow::CF, &self.height),
            (InputIndexRow::CF, &self.input),
            (OutputIndexRow::CF, &self.output),
            (OutputTokenIndexRow::CF, &self.output_token),
            (ScriptHashIndexRow::CF, &self.scripthash),
            (TokenOutputIndexRow::CF, &self.token_output),
        ];
        debug_assert!(map.len() == COLUMN_FAMILIES.len());
        map
    }

    pub fn insert<I: IntoParallelIterator<Item = Row>>(&self, cf_name: &str, rows: I) {
        let mut rows: Vec<Row> = rows.into_par_iter().collect();

        let mut locked = match cf_name {
            META_CF => self.metadata.lock().unwrap(),
            TxCashAccountRow::CF => self.cashaccount.lock().unwrap(),
            HeaderRow::CF => self.header.lock().unwrap(),
            HeightIndexRow::CF => self.height.lock().unwrap(),
            InputIndexRow::CF => self.input.lock().unwrap(),
            OutputIndexRow::CF => self.output.lock().unwrap(),
            OutputTokenIndexRow::CF => self.output_token.lock().unwrap(),
            ScriptHashIndexRow::CF => self.scripthash.lock().unwrap(),
            TokenOutputIndexRow::CF => self.token_output.lock().unwrap(),
            _ => todo!("unknown cf family {cf_name}"),
        };
        locked.append(&mut rows);
    }

    /**
     * How many entries are in the current batch.
     */
    pub fn len(&self) -> usize {
        let locks: Vec<MutexGuard<Vec<Row>>> = self
            .cf_to_vec_tuples()
            .into_iter()
            .map(|(_, column)| column.lock().unwrap())
            .collect();
        locks.iter().map(|rows| rows.len()).sum()
    }
    /**
     * No entires in writebatch
     */
    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }
}

impl Default for WriteBatch {
    fn default() -> Self {
        Self::new()
    }
}