// Copyright 2024 RustFS Team // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. use criterion::{BatchSize, BenchmarkId, Criterion, criterion_group, criterion_main}; use rustfs_filemeta::{ErasureAlgo, FileInfo, FileMeta}; use std::hint::black_box; use std::time::Duration; use time::OffsetDateTime; use uuid::Uuid; const VERSION_COUNT_CASES: &[usize] = &[1, 8, 32, 64]; const BENCH_BASE_TIME_UNIX_SECS: i64 = 1_700_000_000; fn make_file_info(version_id: Uuid, data_dir: Uuid, size: i64, mod_time: OffsetDateTime) -> FileInfo { FileInfo { version_id: Some(version_id), data_dir: Some(data_dir), size, mod_time: Some(mod_time), metadata: [("etag".to_string(), format!("etag-{version_id}"))].into_iter().collect(), erasure: rustfs_filemeta::ErasureInfo { algorithm: ErasureAlgo::ReedSolomon.to_string(), data_blocks: 4, parity_blocks: 2, block_size: 1024 * 1024, index: 1, distribution: vec![1, 2, 3, 4, 5, 6], ..Default::default() }, ..Default::default() } } fn build_meta_with_versions(version_count: usize) -> FileMeta { let mut meta = FileMeta::new(); let base_time = OffsetDateTime::from_unix_timestamp(BENCH_BASE_TIME_UNIX_SECS).expect("valid bench base timestamp"); for i in 0..version_count { let fi = make_file_info(Uuid::new_v4(), Uuid::new_v4(), 64 * 1024, base_time - Duration::from_secs(i as u64)); meta.add_version(fi).expect("seed add_version should succeed"); } meta } fn bench_rename_data_meta_path(c: &mut Criterion) { let mut group = c.benchmark_group("rename_data_meta"); group.sample_size(20); group.measurement_time(Duration::from_secs(10)); for &version_count in VERSION_COUNT_CASES { let seeded = build_meta_with_versions(version_count); let dst_buf = seeded.marshal_msg().expect("marshal seeded meta"); let base_time = OffsetDateTime::from_unix_timestamp(BENCH_BASE_TIME_UNIX_SECS).expect("valid bench base timestamp"); let replace_version_id = seeded .versions .first() .and_then(|v| v.header.version_id) .unwrap_or(Uuid::nil()); group.bench_with_input(BenchmarkId::new("read_modify_write", version_count), &version_count, |b, _| { b.iter(|| { let mut xlmeta = FileMeta::load(black_box(&dst_buf)).expect("load dst meta"); let search_version_id = Some(replace_version_id); let has_old_data_dir = xlmeta.find_unshared_data_dir_for_version(search_version_id); if let Some(old_data_dir) = has_old_data_dir { let _ = xlmeta.data.remove_two(replace_version_id, old_data_dir); } let fi = make_file_info(replace_version_id, Uuid::new_v4(), 64 * 1024, base_time + Duration::from_millis(1)); xlmeta.add_version(fi).expect("add new version"); let out = xlmeta.marshal_msg().expect("marshal updated meta"); black_box(out); }); }); let mut prepared = FileMeta::load(&dst_buf).expect("load prepared meta"); if let Some(old_data_dir) = prepared.find_unshared_data_dir_for_version(Some(replace_version_id)) { let _ = prepared.data.remove_two(replace_version_id, old_data_dir); } group.bench_with_input(BenchmarkId::new("add_version_marshal_only", version_count), &version_count, |b, _| { b.iter_batched( || prepared.clone(), |mut xlmeta| { let fi = make_file_info(replace_version_id, Uuid::new_v4(), 64 * 1024, base_time + Duration::from_millis(1)); xlmeta.add_version(fi).expect("add new version"); let out = xlmeta.marshal_msg().expect("marshal updated meta"); black_box(out); }, BatchSize::SmallInput, ); }); group.bench_with_input(BenchmarkId::new("remove_two_only", version_count), &version_count, |b, _| { b.iter(|| { let mut xlmeta = FileMeta::load(black_box(&dst_buf)).expect("load dst meta"); let removed = if let Some(old_data_dir) = xlmeta.find_unshared_data_dir_for_version(Some(replace_version_id)) { xlmeta.data.remove_two(replace_version_id, old_data_dir).expect("remove two") } else { false }; black_box(removed); black_box(xlmeta); }); }); } } criterion_group!(benches, bench_rename_data_meta_path); criterion_main!(benches);