#[cfg(all(feature = "std", zstd_any))]
use crate::CompressionType;
use crate::{UserValue, key::InternalKey};
pub(crate) struct Separated {
pub(crate) key: InternalKey,
pub(crate) size: u32,
pub(crate) class: u8,
}
#[cfg(all(feature = "std", zstd_any))]
mod workers {
use super::{CompressionType, Separated, UserValue};
use crate::table::writer::{
ParallelCompression,
ordered_pipeline::{OrderedJob, OrderedPipeline},
};
use alloc::collections::VecDeque;
const WORKERS: usize = 1;
const IN_FLIGHT: usize = 64;
struct ValueJob(UserValue);
struct ValueCodec {
compression: CompressionType,
two_pass_seed: bool,
}
impl OrderedJob for ValueJob {
type Context = ValueCodec;
type Output = crate::Result<Vec<u8>>;
fn run(self, codec: &ValueCodec) -> Self::Output {
crate::vlog::blob_file::writer::encode_value(
codec.compression,
None,
codec.two_pass_seed,
&self.0,
)
.map(alloc::borrow::Cow::into_owned)
}
}
pub(crate) struct ValueEncoder {
pipeline: OrderedPipeline<ValueJob>,
waiting: VecDeque<Separated>,
}
impl ValueEncoder {
pub(crate) fn for_flush(
parallel: Option<ParallelCompression>,
compression: CompressionType,
two_pass_seed: bool,
) -> Option<Self> {
if !matches!(compression, CompressionType::Zstd(_)) {
return None;
}
Some(Self {
pipeline: OrderedPipeline::new(
parallel?.spawner,
ValueCodec {
compression,
two_pass_seed,
},
WORKERS,
IN_FLIGHT,
),
waiting: VecDeque::with_capacity(IN_FLIGHT),
})
}
pub(crate) fn is_full(&self) -> bool {
self.waiting.len() >= IN_FLIGHT
}
pub(crate) fn submit(&mut self, separated: Separated, value: UserValue) {
self.waiting.push_back(separated);
self.pipeline.submit(ValueJob(value));
}
pub(crate) fn take(&mut self) -> Option<crate::Result<(Separated, Vec<u8>)>> {
let separated = self.waiting.pop_front()?;
let encoded = self.pipeline.take_next()?;
Some(encoded.map(|encoded| (separated, encoded)))
}
}
}
#[cfg(all(feature = "std", zstd_any))]
pub(crate) use workers::ValueEncoder;
#[cfg(not(all(feature = "std", zstd_any)))]
pub(crate) struct ValueEncoder;
#[cfg(not(all(feature = "std", zstd_any)))]
#[expect(
clippy::unused_self,
clippy::needless_pass_by_ref_mut,
reason = "the signatures of the real encoder"
)]
impl ValueEncoder {
pub(crate) fn is_full(&self) -> bool {
false
}
pub(crate) fn submit(&mut self, _: Separated, _: UserValue) {}
pub(crate) fn take(&mut self) -> Option<crate::Result<(Separated, alloc::vec::Vec<u8>)>> {
None
}
}