|
@@ -1,26 +1,28 @@
|
|
extern crate iron;
|
|
extern crate iron;
|
|
extern crate persistent;
|
|
extern crate persistent;
|
|
-#[macro_use] extern crate router;
|
|
|
|
|
|
+#[macro_use]
|
|
|
|
+extern crate router;
|
|
extern crate serde;
|
|
extern crate serde;
|
|
extern crate serde_json;
|
|
extern crate serde_json;
|
|
-#[macro_use] extern crate serde_derive;
|
|
|
|
|
|
+#[macro_use]
|
|
|
|
+extern crate serde_derive;
|
|
extern crate hyper;
|
|
extern crate hyper;
|
|
-extern crate rand;
|
|
|
|
-extern crate r2d2;
|
|
|
|
|
|
+extern crate mustache;
|
|
extern crate postgres;
|
|
extern crate postgres;
|
|
|
|
+extern crate r2d2;
|
|
extern crate r2d2_postgres;
|
|
extern crate r2d2_postgres;
|
|
-extern crate mustache;
|
|
|
|
|
|
+extern crate rand;
|
|
extern crate rustc_serialize;
|
|
extern crate rustc_serialize;
|
|
|
|
|
|
|
|
+use hyper::header::{ContentType, Server};
|
|
|
|
+use iron::modifiers::Header;
|
|
use iron::prelude::*;
|
|
use iron::prelude::*;
|
|
use iron::status;
|
|
use iron::status;
|
|
-use iron::modifiers::Header;
|
|
|
|
use iron::typemap::Key;
|
|
use iron::typemap::Key;
|
|
-use hyper::header::{Server, ContentType};
|
|
|
|
-use rand::distributions::{Range, IndependentSample};
|
|
|
|
-use r2d2_postgres::{PostgresConnectionManager, TlsMode};
|
|
|
|
-use persistent::{Read};
|
|
|
|
|
|
+use persistent::Read;
|
|
use r2d2::Pool;
|
|
use r2d2::Pool;
|
|
|
|
+use r2d2_postgres::{PostgresConnectionManager, TlsMode};
|
|
|
|
+use rand::distributions::{IndependentSample, Range};
|
|
|
|
|
|
#[derive(Serialize, Deserialize)]
|
|
#[derive(Serialize, Deserialize)]
|
|
struct Message {
|
|
struct Message {
|
|
@@ -31,61 +33,74 @@ struct Message {
|
|
#[derive(Serialize, Deserialize, Clone)]
|
|
#[derive(Serialize, Deserialize, Clone)]
|
|
struct DatabaseRow {
|
|
struct DatabaseRow {
|
|
id: i32,
|
|
id: i32,
|
|
- randomNumber: i32
|
|
|
|
|
|
+ randomNumber: i32,
|
|
}
|
|
}
|
|
|
|
|
|
struct CachedRows;
|
|
struct CachedRows;
|
|
-impl Key for CachedRows { type Value = Vec<DatabaseRow>; }
|
|
|
|
|
|
+impl Key for CachedRows {
|
|
|
|
+ type Value = Vec<DatabaseRow>;
|
|
|
|
+}
|
|
|
|
|
|
pub type PostgresPool = Pool<PostgresConnectionManager>;
|
|
pub type PostgresPool = Pool<PostgresConnectionManager>;
|
|
|
|
|
|
struct DbPool;
|
|
struct DbPool;
|
|
-impl Key for DbPool { type Value = PostgresPool; }
|
|
|
|
|
|
+impl Key for DbPool {
|
|
|
|
+ type Value = PostgresPool;
|
|
|
|
+}
|
|
|
|
|
|
struct FortuneTemplate;
|
|
struct FortuneTemplate;
|
|
-impl Key for FortuneTemplate { type Value = mustache::Template; }
|
|
|
|
|
|
+impl Key for FortuneTemplate {
|
|
|
|
+ type Value = mustache::Template;
|
|
|
|
+}
|
|
|
|
|
|
#[derive(RustcEncodable)]
|
|
#[derive(RustcEncodable)]
|
|
struct FortuneRow {
|
|
struct FortuneRow {
|
|
id: i32,
|
|
id: i32,
|
|
- message: String
|
|
|
|
|
|
+ message: String,
|
|
}
|
|
}
|
|
|
|
|
|
fn main() {
|
|
fn main() {
|
|
let r2d2_config = r2d2::Config::default();
|
|
let r2d2_config = r2d2::Config::default();
|
|
let pg_conn_manager = PostgresConnectionManager::new(
|
|
let pg_conn_manager = PostgresConnectionManager::new(
|
|
"postgres://benchmarkdbuser:benchmarkdbpass@tfb-database/hello_world",
|
|
"postgres://benchmarkdbuser:benchmarkdbpass@tfb-database/hello_world",
|
|
- TlsMode::None).unwrap();
|
|
|
|
|
|
+ TlsMode::None,
|
|
|
|
+ )
|
|
|
|
+ .unwrap();
|
|
let pool = r2d2::Pool::new(r2d2_config, pg_conn_manager).unwrap();
|
|
let pool = r2d2::Pool::new(r2d2_config, pg_conn_manager).unwrap();
|
|
- let template = mustache::compile_str("<!DOCTYPE html>
|
|
|
|
|
|
+ let template = mustache::compile_str(
|
|
|
|
+ "<!DOCTYPE html>
|
|
<html> <head><title>Fortunes</title></head>
|
|
<html> <head><title>Fortunes</title></head>
|
|
<body> <table>
|
|
<body> <table>
|
|
<tr><th>id</th><th>message</th></tr>
|
|
<tr><th>id</th><th>message</th></tr>
|
|
{{#.}} <tr><td>{{id}}</td><td>{{message}}</td></tr>
|
|
{{#.}} <tr><td>{{id}}</td><td>{{message}}</td></tr>
|
|
{{/.}}
|
|
{{/.}}
|
|
- </table> </body> </html>").unwrap();
|
|
|
|
|
|
+ </table> </body> </html>",
|
|
|
|
+ )
|
|
|
|
+ .unwrap();
|
|
|
|
|
|
let mut cached_rows: Vec<DatabaseRow> = Vec::with_capacity(10000);
|
|
let mut cached_rows: Vec<DatabaseRow> = Vec::with_capacity(10000);
|
|
let conn = pool.get().unwrap();
|
|
let conn = pool.get().unwrap();
|
|
|
|
|
|
for num in 1..10000 {
|
|
for num in 1..10000 {
|
|
- let rows = &conn.query("SELECT id, randomnumber FROM World WHERE id = $1",&[&num]).unwrap();
|
|
|
|
|
|
+ let rows = &conn
|
|
|
|
+ .query("SELECT id, randomnumber FROM World WHERE id = $1", &[&num])
|
|
|
|
+ .unwrap();
|
|
let row = rows.get(0);
|
|
let row = rows.get(0);
|
|
cached_rows.push(DatabaseRow {
|
|
cached_rows.push(DatabaseRow {
|
|
id: row.get(0),
|
|
id: row.get(0),
|
|
- randomNumber: row.get(1)
|
|
|
|
|
|
+ randomNumber: row.get(1),
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
let app = router!(
|
|
let app = router!(
|
|
- json: get "/json" => json_handler,
|
|
|
|
- single_db_query: get "/db" => single_db_query_handler,
|
|
|
|
- plaintext: get "/plaintext" => plaintext_handler,
|
|
|
|
- queries: get "/queries" => queries_handler,
|
|
|
|
- cachedworlds: get "/cached-worlds" => cached_queries_handler,
|
|
|
|
- fortune: get "/fortune" => fortune_handler,
|
|
|
|
- updates: get "/updates" => updates_handler
|
|
|
|
- );
|
|
|
|
|
|
+ json: get "/json" => json_handler,
|
|
|
|
+ single_db_query: get "/db" => single_db_query_handler,
|
|
|
|
+ plaintext: get "/plaintext" => plaintext_handler,
|
|
|
|
+ queries: get "/queries" => queries_handler,
|
|
|
|
+ cachedworlds: get "/cached-worlds" => cached_queries_handler,
|
|
|
|
+ fortune: get "/fortune" => fortune_handler,
|
|
|
|
+ updates: get "/updates" => updates_handler
|
|
|
|
+ );
|
|
let mut middleware = Chain::new(app);
|
|
let mut middleware = Chain::new(app);
|
|
middleware.link(Read::<DbPool>::both(pool));
|
|
middleware.link(Read::<DbPool>::both(pool));
|
|
middleware.link(Read::<FortuneTemplate>::both(template));
|
|
middleware.link(Read::<FortuneTemplate>::both(template));
|
|
@@ -96,25 +111,22 @@ fn main() {
|
|
}
|
|
}
|
|
|
|
|
|
fn json_handler(_: &mut Request) -> IronResult<Response> {
|
|
fn json_handler(_: &mut Request) -> IronResult<Response> {
|
|
- let message: Message = Message {
|
|
|
|
- message: "Hello, World!".to_owned()
|
|
|
|
|
|
+ let message: Message = Message {
|
|
|
|
+ message: "Hello, World!".to_owned(),
|
|
};
|
|
};
|
|
let content_type = Header(ContentType::json());
|
|
let content_type = Header(ContentType::json());
|
|
let server = Header(Server("Iron".to_owned()));
|
|
let server = Header(Server("Iron".to_owned()));
|
|
- Ok(Response::with(
|
|
|
|
- (status::Ok,
|
|
|
|
|
|
+ Ok(Response::with((
|
|
|
|
+ status::Ok,
|
|
serde_json::to_string(&message).unwrap(),
|
|
serde_json::to_string(&message).unwrap(),
|
|
content_type,
|
|
content_type,
|
|
- server
|
|
|
|
- )))
|
|
|
|
|
|
+ server,
|
|
|
|
+ )))
|
|
}
|
|
}
|
|
|
|
|
|
fn plaintext_handler(_: &mut Request) -> IronResult<Response> {
|
|
fn plaintext_handler(_: &mut Request) -> IronResult<Response> {
|
|
let server = Header(Server("Iron".to_owned()));
|
|
let server = Header(Server("Iron".to_owned()));
|
|
- Ok(Response::with((
|
|
|
|
- status::Ok,
|
|
|
|
- "Hello, World!",
|
|
|
|
- server)))
|
|
|
|
|
|
+ Ok(Response::with((status::Ok, "Hello, World!", server)))
|
|
}
|
|
}
|
|
|
|
|
|
fn single_db_query_handler(req: &mut Request) -> IronResult<Response> {
|
|
fn single_db_query_handler(req: &mut Request) -> IronResult<Response> {
|
|
@@ -127,8 +139,8 @@ fn single_db_query_handler(req: &mut Request) -> IronResult<Response> {
|
|
status::Ok,
|
|
status::Ok,
|
|
serde_json::to_string(&row).unwrap(),
|
|
serde_json::to_string(&row).unwrap(),
|
|
server,
|
|
server,
|
|
- content_type
|
|
|
|
- )))
|
|
|
|
|
|
+ content_type,
|
|
|
|
+ )))
|
|
}
|
|
}
|
|
|
|
|
|
fn queries_handler(req: &mut Request) -> IronResult<Response> {
|
|
fn queries_handler(req: &mut Request) -> IronResult<Response> {
|
|
@@ -141,23 +153,22 @@ fn queries_handler(req: &mut Request) -> IronResult<Response> {
|
|
Ok(m) => match m {
|
|
Ok(m) => match m {
|
|
e @ 1...500 => e,
|
|
e @ 1...500 => e,
|
|
e if e > 500 => 500,
|
|
e if e > 500 => 500,
|
|
- _ => 1
|
|
|
|
|
|
+ _ => 1,
|
|
},
|
|
},
|
|
- _ => 1
|
|
|
|
|
|
+ _ => 1,
|
|
},
|
|
},
|
|
- _ => 1
|
|
|
|
|
|
+ _ => 1,
|
|
};
|
|
};
|
|
let mut res: Vec<DatabaseRow> = Vec::with_capacity(param);
|
|
let mut res: Vec<DatabaseRow> = Vec::with_capacity(param);
|
|
for _ in 0..param {
|
|
for _ in 0..param {
|
|
let conn = pool.get().unwrap();
|
|
let conn = pool.get().unwrap();
|
|
res.push(random_row(conn))
|
|
res.push(random_row(conn))
|
|
- };
|
|
|
|
- Ok(
|
|
|
|
- Response::with((
|
|
|
|
- status::Ok,
|
|
|
|
- serde_json::to_string(&res).unwrap(),
|
|
|
|
- server,
|
|
|
|
- content_type
|
|
|
|
|
|
+ }
|
|
|
|
+ Ok(Response::with((
|
|
|
|
+ status::Ok,
|
|
|
|
+ serde_json::to_string(&res).unwrap(),
|
|
|
|
+ server,
|
|
|
|
+ content_type,
|
|
)))
|
|
)))
|
|
}
|
|
}
|
|
|
|
|
|
@@ -171,26 +182,25 @@ fn cached_queries_handler(req: &mut Request) -> IronResult<Response> {
|
|
Ok(m) => match m {
|
|
Ok(m) => match m {
|
|
e @ 1...500 => e,
|
|
e @ 1...500 => e,
|
|
e if e > 500 => 500,
|
|
e if e > 500 => 500,
|
|
- _ => 1
|
|
|
|
|
|
+ _ => 1,
|
|
},
|
|
},
|
|
- _ => 1
|
|
|
|
|
|
+ _ => 1,
|
|
},
|
|
},
|
|
- _ => 1
|
|
|
|
|
|
+ _ => 1,
|
|
};
|
|
};
|
|
|
|
|
|
let mut res: Vec<DatabaseRow> = Vec::with_capacity(param);
|
|
let mut res: Vec<DatabaseRow> = Vec::with_capacity(param);
|
|
for _ in 0..param {
|
|
for _ in 0..param {
|
|
let mut rng = rand::thread_rng();
|
|
let mut rng = rand::thread_rng();
|
|
- let between = Range::new(1,10000);
|
|
|
|
|
|
+ let between = Range::new(1, 10000);
|
|
let num = between.ind_sample(&mut rng);
|
|
let num = between.ind_sample(&mut rng);
|
|
res.push(cached_rows[num].to_owned())
|
|
res.push(cached_rows[num].to_owned())
|
|
- };
|
|
|
|
- Ok(
|
|
|
|
- Response::with((
|
|
|
|
- status::Ok,
|
|
|
|
- serde_json::to_string(&res).unwrap(),
|
|
|
|
- server,
|
|
|
|
- content_type
|
|
|
|
|
|
+ }
|
|
|
|
+ Ok(Response::with((
|
|
|
|
+ status::Ok,
|
|
|
|
+ serde_json::to_string(&res).unwrap(),
|
|
|
|
+ server,
|
|
|
|
+ content_type,
|
|
)))
|
|
)))
|
|
}
|
|
}
|
|
|
|
|
|
@@ -200,31 +210,27 @@ fn fortune_handler(req: &mut Request) -> IronResult<Response> {
|
|
let template = req.get::<Read<FortuneTemplate>>().unwrap();
|
|
let template = req.get::<Read<FortuneTemplate>>().unwrap();
|
|
let pool = req.get::<Read<DbPool>>().unwrap();
|
|
let pool = req.get::<Read<DbPool>>().unwrap();
|
|
let conn = pool.get().unwrap();
|
|
let conn = pool.get().unwrap();
|
|
- let query_res = &conn.query("SELECT id, message FROM Fortune",&[]).unwrap();
|
|
|
|
|
|
+ let query_res = &conn.query("SELECT id, message FROM Fortune", &[]).unwrap();
|
|
let query_res_iter = query_res.iter();
|
|
let query_res_iter = query_res.iter();
|
|
- let mut rows: Vec<FortuneRow> = query_res_iter.map(|row| FortuneRow {
|
|
|
|
- id: row.get(0),
|
|
|
|
- message: row.get(1)
|
|
|
|
- }).collect();
|
|
|
|
|
|
+ let mut rows: Vec<FortuneRow> = query_res_iter
|
|
|
|
+ .map(|row| FortuneRow {
|
|
|
|
+ id: row.get(0),
|
|
|
|
+ message: row.get(1),
|
|
|
|
+ })
|
|
|
|
+ .collect();
|
|
rows.push(FortuneRow {
|
|
rows.push(FortuneRow {
|
|
id: 0,
|
|
id: 0,
|
|
- message: "Additional fortune added at request time.".to_string()
|
|
|
|
|
|
+ message: "Additional fortune added at request time.".to_string(),
|
|
});
|
|
});
|
|
rows.sort_by(|it, next| it.message.cmp(&next.message));
|
|
rows.sort_by(|it, next| it.message.cmp(&next.message));
|
|
let mut res = vec![];
|
|
let mut res = vec![];
|
|
template.render(&mut res, &rows).unwrap();
|
|
template.render(&mut res, &rows).unwrap();
|
|
- Ok(
|
|
|
|
- Response::with((
|
|
|
|
- status::Ok,
|
|
|
|
- res,
|
|
|
|
- server,
|
|
|
|
- content_type
|
|
|
|
- )))
|
|
|
|
|
|
+ Ok(Response::with((status::Ok, res, server, content_type)))
|
|
}
|
|
}
|
|
|
|
|
|
fn updates_handler(req: &mut Request) -> IronResult<Response> {
|
|
fn updates_handler(req: &mut Request) -> IronResult<Response> {
|
|
let mut rng = rand::thread_rng();
|
|
let mut rng = rand::thread_rng();
|
|
- let between = Range::new(1,10000);
|
|
|
|
|
|
+ let between = Range::new(1, 10000);
|
|
let content_type = Header(ContentType::json());
|
|
let content_type = Header(ContentType::json());
|
|
let server = Header(Server("Iron".to_owned()));
|
|
let server = Header(Server("Iron".to_owned()));
|
|
let pool = req.get::<Read<DbPool>>().unwrap();
|
|
let pool = req.get::<Read<DbPool>>().unwrap();
|
|
@@ -234,58 +240,64 @@ fn updates_handler(req: &mut Request) -> IronResult<Response> {
|
|
Ok(m) => match m {
|
|
Ok(m) => match m {
|
|
e @ 1...500 => e,
|
|
e @ 1...500 => e,
|
|
e if e > 500 => 500,
|
|
e if e > 500 => 500,
|
|
- _ => 1
|
|
|
|
|
|
+ _ => 1,
|
|
},
|
|
},
|
|
- _ => 1
|
|
|
|
|
|
+ _ => 1,
|
|
},
|
|
},
|
|
- _ => 1
|
|
|
|
|
|
+ _ => 1,
|
|
};
|
|
};
|
|
let mut dbres: Vec<DatabaseRow> = Vec::with_capacity(param);
|
|
let mut dbres: Vec<DatabaseRow> = Vec::with_capacity(param);
|
|
for _ in 0..param {
|
|
for _ in 0..param {
|
|
let conn = pool.get().unwrap();
|
|
let conn = pool.get().unwrap();
|
|
dbres.push(random_row(conn))
|
|
dbres.push(random_row(conn))
|
|
- };
|
|
|
|
|
|
+ }
|
|
let conn = pool.get().unwrap();
|
|
let conn = pool.get().unwrap();
|
|
let trans = conn.transaction().unwrap();
|
|
let trans = conn.transaction().unwrap();
|
|
// Sorting guarantees no deadlocks between multiple concurrent threads
|
|
// Sorting guarantees no deadlocks between multiple concurrent threads
|
|
- dbres.sort_by_key(|it| it.id );
|
|
|
|
|
|
+ dbres.sort_by_key(|it| it.id);
|
|
let mut res: Vec<DatabaseRow> = Vec::with_capacity(param);
|
|
let mut res: Vec<DatabaseRow> = Vec::with_capacity(param);
|
|
for row in dbres {
|
|
for row in dbres {
|
|
let num = between.ind_sample(&mut rng);
|
|
let num = between.ind_sample(&mut rng);
|
|
- trans.execute("UPDATE World SET randomnumber = $1 WHERE id = $2", &[&num, &row.id]).unwrap();
|
|
|
|
|
|
+ trans
|
|
|
|
+ .execute(
|
|
|
|
+ "UPDATE World SET randomnumber = $1 WHERE id = $2",
|
|
|
|
+ &[&num, &row.id],
|
|
|
|
+ )
|
|
|
|
+ .unwrap();
|
|
res.push(DatabaseRow {
|
|
res.push(DatabaseRow {
|
|
id: row.id,
|
|
id: row.id,
|
|
- randomNumber: num
|
|
|
|
|
|
+ randomNumber: num,
|
|
})
|
|
})
|
|
}
|
|
}
|
|
trans.commit().unwrap();
|
|
trans.commit().unwrap();
|
|
- Ok(
|
|
|
|
- Response::with((
|
|
|
|
- status::Ok,
|
|
|
|
- serde_json::to_string(&res).unwrap(),
|
|
|
|
- server,
|
|
|
|
- content_type
|
|
|
|
|
|
+ Ok(Response::with((
|
|
|
|
+ status::Ok,
|
|
|
|
+ serde_json::to_string(&res).unwrap(),
|
|
|
|
+ server,
|
|
|
|
+ content_type,
|
|
)))
|
|
)))
|
|
}
|
|
}
|
|
|
|
|
|
fn random_row(conn: r2d2::PooledConnection<PostgresConnectionManager>) -> DatabaseRow {
|
|
fn random_row(conn: r2d2::PooledConnection<PostgresConnectionManager>) -> DatabaseRow {
|
|
let mut rng = rand::thread_rng();
|
|
let mut rng = rand::thread_rng();
|
|
- let between = Range::new(1,10000);
|
|
|
|
|
|
+ let between = Range::new(1, 10000);
|
|
let num = between.ind_sample(&mut rng);
|
|
let num = between.ind_sample(&mut rng);
|
|
- let rows = &conn.query("SELECT id, randomnumber FROM World WHERE id = $1",&[&num]).unwrap();
|
|
|
|
|
|
+ let rows = &conn
|
|
|
|
+ .query("SELECT id, randomnumber FROM World WHERE id = $1", &[&num])
|
|
|
|
+ .unwrap();
|
|
let row = rows.get(0);
|
|
let row = rows.get(0);
|
|
DatabaseRow {
|
|
DatabaseRow {
|
|
id: row.get(0),
|
|
id: row.get(0),
|
|
- randomNumber: row.get(1)
|
|
|
|
|
|
+ randomNumber: row.get(1),
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
fn get_param<'a>(querystring: &'a str, param: &'a str) -> Option<&'a str> {
|
|
fn get_param<'a>(querystring: &'a str, param: &'a str) -> Option<&'a str> {
|
|
- let n = querystring.split("&").find(
|
|
|
|
- |&it| !(it.find(param).is_none())
|
|
|
|
- );
|
|
|
|
|
|
+ let n = querystring
|
|
|
|
+ .split("&")
|
|
|
|
+ .find(|&it| !(it.find(param).is_none()));
|
|
match n {
|
|
match n {
|
|
Some(n) => n.split("=").nth(1),
|
|
Some(n) => n.split("=").nth(1),
|
|
- _ => n
|
|
|
|
|
|
+ _ => n,
|
|
}
|
|
}
|
|
}
|
|
}
|