Files
zeekay 86788566d1 datastore: rebrand the Rust client and speak the Datastore wire protocol
Cut from the upstream v0.13.3 release tag (not HEAD) so this is a pure
rename with no behaviour change. v0.13.3 is what our consumers already
resolve to: insights/rust's Cargo.lock pins clickhouse 0.13.3 and its
manifest already declares `datastore` at 0.13.x.

The load-bearing change is the HTTP auth header rename. The Datastore
server reads only X-Datastore-User / X-Datastore-Key; the upstream names
return `401 Code: 194 Authentication failed`. Every un-renamed HTTP
client is therefore unable to authenticate at all — this is a
correctness fix, not branding.

- crate `clickhouse` -> `datastore`, `clickhouse-derive` -> `datastore-derive`;
  versions preserved exactly (0.13.3 / 0.2.0).
- derive macro emits `datastore::Row` in lockstep, so downstream
  `#[derive(Row)]` keeps resolving.
- User-Agent reports `datastore-rs/{version}`.
- test-harness env vars CLICKHOUSE_* -> DATASTORE_*; compose uses
  ghcr.io/hanzoai/datastore with /etc/datastore-server config paths.
- doc links point at docs.hanzo.ai/datastore.
- `publish = false`: the `datastore` name on crates.io belongs to an
  unrelated crate, so consume this by git tag, never by version range.

CHANGELOG is truncated to a fork notice rather than find-replaced —
rewriting upstream release history would manufacture changes Datastore
never shipped. References to upstream issues keep their numbers.
2026-07-26 11:30:32 -07:00

125 lines
3.1 KiB
Rust

use std::{
future::Future,
mem,
time::{Duration, Instant},
};
use bytes::Bytes;
use criterion::{black_box, criterion_group, criterion_main, Criterion, Throughput};
use http_body_util::Empty;
use hyper::{body::Incoming, Request, Response};
use serde::Serialize;
use datastore::{error::Result, Client, Compression, Row};
mod common;
async fn serve(request: Request<Incoming>) -> Response<Empty<Bytes>> {
common::skip_incoming(request).await;
Response::new(Empty::new())
}
#[derive(Row, Serialize)]
struct SomeRow {
a: u64,
b: i64,
c: i32,
d: u32,
e: u64,
f: u32,
g: u64,
h: i64,
}
impl SomeRow {
fn sample() -> Self {
black_box(Self {
a: 42,
b: 42,
c: 42,
d: 42,
e: 42,
f: 42,
g: 42,
h: 42,
})
}
}
async fn run_insert(client: Client, iters: u64) -> Result<Duration> {
let start = Instant::now();
let mut insert = client.insert("table")?;
for _ in 0..iters {
insert.write(&SomeRow::sample()).await?;
}
insert.end().await?;
Ok(start.elapsed())
}
#[cfg(feature = "inserter")]
async fn run_inserter<const WITH_PERIOD: bool>(client: Client, iters: u64) -> Result<Duration> {
let start = Instant::now();
let mut inserter = client.inserter("table")?.with_max_rows(iters);
if WITH_PERIOD {
// Just to measure overhead, not to actually use it.
inserter = inserter.with_period(Some(Duration::from_secs(1000)));
}
for _ in 0..iters {
inserter.write(&SomeRow::sample())?;
inserter.commit().await?;
}
inserter.end().await?;
Ok(start.elapsed())
}
fn run<F>(c: &mut Criterion, name: &str, port: u16, f: impl Fn(Client, u64) -> F)
where
F: Future<Output = Result<Duration>> + Send + 'static,
{
let addr = format!("127.0.0.1:{port}").parse().unwrap();
let _server = common::start_server(addr, serve);
let runner = common::start_runner();
let mut group = c.benchmark_group(name);
group.throughput(Throughput::Bytes(mem::size_of::<SomeRow>() as u64));
group.bench_function("no compression", |b| {
b.iter_custom(|iters| {
let client = Client::default()
.with_url(format!("http://{addr}"))
.with_compression(Compression::None);
runner.run((f)(client, iters))
})
});
#[cfg(feature = "lz4")]
group.bench_function("lz4", |b| {
b.iter_custom(|iters| {
let client = Client::default()
.with_url(format!("http://{addr}"))
.with_compression(Compression::Lz4);
runner.run((f)(client, iters))
})
});
group.finish();
}
fn insert(c: &mut Criterion) {
run(c, "insert", 6543, run_insert);
}
#[cfg(feature = "inserter")]
fn inserter(c: &mut Criterion) {
run(c, "inserter", 6544, run_inserter::<false>);
run(c, "inserter-period", 6545, run_inserter::<true>);
}
#[cfg(not(feature = "inserter"))]
criterion_group!(benches, insert);
#[cfg(feature = "inserter")]
criterion_group!(benches, insert, inserter);
criterion_main!(benches);