rollblock 0.4.1

A super-fast, block-oriented and rollbackable key-value store.
Documentation
use std::collections::HashMap;

use crate::error::StoreResult;
use crate::types::{
    BlockDelta, BlockId, BlockUndo, Operation, ShardDelta, ShardOp, ShardUndo, StoreKey as Key,
};

pub(crate) fn plan_replay_delta(
    block_height: BlockId,
    operations: &[Operation],
    undo: &BlockUndo,
    mut shard_for_key: impl FnMut(&Key) -> StoreResult<usize>,
) -> StoreResult<Option<BlockDelta>> {
    if operations.is_empty() {
        return Ok(None);
    }

    let mut shard_deltas: HashMap<usize, ShardDelta> = HashMap::new();
    for op in operations {
        let shard_index = shard_for_key(&op.key)?;
        let delta = shard_deltas
            .entry(shard_index)
            .or_insert_with(|| ShardDelta {
                shard_index,
                operations: Vec::new(),
                undo_entries: Vec::new(),
            });

        delta.operations.push(ShardOp {
            key: op.key,
            value: op.value.clone(),
        });
    }

    if !undo.shard_undos.is_empty() {
        let mut undo_lookup: HashMap<usize, &ShardUndo> = HashMap::new();
        for shard_undo in &undo.shard_undos {
            undo_lookup.insert(shard_undo.shard_index, shard_undo);
        }

        for delta in shard_deltas.values_mut() {
            if let Some(shard_undo) = undo_lookup.get(&delta.shard_index) {
                delta.undo_entries = shard_undo.entries.clone();
            }
        }
    }

    let mut shards: Vec<ShardDelta> = shard_deltas.into_values().collect();
    shards.sort_by_key(|delta| delta.shard_index);

    if shards.is_empty() {
        return Ok(None);
    }

    Ok(Some(BlockDelta {
        block_height,
        shards,
    }))
}