From 60a87d18981230cd09f555242d11828176efb835 Mon Sep 17 00:00:00 2001 From: Magnus Hoff Date: Tue, 5 Sep 2017 14:55:10 +0200 Subject: [PATCH] Introduce db connection pool. Derive Clone for State --- Cargo.lock | 38 ++++++++++++++++++++++++++++++++++++++ Cargo.toml | 2 ++ src/db.rs | 36 +++++++++++++++++++++++------------- src/main.rs | 11 +++++++---- src/state.rs | 23 +++++++++++++++++------ 5 files changed, 87 insertions(+), 23 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 57a299f..ac52685 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -14,6 +14,8 @@ dependencies = [ "num 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", "pulldown-cmark 0.0.11 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", + "r2d2 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", + "r2d2-diesel 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)", "regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)", @@ -37,6 +39,11 @@ name = "ansi_term" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "antidote" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "atty" version = "0.2.2" @@ -451,6 +458,25 @@ name = "quote" version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "r2d2" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "antidote 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "scheduled-thread-pool 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "r2d2-diesel" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "diesel 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)", + "r2d2 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rand" version = "0.3.16" @@ -504,6 +530,14 @@ dependencies = [ "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "scheduled-thread-pool" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "antidote 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "scoped-tls" version = "0.1.0" @@ -791,6 +825,7 @@ dependencies = [ [metadata] "checksum aho-corasick 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "500909c4f87a9e52355b26626d890833e9e1d53ac566db76c36faa984b889699" "checksum ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "23ac7c30002a5accbf7e8987d0632fa6de155b7c3d39d0067317a391e00a2ef6" +"checksum antidote 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "34fde25430d87a9388dadbe6e34d7f72a462c8b43ac8d309b42b0a8505d7e2a5" "checksum atty 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d912da0db7fa85514874458ca3651fe2cddace8d0b0505571dbdcd41ab490159" "checksum bart 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f0f9d52a5c46e2abe28ae1c2ecdaa320c01e424c29a56acb7a6222141c78bae7" "checksum bart_derive 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "39fdc9035ac29aeb14993e2cdae217de7ccc9f9960eae0c5a12d541ca11c6af1" @@ -843,6 +878,8 @@ dependencies = [ "checksum pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "3a8b4c6b8165cd1a1cd4b9b120978131389f64bdaf456435caa41e630edba903" "checksum pulldown-cmark 0.0.11 (registry+https://github.com/rust-lang/crates.io-index)" = "4c7c04a8bb38f80717527edea39c82378c2ef13ecdbc914cbd90653a2e24afdf" "checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a" +"checksum r2d2 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6c665a538b218e1620093be6643b375d3321837bfc1b30aa18757b7c6546d2ca" +"checksum r2d2-diesel 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f6b921696a6c45991296d21b52ed973b9fb56f6c47524fda1f99458c2d6c0478" "checksum rand 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)" = "eb250fd207a4729c976794d03db689c9be1d634ab5a1c9da9492a13d8fecbcdf" "checksum redox_syscall 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)" = "8312fba776a49cf390b7b62f3135f9b294d8617f7a7592cfd0ac2492b658cd7b" "checksum regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1731164734096285ec2a5ec7fea5248ae2f5485b3feeb0115af4fda2183b2d1b" @@ -850,6 +887,7 @@ dependencies = [ "checksum rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "c5f5376ea5e30ce23c03eb77cbe4962b988deead10910c372b226388b594c084" "checksum safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e27a8b19b835f7aea908818e871f5cc3a5a186550c30773be987e155e8163d8f" "checksum same-file 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d931a44fdaa43b8637009e7632a02adc4f2b2e0733c08caa4cf00e8da4a117a7" +"checksum scheduled-thread-pool 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2d9fbe48ead32343b76f544c85953bf260ed39219a8bbbb62cd85f6a00f9644f" "checksum scoped-tls 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f417c22df063e9450888a7561788e9bd46d3bb3c1466435b4eccb903807f147d" "checksum semver 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)" = "d4f410fedcf71af0345d7607d246e7ad15faaadd49d240ee3b24e5dc21a820ac" "checksum serde 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)" = "f7726f29ddf9731b17ff113c461e362c381d9d69433f79de4f3dd572488823e9" diff --git a/Cargo.toml b/Cargo.toml index 33a72d3..8316462 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,6 +12,8 @@ tokio-service = "0.1" serde_derive = "1.0.0" serde = "1.0.0" serde_urlencoded = "0.5.0" +r2d2 = "0.7" +r2d2-diesel = "0.16" regex = "0.2" lazy_static = "0.2" chrono = "0.4" diff --git a/src/db.rs b/src/db.rs index 682c8d6..11ff7e5 100644 --- a/src/db.rs +++ b/src/db.rs @@ -1,23 +1,33 @@ -use diesel::Connection; use diesel::sqlite::SqliteConnection; use diesel::prelude::*; use diesel::expression::sql_literal::sql; use diesel::types::*; +use r2d2::{Config, CustomizeConnection, Pool}; +use r2d2_diesel::{self, ConnectionManager}; embed_migrations!(); -pub fn connect_database(connection_string: &str, run_migrations: bool) -> SqliteConnection { - let connection = SqliteConnection::establish(connection_string) - .expect(&format!("Error connecting to database at {}", connection_string)); +#[derive(Debug)] +struct SqliteInitializer; - // Integer is a dummy placeholder. Compiling fails when passing (). - sql::<(Integer)>("PRAGMA foreign_keys = ON") - .execute(&connection) - .expect("Should be able to enable foreign_keys"); - - if run_migrations { - embedded_migrations::run(&connection).unwrap(); +impl CustomizeConnection for SqliteInitializer { + fn on_acquire(&self, conn: &mut SqliteConnection) -> Result<(), r2d2_diesel::Error> { + sql::<(Integer)>("PRAGMA foreign_keys = ON") + .execute(conn) + .and(Ok(())) + .map_err(|x| r2d2_diesel::Error::QueryError(x)) } - - connection +} + +pub fn create_pool(connection_string: String) -> Result>, Box<::std::error::Error>> { + let config = Config::builder() + .connection_customizer(Box::new(SqliteInitializer {})) + .build(); + let manager = ConnectionManager::::new(connection_string); + + let pool = Pool::new(config, manager)?; + + embedded_migrations::run(&*pool.get()?)?; + + Ok(pool) } diff --git a/src/main.rs b/src/main.rs index fb3ef6e..3cc266c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,13 +2,16 @@ #[macro_use] extern crate diesel; #[macro_use] extern crate diesel_codegen; #[macro_use] extern crate lazy_static; +#[macro_use] extern crate serde_derive; -extern crate bart; extern crate chrono; extern crate clap; extern crate futures; extern crate hyper; extern crate pulldown_cmark; +extern crate r2d2; +extern crate r2d2_diesel; +extern crate serde_urlencoded; use std::net::SocketAddr; @@ -48,14 +51,14 @@ fn core_main() -> Result<(), Box> { .map(|p| p.parse().expect("Guaranteed by validator")) .unwrap_or(8080); - // Connect to the database and run migrations up front: - db::connect_database(&db_file, true); + let db_pool = db::create_pool(db_file)?; + let state = state::State::new(db_pool); let server = hyper::server::Http::new() .bind( &SocketAddr::new(bind_host, bind_port), - move || Ok(site::Site::new(state::State::new(db::connect_database(&db_file, false)))) + move || Ok(site::Site::new(state.clone())) )?; println!("Listening on http://{}", server.local_addr().unwrap()); diff --git a/src/state.rs b/src/state.rs index 814ff33..7ffeb2e 100644 --- a/src/state.rs +++ b/src/state.rs @@ -3,19 +3,30 @@ use std; use chrono; use diesel::sqlite::SqliteConnection; use diesel::prelude::*; +use r2d2::Pool; +use r2d2_diesel::ConnectionManager; use models; +#[derive(Clone)] pub struct State { - db_connection: SqliteConnection + connection_pool: Pool> } +#[derive(Deserialize)] +pub struct UpdateArticle { + base_revision: i32, + body: String, +} + +pub type Error = Box; + impl State { - pub fn new(db_connection: SqliteConnection) -> State { - State { db_connection } + pub fn new(connection_pool: Pool>) -> State { + State { connection_pool } } - pub fn get_article_revision_by_slug(&self, slug: &str) -> Result, Box> { + pub fn get_article_revision_by_slug(&self, slug: &str) -> Result, Error> { Ok(Some(models::ArticleRevision { article_id: 0, revision: 0, @@ -25,14 +36,14 @@ impl State { })) } - pub fn get_article_revision_by_id(&self, article_id: i32) -> Result, Box> { + pub fn get_article_revision_by_id(&self, article_id: i32) -> Result, Error> { use schema::article_revisions; Ok(article_revisions::table .filter(article_revisions::article_id.eq(article_id)) .order(article_revisions::revision.desc()) .limit(1) - .load::(&self.db_connection)? + .load::(&*self.connection_pool.get()?)? .pop()) } }