2023-08-02 11:45:30 +00:00
|
|
|
use std::{collections::BTreeMap, iter, sync::Arc};
|
|
|
|
|
|
|
|
use criterion::{
|
|
|
|
criterion_group, criterion_main, measurement::WallTime, BatchSize, BenchmarkGroup, Criterion,
|
|
|
|
Throughput,
|
|
|
|
};
|
|
|
|
use data_types::{
|
|
|
|
partition_template::{NamespacePartitionTemplateOverride, TablePartitionTemplateOverride},
|
|
|
|
ColumnId, ColumnSchema, NamespaceId, NamespaceName, NamespaceSchema, TableId, TableSchema,
|
|
|
|
};
|
|
|
|
use iox_catalog::{interface::Catalog, mem::MemCatalog};
|
|
|
|
use once_cell::sync::Lazy;
|
2023-08-28 16:01:47 +00:00
|
|
|
use router::{
|
2023-08-29 14:24:10 +00:00
|
|
|
gossip::anti_entropy::mst::{actor::AntiEntropyActor, merkle::MerkleTree},
|
2023-08-28 16:01:47 +00:00
|
|
|
namespace_cache::{MemoryNamespaceCache, NamespaceCache, ReadThroughCache, ShardedCache},
|
2023-08-02 11:45:30 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static ARBITRARY_NAMESPACE: Lazy<NamespaceName<'static>> =
|
|
|
|
Lazy::new(|| "bananas".try_into().unwrap());
|
|
|
|
|
|
|
|
fn init_ns_cache(
|
2023-08-28 23:07:03 +00:00
|
|
|
rt: &tokio::runtime::Runtime,
|
2023-08-02 11:45:30 +00:00
|
|
|
initial_schema: impl IntoIterator<Item = (NamespaceName<'static>, NamespaceSchema)>,
|
|
|
|
) -> impl NamespaceCache {
|
|
|
|
let metrics = Arc::new(metric::Registry::default());
|
|
|
|
|
|
|
|
let catalog: Arc<dyn Catalog> = Arc::new(MemCatalog::new(Arc::clone(&metrics)));
|
2023-08-29 18:04:15 +00:00
|
|
|
let cache = Arc::new(ShardedCache::new(
|
2023-09-05 11:47:00 +00:00
|
|
|
iter::repeat_with(MemoryNamespaceCache::default).take(10),
|
2023-08-28 23:07:03 +00:00
|
|
|
));
|
|
|
|
|
2023-08-29 18:04:15 +00:00
|
|
|
let (actor, handle) = AntiEntropyActor::new(Arc::clone(&cache));
|
2023-08-28 23:07:03 +00:00
|
|
|
rt.spawn(actor.run());
|
|
|
|
|
|
|
|
let cache = MerkleTree::new(cache, handle);
|
2023-09-05 12:15:35 +00:00
|
|
|
let cache = ReadThroughCache::new(cache, Arc::clone(&catalog));
|
2023-08-02 11:45:30 +00:00
|
|
|
|
|
|
|
for (name, schema) in initial_schema {
|
|
|
|
cache.put_schema(name, schema);
|
|
|
|
}
|
|
|
|
|
|
|
|
cache
|
|
|
|
}
|
|
|
|
|
|
|
|
fn namespace_schema_cache_benchmarks(c: &mut Criterion) {
|
|
|
|
let mut group = c.benchmark_group("namespace_schema_cache_add_new_tables_with_columns");
|
|
|
|
|
2023-08-02 12:35:24 +00:00
|
|
|
for i in [1, 10, 100] {
|
|
|
|
bench_add_new_tables_with_columns(&mut group, i, 100);
|
|
|
|
}
|
2023-08-02 11:45:30 +00:00
|
|
|
|
|
|
|
group.finish();
|
|
|
|
|
|
|
|
let mut group = c.benchmark_group("namespace_schema_cache_add_columns_to_existing_table");
|
|
|
|
|
2023-08-02 12:35:24 +00:00
|
|
|
for i in [1, 10, 50] {
|
|
|
|
bench_add_columns_to_existing_table(&mut group, i, 1);
|
|
|
|
bench_add_columns_to_existing_table(&mut group, i, 10);
|
|
|
|
bench_add_columns_to_existing_table(&mut group, i, 100);
|
|
|
|
}
|
2023-08-02 11:45:30 +00:00
|
|
|
|
|
|
|
group.finish();
|
|
|
|
}
|
|
|
|
|
|
|
|
fn bench_add_new_tables_with_columns(
|
|
|
|
group: &mut BenchmarkGroup<WallTime>,
|
|
|
|
tables: usize,
|
|
|
|
columns_per_table: usize,
|
|
|
|
) {
|
|
|
|
const INITIAL_TABLE_COUNT: usize = 1;
|
|
|
|
let initial_schema = generate_namespace_schema(INITIAL_TABLE_COUNT, columns_per_table);
|
|
|
|
let schema_update = generate_namespace_schema(INITIAL_TABLE_COUNT + tables, columns_per_table);
|
|
|
|
|
2023-08-29 18:04:15 +00:00
|
|
|
let rt = tokio::runtime::Builder::new_multi_thread()
|
|
|
|
.worker_threads(4)
|
|
|
|
.build()
|
|
|
|
.unwrap();
|
2023-08-28 23:07:03 +00:00
|
|
|
|
2023-08-02 11:45:30 +00:00
|
|
|
group.throughput(Throughput::Elements((tables * columns_per_table) as _));
|
|
|
|
group.bench_function(format!("{tables}x{columns_per_table}"), |b| {
|
|
|
|
b.iter_batched(
|
|
|
|
|| {
|
|
|
|
(
|
2023-08-28 23:07:03 +00:00
|
|
|
init_ns_cache(&rt, [(ARBITRARY_NAMESPACE.clone(), initial_schema.clone())]),
|
2023-08-02 11:45:30 +00:00
|
|
|
ARBITRARY_NAMESPACE.clone(),
|
|
|
|
schema_update.clone(),
|
|
|
|
)
|
|
|
|
},
|
|
|
|
|(ns_cache, namespace_name, schema_update)| {
|
|
|
|
ns_cache.put_schema(namespace_name, schema_update)
|
|
|
|
},
|
2023-08-02 12:35:24 +00:00
|
|
|
BatchSize::NumIterations(1),
|
2023-08-02 11:45:30 +00:00
|
|
|
);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
fn bench_add_columns_to_existing_table(
|
|
|
|
group: &mut BenchmarkGroup<WallTime>,
|
|
|
|
initial_column_count: usize,
|
|
|
|
add_new_columns: usize,
|
|
|
|
) {
|
|
|
|
let initial_schema = generate_namespace_schema(1, initial_column_count);
|
|
|
|
let schema_update = generate_namespace_schema(1, initial_column_count + add_new_columns);
|
|
|
|
|
2023-08-28 23:07:03 +00:00
|
|
|
let rt = tokio::runtime::Runtime::new().unwrap();
|
|
|
|
|
2023-08-02 11:45:30 +00:00
|
|
|
group.throughput(Throughput::Elements(add_new_columns as _));
|
|
|
|
group.bench_function(format!("{initial_column_count}+{add_new_columns}"), |b| {
|
|
|
|
b.iter_batched(
|
|
|
|
|| {
|
|
|
|
(
|
2023-08-28 23:07:03 +00:00
|
|
|
init_ns_cache(&rt, [(ARBITRARY_NAMESPACE.clone(), initial_schema.clone())]),
|
2023-08-02 11:45:30 +00:00
|
|
|
ARBITRARY_NAMESPACE.clone(),
|
|
|
|
schema_update.clone(),
|
|
|
|
)
|
|
|
|
},
|
|
|
|
|(ns_cache, namespace_name, schema_update)| {
|
|
|
|
ns_cache.put_schema(namespace_name, schema_update)
|
|
|
|
},
|
2023-08-02 12:35:24 +00:00
|
|
|
BatchSize::NumIterations(1),
|
2023-08-02 11:45:30 +00:00
|
|
|
);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Deterministically generate an arbitrary [`NamespaceSchema`] with number of
|
|
|
|
/// `tables` each with a number of `columns_per_table`. An increasing number of
|
|
|
|
/// `tables` supersets the schema for a constant `columns_per_table` and vice
|
|
|
|
/// versa.
|
|
|
|
fn generate_namespace_schema(tables: usize, columns_per_table: usize) -> NamespaceSchema {
|
|
|
|
let partition_template = NamespacePartitionTemplateOverride::default();
|
|
|
|
NamespaceSchema {
|
|
|
|
id: NamespaceId::new(42),
|
|
|
|
tables: (0..tables)
|
|
|
|
.map(|i| {
|
|
|
|
let schema = TableSchema {
|
|
|
|
id: TableId::new(i as _),
|
|
|
|
columns: (0..columns_per_table)
|
|
|
|
.map(|j| {
|
|
|
|
(
|
|
|
|
format!("column{j}"),
|
|
|
|
ColumnSchema {
|
|
|
|
id: ColumnId::new(j as _),
|
|
|
|
column_type: data_types::ColumnType::U64,
|
|
|
|
},
|
|
|
|
)
|
|
|
|
})
|
|
|
|
.collect::<BTreeMap<_, _>>()
|
|
|
|
.into(),
|
|
|
|
partition_template: TablePartitionTemplateOverride::try_new(
|
|
|
|
None,
|
|
|
|
&partition_template,
|
|
|
|
)
|
|
|
|
.expect("should be able to use namespace partition template"),
|
|
|
|
};
|
|
|
|
(format!("table{i}"), schema)
|
|
|
|
})
|
|
|
|
.collect::<BTreeMap<_, _>>(),
|
|
|
|
max_columns_per_table: usize::MAX,
|
|
|
|
max_tables: usize::MAX,
|
|
|
|
retention_period_ns: None,
|
|
|
|
partition_template,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
criterion_group!(benches, namespace_schema_cache_benchmarks);
|
|
|
|
criterion_main!(benches);
|