Files
qdrant/lib/wal/src/test_utils.rs
dependabot[bot] a7739dbf2d build(deps): bump rand_distr from 0.5.1 to 0.6.0 (#8148)
* build(deps): bump rand_distr from 0.5.1 to 0.6.0

Bumps [rand_distr](https://github.com/rust-random/rand_distr) from 0.5.1 to 0.6.0.
- [Release notes](https://github.com/rust-random/rand_distr/releases)
- [Changelog](https://github.com/rust-random/rand_distr/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rust-random/rand_distr/compare/0.5.1...0.6.0)

---
updated-dependencies:
- dependency-name: rand_distr
  dependency-version: 0.6.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

* Migrate main code base to rand 0.10

* Migrate tests

* Migrate benches

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: timvisee <tim@visee.me>
2026-03-26 17:09:49 +01:00

144 lines
3.8 KiB
Rust

use std::{env, fmt};
use log::info;
use rand::{self, RngExt, SeedableRng};
use rand_distr::{Distribution, StandardUniform};
use crate::segment;
pub struct EntryGenerator {
seed: usize,
/// Random number generator.
rng: rand::rngs::StdRng,
/// Gamma(shape=1.25, scale=25.6) distribution for generating entry sizes.
/// Produces values with a mean of 32 bytes and a median of 24 bytes. See
/// http://wolfr.am/8r3vGRkZ.
dist: rand_distr::Gamma<f32>,
remaining_size: usize,
}
impl EntryGenerator {
pub fn new() -> EntryGenerator {
EntryGenerator::with_segment_capacity(usize::MAX)
}
pub fn with_seed(seed: usize) -> EntryGenerator {
EntryGenerator::with_seed_and_segment_capacity(seed, usize::MAX)
}
pub fn with_segment_capacity(size: usize) -> EntryGenerator {
let seed: usize = env::var("WAL_TEST_SEED")
.map(|seed| seed.parse::<usize>().unwrap())
.unwrap_or_else(|_| rand::rng().random_range(0..usize::MAX));
EntryGenerator::with_seed_and_segment_capacity(seed, size)
}
pub fn with_seed_and_segment_capacity(seed: usize, size: usize) -> EntryGenerator {
info!("Creating EntryGenerator with seed {seed}");
EntryGenerator {
seed,
rng: rand::rngs::StdRng::seed_from_u64(seed as u64),
dist: rand_distr::Gamma::new(1.25, 25.6).unwrap(),
remaining_size: size.saturating_sub(segment::segment_overhead()),
}
}
pub fn seed(&self) -> usize {
self.seed
}
}
impl Default for EntryGenerator {
fn default() -> Self {
Self::new()
}
}
impl Iterator for EntryGenerator {
type Item = Vec<u8>;
fn next(&mut self) -> Option<Vec<u8>> {
let size = self.dist.sample(&mut self.rng) as usize;
let padded_size = size + segment::entry_overhead(size);
if self.remaining_size >= padded_size {
self.remaining_size -= padded_size;
Some(
StandardUniform
.sample_iter(&mut self.rng)
.take(size)
.collect(),
)
} else {
self.remaining_size = 0;
None
}
}
}
impl fmt::Debug for EntryGenerator {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"EntryGenerator {{ seed: {}, remaining_size: {} }}",
self.seed, self.remaining_size
)
}
}
#[cfg(test)]
mod test {
use super::EntryGenerator;
use crate::segment;
#[test]
fn entry_generator_distribution() {
let generator = EntryGenerator::new();
let mut sizes: Vec<usize> = generator
.into_iter()
.take(1000)
.map(|entry| entry.len())
.collect();
sizes.sort();
let sum: usize = sizes.iter().sum();
let mean = sum as f64 / sizes.len() as f64;
let median = sizes[sizes.len() / 2];
println!("median: {median}, mean: {mean}");
assert!(median >= 18);
assert!(median <= 30);
assert!(mean >= 26.0);
assert!(mean <= 38.0);
}
#[test]
fn entry_generator_size() {
let generator = EntryGenerator::with_segment_capacity(1023);
let len = generator
.into_iter()
.fold(segment::segment_overhead(), |acc, entry| {
let len = entry.len();
acc + len + segment::entry_overhead(len)
});
assert!(len <= 1023);
}
#[test]
fn test_seed() {
let gen1 = EntryGenerator::with_seed(42);
let gen2 = EntryGenerator::with_seed(42);
assert_eq!(
gen1.into_iter().take(100).collect::<Vec<_>>(),
gen2.into_iter().take(100).collect::<Vec<_>>()
);
}
}