|
@@ -1,24 +1,25 @@
|
|
|
#[global_allocator]
|
|
|
static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc;
|
|
|
|
|
|
-use std::borrow::Cow;
|
|
|
use std::fmt::Write;
|
|
|
use std::io;
|
|
|
use std::sync::atomic::{AtomicUsize, Ordering};
|
|
|
use std::sync::Arc;
|
|
|
|
|
|
+use bytes::BytesMut;
|
|
|
use may_minihttp::{HttpService, HttpServiceFactory, Request, Response};
|
|
|
use may_postgres::{self, types::ToSql, Client, Statement};
|
|
|
-use oorandom::Rand32;
|
|
|
+use nanorand::{Rng, WyRand};
|
|
|
use smallvec::SmallVec;
|
|
|
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") {
|
|
|
- query.split_at(pos + 3).1.parse::<u16>().ok().unwrap_or(1)
|
|
|
+ u16::from_radix_10(query.split_at(pos + 3).1.as_ref()).0
|
|
|
} else {
|
|
|
1
|
|
|
};
|
|
@@ -33,7 +34,7 @@ mod utils {
|
|
|
}
|
|
|
|
|
|
#[derive(Serialize)]
|
|
|
-struct HeloMessage {
|
|
|
+struct HelloMessage {
|
|
|
message: &'static str,
|
|
|
}
|
|
|
|
|
@@ -44,9 +45,9 @@ struct WorldRow {
|
|
|
}
|
|
|
|
|
|
#[derive(Serialize)]
|
|
|
-pub struct Fortune {
|
|
|
+pub struct Fortune<'a> {
|
|
|
id: i32,
|
|
|
- message: Cow<'static, str>,
|
|
|
+ message: &'a str,
|
|
|
}
|
|
|
|
|
|
struct PgConnectionPool {
|
|
@@ -85,9 +86,11 @@ struct PgConnection {
|
|
|
impl PgConnection {
|
|
|
fn new(db_url: &str) -> Self {
|
|
|
let client = may_postgres::connect(db_url).unwrap();
|
|
|
- let world = client.prepare("SELECT * FROM world WHERE id=$1").unwrap();
|
|
|
+ let world = client
|
|
|
+ .prepare("SELECT id, randomnumber FROM world WHERE id=$1")
|
|
|
+ .unwrap();
|
|
|
|
|
|
- let fortune = client.prepare("SELECT * FROM fortune").unwrap();
|
|
|
+ let fortune = client.prepare("SELECT id, message FROM fortune").unwrap();
|
|
|
|
|
|
let mut updates = Vec::new();
|
|
|
for num in 1..=500u16 {
|
|
@@ -125,18 +128,18 @@ impl PgConnection {
|
|
|
id: row.get(0),
|
|
|
randomnumber: row.get(1),
|
|
|
}),
|
|
|
- None => unreachable!(),
|
|
|
+ None => unreachable!("random_id={}", random_id),
|
|
|
}
|
|
|
}
|
|
|
|
|
|
fn get_worlds(
|
|
|
&self,
|
|
|
num: usize,
|
|
|
- rand: &mut Rand32,
|
|
|
+ rand: &mut WyRand,
|
|
|
) -> Result<SmallVec<[WorldRow; 32]>, may_postgres::Error> {
|
|
|
let mut queries = SmallVec::<[_; 32]>::new();
|
|
|
for _ in 0..num {
|
|
|
- let random_id = (rand.rand_u32() % 10_000 + 1) as i32;
|
|
|
+ let random_id = (rand.generate::<u32>() % 10_000 + 1) as i32;
|
|
|
queries.push(
|
|
|
self.client
|
|
|
.query_raw(&self.world, utils::slice_iter(&[&random_id]))?,
|
|
@@ -159,11 +162,11 @@ impl PgConnection {
|
|
|
fn updates(
|
|
|
&self,
|
|
|
num: usize,
|
|
|
- rand: &mut Rand32,
|
|
|
+ rand: &mut WyRand,
|
|
|
) -> Result<SmallVec<[WorldRow; 32]>, may_postgres::Error> {
|
|
|
let mut queries = SmallVec::<[_; 32]>::new();
|
|
|
for _ in 0..num {
|
|
|
- let random_id = (rand.rand_u32() % 10_000 + 1) as i32;
|
|
|
+ let random_id = (rand.generate::<u32>() % 10_000 + 1) as i32;
|
|
|
queries.push(
|
|
|
self.client
|
|
|
.query_raw(&self.world, utils::slice_iter(&[&random_id]))?,
|
|
@@ -172,7 +175,7 @@ impl PgConnection {
|
|
|
|
|
|
let mut worlds = SmallVec::<[_; 32]>::new();
|
|
|
for mut q in queries {
|
|
|
- let new_random_num = (rand.rand_u32() % 10_000 + 1) as i32;
|
|
|
+ let new_random_num = (rand.generate::<u32>() % 10_000 + 1) as i32;
|
|
|
match q.next().transpose()? {
|
|
|
Some(row) => worlds.push(WorldRow {
|
|
|
id: row.get(0),
|
|
@@ -195,32 +198,35 @@ impl PgConnection {
|
|
|
Ok(worlds)
|
|
|
}
|
|
|
|
|
|
- fn tell_fortune(&self) -> Result<Vec<Fortune>, may_postgres::Error> {
|
|
|
- let mut items = vec![Fortune {
|
|
|
- id: 0,
|
|
|
- message: Cow::Borrowed("Additional fortune added at request time."),
|
|
|
- }];
|
|
|
-
|
|
|
+ fn tell_fortune(&self, buf: &mut BytesMut) -> Result<(), may_postgres::Error> {
|
|
|
let rows = self
|
|
|
.client
|
|
|
.query_raw(&self.fortune, utils::slice_iter(&[]))?;
|
|
|
|
|
|
- for row in rows {
|
|
|
- let r = row?;
|
|
|
- items.push(Fortune {
|
|
|
+ let all_rows = rows.map(|r| r.unwrap()).collect::<Vec<_>>();
|
|
|
+ let mut fortunes = all_rows
|
|
|
+ .iter()
|
|
|
+ .map(|r| Fortune {
|
|
|
id: r.get(0),
|
|
|
- message: Cow::Owned(r.get(1)),
|
|
|
- });
|
|
|
- }
|
|
|
+ message: r.get(1),
|
|
|
+ })
|
|
|
+ .collect::<Vec<_>>();
|
|
|
+ fortunes.push(Fortune {
|
|
|
+ id: 0,
|
|
|
+ message: "Additional fortune added at request time.",
|
|
|
+ });
|
|
|
+ fortunes.sort_by(|it, next| it.message.cmp(next.message));
|
|
|
|
|
|
- items.sort_by(|it, next| it.message.cmp(&next.message));
|
|
|
- Ok(items)
|
|
|
+ let mut body = std::mem::replace(buf, BytesMut::new());
|
|
|
+ ywrite_html!(body, "{{> fortune }}");
|
|
|
+ let _ = std::mem::replace(buf, body);
|
|
|
+ Ok(())
|
|
|
}
|
|
|
}
|
|
|
|
|
|
struct Techempower {
|
|
|
db: Arc<PgConnection>,
|
|
|
- rng: Rand32,
|
|
|
+ rng: WyRand,
|
|
|
}
|
|
|
|
|
|
impl HttpService for Techempower {
|
|
@@ -229,7 +235,7 @@ impl HttpService for Techempower {
|
|
|
match req.path() {
|
|
|
"/json" => {
|
|
|
rsp.header("Content-Type: application/json");
|
|
|
- let msg = HeloMessage {
|
|
|
+ let msg = HelloMessage {
|
|
|
message: "Hello, World!",
|
|
|
};
|
|
|
msg.to_bytes_mut(rsp.body_mut());
|
|
@@ -239,16 +245,13 @@ impl HttpService for Techempower {
|
|
|
}
|
|
|
"/db" => {
|
|
|
rsp.header("Content-Type: application/json");
|
|
|
- let random_id = (self.rng.rand_u32() % 10_000 + 1) as i32;
|
|
|
+ let random_id = (self.rng.generate::<u32>() % 10_000 + 1) as i32;
|
|
|
let world = self.db.get_world(random_id).unwrap();
|
|
|
world.to_bytes_mut(rsp.body_mut())
|
|
|
}
|
|
|
"/fortunes" => {
|
|
|
rsp.header("Content-Type: text/html; charset=utf-8");
|
|
|
- let fortunes = self.db.tell_fortune().unwrap();
|
|
|
- let mut body = Vec::with_capacity(2048);
|
|
|
- ywrite_html!(body, "{{> fortune }}");
|
|
|
- rsp.body_vec(body);
|
|
|
+ self.db.tell_fortune(rsp.body_mut()).unwrap();
|
|
|
}
|
|
|
p if p.starts_with("/queries") => {
|
|
|
rsp.header("Content-Type: application/json");
|
|
@@ -279,8 +282,8 @@ impl HttpServiceFactory for HttpServer {
|
|
|
type Service = Techempower;
|
|
|
|
|
|
fn new_service(&self) -> Self::Service {
|
|
|
- let (db, idx) = self.db_pool.get_connection();
|
|
|
- let rng = Rand32::new(idx as u64);
|
|
|
+ let (db, _idx) = self.db_pool.get_connection();
|
|
|
+ let rng = WyRand::new();
|
|
|
Techempower { db, rng }
|
|
|
}
|
|
|
}
|