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);