Skip to content

Commit 37ebdba

Browse files
committed
Optimising codegen using an asynchronous client and pipelining
1 parent 22df44e commit 37ebdba

File tree

17 files changed

+129
-83
lines changed

17 files changed

+129
-83
lines changed

Cargo.lock

Lines changed: 37 additions & 24 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

benches/codegen.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ fn bench(c: &mut Criterion) {
66
cornucopia::container::setup(false).unwrap();
77
let client = &mut cornucopia_conn().unwrap();
88

9-
cornucopia::load_schema(client, &["../codegen_test/schema.sql"]).unwrap();
9+
cornucopia::load_schema(client, &["../test_codegen/schema.sql"]).unwrap();
1010
c.bench_function("codegen_sync", |b| {
1111
b.iter(|| {
1212
cornucopia::generate_live(

benches/execution/main.rs

Lines changed: 7 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ use cornucopia::conn::cornucopia_conn;
44
use criterion::{BenchmarkId, Criterion};
55
use diesel::{Connection, PgConnection};
66
use postgres::{fallible_iterator::FallibleIterator, Client, NoTls};
7-
use tokio::runtime::Runtime;
87

98
const QUERY_SIZE: &[usize] = &[1, 100, 10_000];
109
const INSERT_SIZE: &[usize] = &[1, 100, 1000];
@@ -128,23 +127,16 @@ fn prepare_full(client: &mut Client) {
128127
fn bench(c: &mut Criterion) {
129128
cornucopia::container::cleanup(false).ok();
130129
cornucopia::container::setup(false).unwrap();
131-
let client = &mut cornucopia_conn().unwrap();
132-
let rt: &'static Runtime = Box::leak(Box::new(Runtime::new().unwrap()));
133-
let async_client = &mut rt.block_on(async {
134-
let (client, conn) = tokio_postgres::connect(
135-
"postgresql://postgres:[email protected]:5435/postgres",
136-
NoTls,
137-
)
138-
.await
139-
.unwrap();
140-
rt.spawn(conn);
141-
client
142-
});
130+
let client = &mut postgres::Client::connect(
131+
"postgresql://postgres:[email protected]:5435/postgres",
132+
NoTls,
133+
)
134+
.unwrap();
135+
let async_client = &mut cornucopia_conn().unwrap();
143136
let conn =
144137
&mut PgConnection::establish("postgresql://postgres:[email protected]:5435/postgres")
145138
.unwrap();
146-
147-
cornucopia::load_schema(client, &["usage/cornucopia_benches/schema.sql"]).unwrap();
139+
cornucopia::load_schema(async_client, &["execution/cornucopia_benches/schema.sql"]).unwrap();
148140
{
149141
let mut group = c.benchmark_group("bench_trivial_query");
150142
for size in QUERY_SIZE {

crates/cornucopia/Cargo.toml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,13 @@ keywords = ["postgresql", "query", "generator", "sql", "tokio-postgres"]
1515
codegen_template = { path = "../codegen_template", version = "0.1.0" }
1616

1717
# Postgres interaction
18-
postgres = "0.19.4"
18+
tokio-postgres = "0.7.8"
1919
postgres-types = "0.2.4"
2020

21+
# Async
22+
tokio = { version = "1.28.1", features = ["rt-multi-thread"] }
23+
futures = "0.3.28"
24+
2125
# Error handling and reporting
2226
thiserror = "1.0.38"
2327
miette = { version = "5.5.0", features = ["fancy"] }

crates/cornucopia/src/cli.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,8 @@ pub fn run() -> Result<(), Error> {
6464

6565
match action {
6666
Action::Live { url } => {
67-
let mut client = conn::from_url(&url)?;
68-
generate_live(&mut client, &queries_path, Some(&destination), settings)?;
67+
let client = conn::from_url(&url)?;
68+
generate_live(&client, &queries_path, Some(&destination), settings)?;
6969
}
7070
Action::Schema { schema_files } => {
7171
// Run the generate command. If the command is unsuccessful, cleanup Cornucopia's container

crates/cornucopia/src/conn.rs

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,42 @@
1-
use postgres::{Client, Config, NoTls};
1+
use tokio::runtime::Runtime;
2+
use tokio_postgres::{Client, Config, NoTls};
23

34
use self::error::Error;
45

56
/// Creates a non-TLS connection from a URL.
67
pub(crate) fn from_url(url: &str) -> Result<Client, Error> {
7-
Ok(Client::connect(url, NoTls)?)
8+
connect(url.parse()?)
89
}
910

1011
/// Create a non-TLS connection to the container managed by Cornucopia.
1112
pub fn cornucopia_conn() -> Result<Client, Error> {
12-
Ok(Config::new()
13-
.user("postgres")
14-
.password("postgres")
15-
.host("127.0.0.1")
16-
.port(5435)
17-
.dbname("postgres")
18-
.connect(NoTls)?)
13+
connect(
14+
Config::new()
15+
.user("postgres")
16+
.password("postgres")
17+
.host("127.0.0.1")
18+
.port(5435)
19+
.dbname("postgres")
20+
.clone(),
21+
)
22+
}
23+
24+
fn connect(config: Config) -> Result<Client, Error> {
25+
let rt: &'static Runtime = Box::leak(Box::new(
26+
Runtime::new().expect("Failed to start async Runtime"),
27+
));
28+
let client = rt.block_on(async {
29+
let (client, conn) = config.connect(NoTls).await.unwrap();
30+
rt.spawn(conn);
31+
client
32+
});
33+
Ok(client)
1934
}
2035

2136
pub(crate) mod error {
2237
use miette::Diagnostic;
2338

2439
#[derive(Debug, thiserror::Error, Diagnostic)]
2540
#[error("Couldn't establish a connection with the database.")]
26-
pub struct Error(#[from] pub postgres::Error);
41+
pub struct Error(#[from] pub tokio_postgres::Error);
2742
}

crates/cornucopia/src/lib.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ pub mod container;
1616

1717
use std::path::Path;
1818

19-
use postgres::Client;
19+
use tokio_postgres::Client;
2020

2121
use codegen::generate as generate_internal;
2222
use error::WriteOutputError;
@@ -43,7 +43,7 @@ pub struct CodegenSettings {
4343
/// the generated code will be written at that path. Code generation settings are
4444
/// set using the `settings` parameter.
4545
pub fn generate_live<P: AsRef<Path>>(
46-
client: &mut Client,
46+
client: &Client,
4747
queries_path: P,
4848
destination: Option<P>,
4949
settings: CodegenSettings,
@@ -84,9 +84,9 @@ pub fn generate_managed<P: AsRef<Path>>(
8484
.map(parse_query_module)
8585
.collect::<Result<_, parser::error::Error>>()?;
8686
container::setup(podman)?;
87-
let mut client = conn::cornucopia_conn()?;
88-
load_schema(&mut client, schema_files)?;
89-
let prepared_modules = prepare(&mut client, modules)?;
87+
let client = conn::cornucopia_conn()?;
88+
load_schema(&client, schema_files)?;
89+
let prepared_modules = prepare(&client, modules)?;
9090
let generated_code = generate_internal(prepared_modules, settings);
9191
container::cleanup(podman)?;
9292

crates/cornucopia/src/load_schema.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use std::path::Path;
22

33
use miette::NamedSource;
4-
use postgres::Client;
4+
use tokio_postgres::Client;
55

66
use crate::utils::db_err;
77

@@ -10,14 +10,14 @@ use self::error::Error;
1010
/// Loads PostgreSQL schemas into a database.
1111
///
1212
/// Takes a list of file paths as parameter and loads them in their given order.
13-
pub fn load_schema<P: AsRef<Path>>(client: &mut Client, paths: &[P]) -> Result<(), Error> {
13+
pub fn load_schema<P: AsRef<Path>>(client: &Client, paths: &[P]) -> Result<(), Error> {
1414
for path in paths {
1515
let path = path.as_ref();
1616
let sql = std::fs::read_to_string(path).map_err(|err| Error::Io {
1717
path: path.to_string_lossy().to_string(),
1818
err,
1919
})?;
20-
client.batch_execute(&sql).map_err(|err| {
20+
futures::executor::block_on(client.batch_execute(&sql)).map_err(|err| {
2121
let msg = format!("{err:#}");
2222
let src = NamedSource::new(path.to_string_lossy(), sql);
2323
if let Some((position, msg, help)) = db_err(&err) {

0 commit comments

Comments
 (0)