|  | @@ -15,7 +15,6 @@ use yarte::{ywrite_html, Serialize};
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  mod utils {
 | 
	
		
			
				|  |  |      use atoi::FromRadix10;
 | 
	
		
			
				|  |  | -    use may_postgres::types::ToSql;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      pub fn get_query_param(query: &str) -> u16 {
 | 
	
		
			
				|  |  |          let q = if let Some(pos) = query.find("?q") {
 | 
	
	
		
			
				|  | @@ -25,12 +24,6 @@ mod utils {
 | 
	
		
			
				|  |  |          };
 | 
	
		
			
				|  |  |          q.clamp(1, 500)
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    pub fn slice_iter<'a>(
 | 
	
		
			
				|  |  | -        s: &'a [&'a (dyn ToSql + Sync)],
 | 
	
		
			
				|  |  | -    ) -> impl ExactSizeIterator<Item = &'a dyn ToSql> + 'a {
 | 
	
		
			
				|  |  | -        s.iter().map(|s| *s as _)
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  #[derive(Serialize)]
 | 
	
	
		
			
				|  | @@ -52,16 +45,15 @@ pub struct Fortune<'a> {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  struct PgConnectionPool {
 | 
	
		
			
				|  |  |      idx: AtomicUsize,
 | 
	
		
			
				|  |  | -    clients: Vec<Arc<PgConnection>>,
 | 
	
		
			
				|  |  | +    clients: Vec<PgConnection>,
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  impl PgConnectionPool {
 | 
	
		
			
				|  |  | -    fn new(db_url: &str, size: usize) -> PgConnectionPool {
 | 
	
		
			
				|  |  | -        let mut clients = Vec::with_capacity(size);
 | 
	
		
			
				|  |  | -        for _ in 0..size {
 | 
	
		
			
				|  |  | -            let client = PgConnection::new(db_url);
 | 
	
		
			
				|  |  | -            clients.push(Arc::new(client));
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | +    fn new(db_url: &'static str, size: usize) -> PgConnectionPool {
 | 
	
		
			
				|  |  | +        let clients = (0..size)
 | 
	
		
			
				|  |  | +            .map(|_| std::thread::spawn(move || PgConnection::new(db_url)))
 | 
	
		
			
				|  |  | +            .collect::<Vec<_>>();
 | 
	
		
			
				|  |  | +        let clients = clients.into_iter().map(|t| t.join().unwrap()).collect();
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          PgConnectionPool {
 | 
	
		
			
				|  |  |              idx: AtomicUsize::new(0),
 | 
	
	
		
			
				|  | @@ -69,20 +61,28 @@ impl PgConnectionPool {
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    fn get_connection(&self) -> (Arc<PgConnection>, usize) {
 | 
	
		
			
				|  |  | +    fn get_connection(&self) -> PgConnection {
 | 
	
		
			
				|  |  |          let idx = self.idx.fetch_add(1, Ordering::Relaxed);
 | 
	
		
			
				|  |  |          let len = self.clients.len();
 | 
	
		
			
				|  |  | -        (self.clients[idx % len].clone(), idx)
 | 
	
		
			
				|  |  | +        let connection = &self.clients[idx % len];
 | 
	
		
			
				|  |  | +        PgConnection {
 | 
	
		
			
				|  |  | +            client: connection.client.clone(),
 | 
	
		
			
				|  |  | +            statement: connection.statement.clone(),
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -struct PgConnection {
 | 
	
		
			
				|  |  | -    client: Client,
 | 
	
		
			
				|  |  | +struct PgStatement {
 | 
	
		
			
				|  |  |      world: Statement,
 | 
	
		
			
				|  |  |      fortune: Statement,
 | 
	
		
			
				|  |  |      updates: Vec<Statement>,
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +struct PgConnection {
 | 
	
		
			
				|  |  | +    client: Client,
 | 
	
		
			
				|  |  | +    statement: Arc<PgStatement>,
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  impl PgConnection {
 | 
	
		
			
				|  |  |      fn new(db_url: &str) -> Self {
 | 
	
		
			
				|  |  |          let client = may_postgres::connect(db_url).unwrap();
 | 
	
	
		
			
				|  | @@ -103,7 +103,7 @@ impl PgConnection {
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |              q.push_str("ELSE randomnumber END WHERE id IN (");
 | 
	
		
			
				|  |  |              for _ in 1..=num {
 | 
	
		
			
				|  |  | -                let _ = write!(&mut q, "${},", pl);
 | 
	
		
			
				|  |  | +                let _ = write!(&mut q, "${pl},");
 | 
	
		
			
				|  |  |                  pl += 1;
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |              q.pop();
 | 
	
	
		
			
				|  | @@ -111,18 +111,19 @@ impl PgConnection {
 | 
	
		
			
				|  |  |              updates.push(client.prepare(&q).unwrap());
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -        PgConnection {
 | 
	
		
			
				|  |  | -            client,
 | 
	
		
			
				|  |  | +        let statement = Arc::new(PgStatement {
 | 
	
		
			
				|  |  |              world,
 | 
	
		
			
				|  |  |              fortune,
 | 
	
		
			
				|  |  |              updates,
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | +        });
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        PgConnection { client, statement }
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      fn get_world(&self, random_id: i32) -> Result<WorldRow, may_postgres::Error> {
 | 
	
		
			
				|  |  |          let mut q = self
 | 
	
		
			
				|  |  |              .client
 | 
	
		
			
				|  |  | -            .query_raw(&self.world, utils::slice_iter(&[&random_id]))?;
 | 
	
		
			
				|  |  | +            .query_raw(&self.statement.world, [&random_id as _])?;
 | 
	
		
			
				|  |  |          match q.next().transpose()? {
 | 
	
		
			
				|  |  |              Some(row) => Ok(WorldRow {
 | 
	
		
			
				|  |  |                  id: row.get(0),
 | 
	
	
		
			
				|  | @@ -142,7 +143,7 @@ impl PgConnection {
 | 
	
		
			
				|  |  |              let random_id = (rand.generate::<u32>() % 10_000 + 1) as i32;
 | 
	
		
			
				|  |  |              queries.push(
 | 
	
		
			
				|  |  |                  self.client
 | 
	
		
			
				|  |  | -                    .query_raw(&self.world, utils::slice_iter(&[&random_id]))?,
 | 
	
		
			
				|  |  | +                    .query_raw(&self.statement.world, [&random_id as _])?,
 | 
	
		
			
				|  |  |              );
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -169,7 +170,7 @@ impl PgConnection {
 | 
	
		
			
				|  |  |              let random_id = (rand.generate::<u32>() % 10_000 + 1) as i32;
 | 
	
		
			
				|  |  |              queries.push(
 | 
	
		
			
				|  |  |                  self.client
 | 
	
		
			
				|  |  | -                    .query_raw(&self.world, utils::slice_iter(&[&random_id]))?,
 | 
	
		
			
				|  |  | +                    .query_raw(&self.statement.world, [&random_id as _])?,
 | 
	
		
			
				|  |  |              );
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -185,7 +186,7 @@ impl PgConnection {
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -        let mut params: Vec<&(dyn ToSql + Sync)> = Vec::with_capacity(num * 3);
 | 
	
		
			
				|  |  | +        let mut params: Vec<&(dyn ToSql)> = Vec::with_capacity(num * 3);
 | 
	
		
			
				|  |  |          for w in &worlds {
 | 
	
		
			
				|  |  |              params.push(&w.id);
 | 
	
		
			
				|  |  |              params.push(&w.randomnumber);
 | 
	
	
		
			
				|  | @@ -194,23 +195,20 @@ impl PgConnection {
 | 
	
		
			
				|  |  |              params.push(&w.id);
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -        self.client.query(&self.updates[num - 1], ¶ms)?;
 | 
	
		
			
				|  |  | +        self.client
 | 
	
		
			
				|  |  | +            .query_raw(&self.statement.updates[num - 1], params)?;
 | 
	
		
			
				|  |  |          Ok(worlds)
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      fn tell_fortune(&self, buf: &mut BytesMut) -> Result<(), may_postgres::Error> {
 | 
	
		
			
				|  |  | -        let rows = self
 | 
	
		
			
				|  |  | -            .client
 | 
	
		
			
				|  |  | -            .query_raw(&self.fortune, utils::slice_iter(&[]))?;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        let all_rows = rows.map(|r| r.unwrap()).collect::<Vec<_>>();
 | 
	
		
			
				|  |  | -        let mut fortunes = all_rows
 | 
	
		
			
				|  |  | -            .iter()
 | 
	
		
			
				|  |  | -            .map(|r| Fortune {
 | 
	
		
			
				|  |  | -                id: r.get(0),
 | 
	
		
			
				|  |  | -                message: r.get(1),
 | 
	
		
			
				|  |  | -            })
 | 
	
		
			
				|  |  | -            .collect::<Vec<_>>();
 | 
	
		
			
				|  |  | +        let rows = self.client.query_raw(&self.statement.fortune, [])?;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        let all_rows = Vec::from_iter(rows.map(|r| r.unwrap()));
 | 
	
		
			
				|  |  | +        let mut fortunes = Vec::with_capacity(all_rows.capacity() + 1);
 | 
	
		
			
				|  |  | +        fortunes.extend(all_rows.iter().map(|r| Fortune {
 | 
	
		
			
				|  |  | +            id: r.get(0),
 | 
	
		
			
				|  |  | +            message: r.get(1),
 | 
	
		
			
				|  |  | +        }));
 | 
	
		
			
				|  |  |          fortunes.push(Fortune {
 | 
	
		
			
				|  |  |              id: 0,
 | 
	
		
			
				|  |  |              message: "Additional fortune added at request time.",
 | 
	
	
		
			
				|  | @@ -225,7 +223,7 @@ impl PgConnection {
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  struct Techempower {
 | 
	
		
			
				|  |  | -    db: Arc<PgConnection>,
 | 
	
		
			
				|  |  | +    db: PgConnection,
 | 
	
		
			
				|  |  |      rng: WyRand,
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -282,16 +280,14 @@ impl HttpServiceFactory for HttpServer {
 | 
	
		
			
				|  |  |      type Service = Techempower;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      fn new_service(&self) -> Self::Service {
 | 
	
		
			
				|  |  | -        let (db, _idx) = self.db_pool.get_connection();
 | 
	
		
			
				|  |  | +        let db = self.db_pool.get_connection();
 | 
	
		
			
				|  |  |          let rng = WyRand::new();
 | 
	
		
			
				|  |  |          Techempower { db, rng }
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  fn main() {
 | 
	
		
			
				|  |  | -    may::config()
 | 
	
		
			
				|  |  | -        .set_pool_capacity(10000)
 | 
	
		
			
				|  |  | -        .set_stack_size(0x1000);
 | 
	
		
			
				|  |  | +    may::config().set_pool_capacity(1000).set_stack_size(0x1000);
 | 
	
		
			
				|  |  |      println!("Starting http server: 127.0.0.1:8080");
 | 
	
		
			
				|  |  |      let server = HttpServer {
 | 
	
		
			
				|  |  |          db_pool: PgConnectionPool::new(
 |