diff --git a/server/Cargo.toml b/server/Cargo.toml index 9d4a79a..9e38251 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -16,3 +16,4 @@ http = "0.2" geo = "0.18" cairo-rs = { version = "0.14", features = ["png"] } chrono = { version = "0.4", features = ["serde"] } +num_cpus = "1" diff --git a/server/src/area.rs b/server/src/area.rs index 53be199..c919555 100644 --- a/server/src/area.rs +++ b/server/src/area.rs @@ -17,12 +17,11 @@ pub fn get_details(state: State) -> (State, Response) { let pe = PointExtractor::borrow_from(&state); let app_state = AppState::borrow_from(&state); let mut seen_srcs = HashSet::new(); - let result = { - let mut db = app_state.db.lock().unwrap(); + let result = app_state.with_db(|db| { db.query("SELECT src, attrs FROM areas WHERE coords @> $1::point ORDER BY coords <-> $1::point ASC", &[ &pe.to_point() ]).unwrap() - }.into_iter().filter(|row| { + }).into_iter().filter(|row| { let src: &str = row.get(0); if seen_srcs.contains(src) { false @@ -43,12 +42,11 @@ pub fn get_details(state: State) -> (State, Response) { pub fn get_heatmap(state: State) -> (State, Response) { let pe = AreaExtractor::borrow_from(&state); let app_state = AppState::borrow_from(&state); - let result = { - let mut db = app_state.db.lock().unwrap(); + let result = app_state.with_db(|db| { db.query("SELECT path(coords), src, attrs FROM areas WHERE box(coords) ?# $1::box", &[ &pe.to_rect() ]).unwrap() - }; + }); const TILE_MAX: i32 = 256; let (w, h) = if pe.w() > pe.h() { diff --git a/server/src/main.rs b/server/src/main.rs index 1b51616..5f8e711 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -29,7 +29,23 @@ mod tiles; #[derive(Clone, StateData)] pub struct AppState { - pub db: Arc>, + pub db_pool: Vec>>, + pub db_pool_index: Arc>, +} + +impl AppState { + pub fn with_db R, R>(&self, f: F) -> R { + use std::ops::Deref; + let mut db_pool_index = self.db_pool_index.lock().unwrap(); + let mut db = self.db_pool[*db_pool_index].lock().unwrap(); + + *db_pool_index += 1; + if *db_pool_index >= self.db_pool.len() { + *db_pool_index = 0; + } + + f(&mut db) + } } @@ -119,11 +135,15 @@ impl TileExtractor { fn main() { const DB_URL: &str = "host=10.233.1.2 dbname=treeadvisor user=treeadvisor password=123"; - let db = postgres::Client::connect(DB_URL, postgres::NoTls) - .expect("DB"); + let cpus = num_cpus::get(); + let db_pool = (0..cpus).map(|_| Arc::new(Mutex::new( + postgres::Client::connect(DB_URL, postgres::NoTls) + .expect("DB") + ))).collect(); let state = AppState { - db: Arc::new(Mutex::new(db)), + db_pool: db_pool, + db_pool_index: Arc::new(Mutex::new(0)), }; let (chain, pipelines) = single_pipeline( single_middleware( diff --git a/server/src/tiles.rs b/server/src/tiles.rs index 62c117c..c3b4b2c 100644 --- a/server/src/tiles.rs +++ b/server/src/tiles.rs @@ -38,12 +38,11 @@ pub fn get_tile(state: State) -> (State, Response) { let bounds = te.to_rect(); println!("get_tile@{} {:?}", zoom, bounds); let app_state = AppState::borrow_from(&state); - let result = { - let mut db = app_state.db.lock().unwrap(); + let result = app_state.with_db(|db| db.query("SELECT geo, attrs FROM osm_ways WHERE box(polygon(pclose(geo))) && $1::box", &[ &bounds.grow(1.2) ]).unwrap() - }; + ); const TILE_SIZE: i32 = 256; let (w, h) = (TILE_SIZE, TILE_SIZE); diff --git a/server/src/trees.rs b/server/src/trees.rs index 1469080..f159627 100644 --- a/server/src/trees.rs +++ b/server/src/trees.rs @@ -40,12 +40,11 @@ struct Tree { pub fn get_trees(state: State) -> (State, Response) { let pe = AreaExtractor::borrow_from(&state); let app_state = AppState::borrow_from(&state); - let result = { - let mut db = app_state.db.lock().unwrap(); + let result = app_state.with_db(|db| { db.query("SELECT id, coord, botanic, german, planted FROM trees WHERE coord <@ $1::box ORDER BY coord <-> center($1::box) ASC LIMIT 2000", &[ &pe.to_rect() ]).unwrap() - }.into_iter().map(|row| { + }).into_iter().map(|row| { let point: Point = row.get(1); Tree { id: row.get(0), @@ -82,8 +81,7 @@ const PFAF_COLS: &[&str] = &[ pub fn get_tree(state: State) -> (State, Response) { let ie = IdExtractor::borrow_from(&state); let app_state = AppState::borrow_from(&state); - let result = { - let mut db = app_state.db.lock().unwrap(); + let result = app_state.with_db(|db| { match db.query("SELECT id, coord, botanic, botanic_pfaf, german, planted FROM trees WHERE id=$1 LIMIT 1", &[&ie.id]).unwrap() .into_iter() .next() { @@ -119,7 +117,7 @@ pub fn get_tree(state: State) -> (State, Response) { }) } } - }; + }); let res = match result { Some(result) => { @@ -135,12 +133,11 @@ pub fn get_tree(state: State) -> (State, Response) { pub fn get_heatmap(state: State) -> (State, Response) { let rect = TileExtractor::borrow_from(&state).to_rect(); let app_state = AppState::borrow_from(&state); - let result = { - let mut db = app_state.db.lock().unwrap(); + let result = app_state.with_db(|db| { db.query("SELECT coord, score, planted FROM trees WHERE coord <@ $1::box AND SCORE IS NOT NULL", &[ &rect.grow(1.2) ]).unwrap() - }; + }); const TILE_SIZE: i32 = 256; let (w, h) = (TILE_SIZE, TILE_SIZE);