소스 검색

Upgrade to actix-web 1.0.0 (#4593)

* upgrade to 2018 edition

* upgrade actix-web

* upgrade askama

* consdtruct Response directly

* use Server directly

* simplify connection selection

* update deps

* fix server bind call and query parsing

* fix platform fortunes test

* remove unneeded sort

* disable logging
Nikolay Kim 6 년 전
부모
커밋
03e3c4effa

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 438 - 262
frameworks/Rust/actix/Cargo.lock


+ 17 - 16
frameworks/Rust/actix/Cargo.toml

@@ -1,15 +1,15 @@
 [package]
 name = "actix"
-version = "0.7.2"
-build = "build.rs"
+version = "1.0.0"
+edition = "2018"
 
 [[bin]]
 name = "actix"
 path = "src/main.rs"
 
 [[bin]]
-name = "actix-raw"
-path = "src/main_raw.rs"
+name = "actix-platform"
+path = "src/main_platform.rs"
 
 [[bin]]
 name = "actix-diesel"
@@ -20,32 +20,33 @@ name = "actix-pg"
 path = "src/main_pg.rs"
 
 [dependencies]
-askama = "0.7"
+actix = { version="0.8.0-alpha.2", features=["http"] }
+actix-web = { version="1.0.0-alpha.2", default-features = false }
+actix-http = { version="0.1.0-alpha.2", default-features = false }
+actix-rt = "0.2.2"
+actix-server = "0.4.2"
+actix-service = "0.3.5"
+
+askama = "0.8"
 serde = "1.0"
 serde_json = "1.0"
 serde_derive = "1.0"
+env_logger = "0.6"
 rand = "0.5"
 bytes = "0.4"
 num_cpus = "1.0"
-futures = "0.1"
+futures = "0.1.25"
 http = "0.1"
 diesel = { version = "1.2", features = ["postgres"] }
 url = { version="1.7", features=["query_encoding"] }
-
-actix = "0.7"
-actix-web = { version="0.7", default-features = false }
-
+log = { version = "0.4", features = ["release_max_level_off"] }
 phf = "0.7.22"
 tokio-postgres = { git="https://github.com/fafhrd91/rust-postgres.git" }
 
-[patch.crates-io]
-tokio-io = { git="https://github.com/tokio-rs/tokio.git" }
-tokio-uds = { git="https://github.com/tokio-rs/tokio.git" }
-
 [build-dependencies]
-askama = "0.7"
+askama = "0.8"
 
 [profile.release]
 lto = true
 opt-level = 3
-codegen-units = 1
+codegen-units = 1

+ 2 - 2
frameworks/Rust/actix/README.md

@@ -29,7 +29,7 @@ PostgreSQL.
 
 ## Test URLs
 
-### Test 1: JSON Encoding 
+### Test 1: JSON Encoding
 
     http://localhost:8080/json
 
@@ -37,7 +37,7 @@ PostgreSQL.
 
     http://localhost:8080/db
 
-### Test 3: Multi Row Query 
+### Test 3: Multi Row Query
 
     http://localhost:8080/queries?q=20
 

+ 1 - 1
frameworks/Rust/actix/actix-diesel.dockerfile

@@ -1,4 +1,4 @@
-FROM rust:1.29.1
+FROM rust:1.33.0
 
 ADD ./ /actix
 WORKDIR /actix

+ 1 - 1
frameworks/Rust/actix/actix-pg.dockerfile

@@ -1,4 +1,4 @@
-FROM rust:1.29.1
+FROM rust:1.33.0
 
 ADD ./ /actix
 WORKDIR /actix

+ 2 - 2
frameworks/Rust/actix/actix-raw.dockerfile → frameworks/Rust/actix/actix-platform.dockerfile

@@ -1,4 +1,4 @@
-FROM rust:1.29.1
+FROM rust:1.33.0
 
 ADD ./ /actix
 WORKDIR /actix
@@ -6,4 +6,4 @@ WORKDIR /actix
 RUN cargo clean
 RUN RUSTFLAGS="-C target-cpu=native" cargo build --release
 
-CMD ./target/release/actix-raw
+CMD ./target/release/actix-platform

+ 1 - 1
frameworks/Rust/actix/actix.dockerfile

@@ -1,4 +1,4 @@
-FROM rust:1.29.1
+FROM rust:1.33.0
 
 ADD ./ /actix
 WORKDIR /actix

+ 1 - 1
frameworks/Rust/actix/benchmark_config.json

@@ -19,7 +19,7 @@
       "notes": "",
       "versus": ""
     },
-    "raw": {
+    "platform": {
       "fortune_url": "/fortune",
       "json_url": "/json",
       "plaintext_url": "/plaintext",

+ 0 - 5
frameworks/Rust/actix/build.rs

@@ -1,5 +0,0 @@
-extern crate askama;
-
-fn main() {
-    askama::rerun_if_templates_changed();
-}

+ 0 - 3
frameworks/Rust/actix/rustfmt.toml

@@ -1,5 +1,2 @@
 max_width = 89
 reorder_imports = true
-wrap_comments = true
-fn_args_density = "Compressed"
-#use_small_heuristics = false

+ 11 - 10
frameworks/Rust/actix/src/db.rs

@@ -1,12 +1,13 @@
 //! Db executor actor
+use std::io;
+
 use actix::prelude::*;
 use diesel;
 use diesel::prelude::*;
 use diesel::result::Error;
 use rand::{thread_rng, Rng, ThreadRng};
-use std::io;
 
-use models;
+use crate::models;
 
 pub struct DbExecutor {
     conn: PgConnection,
@@ -39,7 +40,7 @@ impl Handler<RandomWorld> for DbExecutor {
     type Result = io::Result<models::World>;
 
     fn handle(&mut self, _: RandomWorld, _: &mut Self::Context) -> Self::Result {
-        use schema::world::dsl::*;
+        use crate::schema::world::dsl::*;
 
         let random_id = self.rng.gen_range(1, 10_001);
         match world
@@ -62,7 +63,7 @@ impl Handler<RandomWorlds> for DbExecutor {
     type Result = io::Result<Vec<models::World>>;
 
     fn handle(&mut self, msg: RandomWorlds, _: &mut Self::Context) -> Self::Result {
-        use schema::world::dsl::*;
+        use crate::schema::world::dsl::*;
 
         let mut worlds = Vec::with_capacity(msg.0 as usize);
         for _ in 0..msg.0 {
@@ -70,7 +71,7 @@ impl Handler<RandomWorlds> for DbExecutor {
             let w = match world.filter(id.eq(w_id)).load::<models::World>(&self.conn) {
                 Ok(mut items) => items.pop().unwrap(),
                 Err(_) => {
-                    return Err(io::Error::new(io::ErrorKind::Other, "Database error"))
+                    return Err(io::Error::new(io::ErrorKind::Other, "Database error"));
                 }
             };
             worlds.push(w)
@@ -79,7 +80,7 @@ impl Handler<RandomWorlds> for DbExecutor {
     }
 }
 
-pub struct UpdateWorld(pub usize);
+pub struct UpdateWorld(pub u16);
 
 impl Message for UpdateWorld {
     type Result = io::Result<Vec<models::World>>;
@@ -89,16 +90,16 @@ impl Handler<UpdateWorld> for DbExecutor {
     type Result = io::Result<Vec<models::World>>;
 
     fn handle(&mut self, msg: UpdateWorld, _: &mut Self::Context) -> Self::Result {
-        use schema::world::dsl::*;
+        use crate::schema::world::dsl::*;
 
-        let mut worlds = Vec::with_capacity(msg.0);
+        let mut worlds = Vec::with_capacity(msg.0 as usize);
         for _ in 0..msg.0 {
             let w_id = self.rng.gen_range::<i32>(1, 10_001);
             let mut w = match world.filter(id.eq(w_id)).load::<models::World>(&self.conn)
             {
                 Ok(mut items) => items.pop().unwrap(),
                 Err(_) => {
-                    return Err(io::Error::new(io::ErrorKind::Other, "Database error"))
+                    return Err(io::Error::new(io::ErrorKind::Other, "Database error"));
                 }
             };
             w.randomnumber = self.rng.gen_range(1, 10_001);
@@ -130,7 +131,7 @@ impl Handler<TellFortune> for DbExecutor {
     type Result = io::Result<Vec<models::Fortune>>;
 
     fn handle(&mut self, _: TellFortune, _: &mut Self::Context) -> Self::Result {
-        use schema::fortune::dsl::*;
+        use crate::schema::fortune::dsl::*;
 
         match fortune.load::<models::Fortune>(&self.conn) {
             Ok(mut items) => {

+ 6 - 15
frameworks/Rust/actix/src/db_pg.rs

@@ -6,14 +6,13 @@ use futures::{stream, Future, Stream};
 use rand::{thread_rng, Rng, ThreadRng};
 use tokio_postgres::{connect, Client, Statement, TlsMode};
 
-use models::{Fortune, World};
+use crate::models::{Fortune, World};
 
 /// Postgres interface
 pub struct PgConnection {
     cl: Option<Client>,
     fortune: Option<Statement>,
     world: Option<Statement>,
-    update: Option<Statement>,
     rng: ThreadRng,
 }
 
@@ -30,7 +29,6 @@ impl PgConnection {
                 cl: None,
                 fortune: None,
                 world: None,
-                update: None,
                 rng: thread_rng(),
             };
 
@@ -55,20 +53,12 @@ impl PgConnection {
                                 fut::ok(())
                             }),
                     );
-                    ctx.wait(
-                        cl.prepare("SELECT id FROM world WHERE id=$1")
-                            .map_err(|_| ())
-                            .into_actor(act)
-                            .and_then(|st, act, _| {
-                                act.update = Some(st);
-                                fut::ok(())
-                            }),
-                    );
 
                     act.cl = Some(cl);
                     Arbiter::spawn(conn.map_err(|e| panic!("{}", e)));
                     fut::ok(())
-                }).wait(ctx);
+                })
+                .wait(ctx);
 
             act
         })
@@ -157,7 +147,7 @@ impl Handler<UpdateWorld> for PgConnection {
                 self.cl
                     .as_mut()
                     .unwrap()
-                    .query(self.update.as_ref().unwrap(), &[&w_id])
+                    .query(self.world.as_ref().unwrap(), &[&w_id])
                     .into_future()
                     .map_err(|e| io::Error::new(io::ErrorKind::Other, e.0))
                     .and_then(move |(row, _)| {
@@ -227,7 +217,8 @@ impl Handler<TellFortune> for PgConnection {
                         message: row.get(1),
                     });
                     Ok::<_, io::Error>(items)
-                }).map_err(|e| io::Error::new(io::ErrorKind::Other, e))
+                })
+                .map_err(|e| io::Error::new(io::ErrorKind::Other, e))
                 .and_then(|mut items| {
                     items.sort_by(|it, next| it.message.cmp(&next.message));
                     Ok(items)

+ 33 - 35
frameworks/Rust/actix/src/db_pg_direct.rs

@@ -1,18 +1,18 @@
 use std::io;
 
-use actix::prelude::*;
+use futures::future::join_all;
 use futures::{stream, Future, Stream};
-use rand::{thread_rng, Rng};
+use rand::{thread_rng, Rng, ThreadRng};
 use tokio_postgres::{connect, Client, Statement, TlsMode};
 
-use models::{Fortune, World};
+use crate::models::{Fortune, World};
 
 /// Postgres interface
 pub struct PgConnection {
     cl: Client,
     fortune: Statement,
     world: Statement,
-    update: Statement,
+    rng: ThreadRng,
 }
 
 impl PgConnection {
@@ -21,33 +21,30 @@ impl PgConnection {
 
         hs.map_err(|_| panic!("can not connect to postgresql"))
             .and_then(|(cl, conn)| {
-                Arbiter::spawn(conn.map_err(|e| panic!("{}", e)));
-                cl.prepare("SELECT id, message FROM fortune")
-                    .map_err(|_| ())
-                    .and_then(move |fortune| {
-                        cl.prepare("SELECT id, randomnumber FROM world WHERE id=$1")
-                            .map_err(|_| ())
-                            .and_then(move |world| {
-                                let st = (fortune, world);
-                                cl.prepare("SELECT id FROM world WHERE id=$1")
-                                    .map_err(|_| ())
-                                    .and_then(|update| {
-                                        Ok(PgConnection {
-                                            cl,
-                                            fortune: st.0,
-                                            world: st.1,
-                                            update,
-                                        })
-                                    })
-                            })
-                    })
+                actix_rt::spawn(conn.map_err(|e| panic!("{}", e)));
+
+                join_all(vec![
+                    cl.prepare("SELECT id, message FROM fortune"),
+                    cl.prepare("SELECT id, randomnumber FROM world WHERE id=$1"),
+                ])
+                .map_err(|_| ())
+                .map(move |mut st| {
+                    let world = st.pop().unwrap();
+                    let fortune = st.pop().unwrap();
+                    PgConnection {
+                        cl,
+                        fortune,
+                        world,
+                        rng: thread_rng(),
+                    }
+                })
             })
     }
 }
 
 impl PgConnection {
-    pub fn get_world(&self) -> impl Future<Item = World, Error = io::Error> {
-        let random_id = thread_rng().gen_range::<i32>(1, 10_001);
+    pub fn get_world(&mut self) -> impl Future<Item = World, Error = io::Error> {
+        let random_id = self.rng.gen_range::<i32>(1, 10_001);
 
         self.cl
             .query(&self.world, &[&random_id])
@@ -63,11 +60,12 @@ impl PgConnection {
     }
 
     pub fn get_worlds(
-        &self, num: usize,
+        &mut self,
+        num: usize,
     ) -> impl Future<Item = Vec<World>, Error = io::Error> {
         let mut worlds = Vec::with_capacity(num);
         for _ in 0..num {
-            let w_id: i32 = thread_rng().gen_range(1, 10_001);
+            let w_id: i32 = self.rng.gen_range(1, 10_001);
             worlds.push(
                 self.cl
                     .query(&self.world, &[&w_id])
@@ -87,15 +85,16 @@ impl PgConnection {
     }
 
     pub fn update(
-        &self, num: usize,
+        &mut self,
+        num: usize,
     ) -> impl Future<Item = Vec<World>, Error = io::Error> {
         let mut worlds = Vec::with_capacity(num);
         for _ in 0..num {
-            let id: i32 = thread_rng().gen_range(1, 10_001);
-            let w_id: i32 = thread_rng().gen_range(1, 10_001);
+            let id: i32 = self.rng.gen_range(1, 10_001);
+            let w_id: i32 = self.rng.gen_range(1, 10_001);
             worlds.push(
                 self.cl
-                    .query(&self.update, &[&w_id])
+                    .query(&self.world, &[&w_id])
                     .into_future()
                     .map_err(|e| io::Error::new(io::ErrorKind::Other, e.0))
                     .and_then(move |(row, _)| {
@@ -120,8 +119,6 @@ impl PgConnection {
                 for w in &worlds {
                     update.push_str(&format!("({}, {}),", w.id, w.randomnumber));
                 }
-                worlds.sort_by_key(|w| w.id);
-
                 update.pop();
                 update.push_str(
                     " ORDER BY 1) AS temp(id, randomnumber) WHERE temp.id = world.id",
@@ -148,7 +145,8 @@ impl PgConnection {
                     message: row.get(1),
                 });
                 Ok::<_, io::Error>(items)
-            }).map_err(|e| io::Error::new(io::ErrorKind::Other, e))
+            })
+            .map_err(|e| io::Error::new(io::ErrorKind::Other, e))
             .and_then(|mut items| {
                 items.sort_by(|it, next| it.message.cmp(&next.message));
                 Ok(items)

+ 35 - 31
frameworks/Rust/actix/src/main.rs

@@ -1,53 +1,57 @@
-extern crate actix;
-extern crate actix_web;
-extern crate bytes;
-extern crate futures;
-extern crate serde;
-extern crate serde_json;
-extern crate url;
 #[macro_use]
 extern crate serde_derive;
 
-use actix::prelude::*;
-use actix_web::{http, server, App, HttpRequest, HttpResponse};
-use bytes::BytesMut;
+use actix_http::{HttpService, KeepAlive};
+use actix_server::Server;
+use actix_web::dev::Body;
+use actix_web::http::{header::CONTENT_TYPE, header::SERVER, HeaderValue, StatusCode};
+use actix_web::{web, App, HttpResponse};
+use bytes::{Bytes, BytesMut};
 
 mod utils;
 use utils::{Message, Writer, SIZE};
 
-fn json(req: &HttpRequest) -> HttpResponse {
+fn json() -> HttpResponse {
     let message = Message {
         message: "Hello, World!",
     };
     let mut body = BytesMut::with_capacity(SIZE);
     serde_json::to_writer(Writer(&mut body), &message).unwrap();
 
-    HttpResponse::build_from(req)
-        .header(http::header::SERVER, "Actix")
-        .header(http::header::CONTENT_TYPE, "application/json")
-        .body(body)
+    let mut res = HttpResponse::with_body(StatusCode::OK, Body::Bytes(body.freeze()));
+    res.headers_mut()
+        .insert(SERVER, HeaderValue::from_static("Actix"));
+    res.headers_mut()
+        .insert(CONTENT_TYPE, HeaderValue::from_static("application/json"));
+    res
 }
 
-fn plaintext(req: &HttpRequest) -> HttpResponse {
-    HttpResponse::build_from(req)
-        .header(http::header::SERVER, "Actix")
-        .header(http::header::CONTENT_TYPE, "text/plain")
-        .body("Hello, World!")
+fn plaintext() -> HttpResponse {
+    let mut res = HttpResponse::with_body(
+        StatusCode::OK,
+        Body::Bytes(Bytes::from_static(b"Hello, World!")),
+    );
+    res.headers_mut()
+        .insert(SERVER, HeaderValue::from_static("Actix"));
+    res.headers_mut()
+        .insert(CONTENT_TYPE, HeaderValue::from_static("text/plain"));
+    res
 }
 
-fn main() {
-    let sys = System::new("techempower");
+fn main() -> std::io::Result<()> {
+    env_logger::init();
+    let sys = actix_rt::System::new("techempower");
 
     // start http server
-    server::new(move || {
-        App::new()
-            .resource("/json", |r| r.f(json))
-            .resource("/plaintext", |r| r.f(plaintext))
-    }).backlog(8192)
-    .bind("0.0.0.0:8080")
-    .unwrap()
-    .start();
+    Server::build()
+        .backlog(1024)
+        .bind("techempower", "0.0.0.0:8080", || {
+            HttpService::build().keep_alive(KeepAlive::Os).h1(App::new()
+                .service(web::resource("/json").to(json))
+                .service(web::resource("/plaintext").to(plaintext)))
+        })?
+        .start();
 
     println!("Started http server: 127.0.0.1:8080");
-    let _ = sys.run();
+    sys.run()
 }

+ 57 - 94
frameworks/Rust/actix/src/main_diesel.rs

@@ -1,28 +1,15 @@
-extern crate actix;
-extern crate actix_web;
-extern crate bytes;
-extern crate futures;
-extern crate num_cpus;
-extern crate rand;
-extern crate serde;
-extern crate serde_json;
 #[macro_use]
 extern crate serde_derive;
 #[macro_use]
 extern crate diesel;
-#[macro_use]
-extern crate askama;
-extern crate url;
 
 use actix::prelude::*;
-use actix_web::{
-    http, server, App, AsyncResponder, FutureResponse, HttpRequest, HttpResponse,
-};
+use actix_http::{HttpService, KeepAlive};
+use actix_server::Server;
+use actix_web::{http, web, App, Error, HttpRequest, HttpResponse};
 use askama::Template;
 use bytes::BytesMut;
-use diesel::prelude::{Connection, PgConnection};
 use futures::Future;
-use std::cmp;
 
 mod db;
 mod models;
@@ -30,84 +17,68 @@ mod schema;
 mod utils;
 use utils::Writer;
 
-struct State {
-    db: Addr<db::DbExecutor>,
-}
-
-fn world_row(req: &HttpRequest<State>) -> FutureResponse<HttpResponse> {
-    let mut resp = HttpResponse::build_from(req);
-    req.state()
-        .db
-        .send(db::RandomWorld)
+fn world_row(
+    db: web::Data<Addr<db::DbExecutor>>,
+) -> impl Future<Item = HttpResponse, Error = Error> {
+    db.send(db::RandomWorld)
         .from_err()
         .and_then(move |res| match res {
             Ok(row) => {
                 let mut body = BytesMut::with_capacity(31);
                 serde_json::to_writer(Writer(&mut body), &row).unwrap();
-                Ok(resp
+                Ok(HttpResponse::Ok()
                     .header(http::header::SERVER, "Actix")
-                    .content_type("application/json")
+                    .header(http::header::CONTENT_TYPE, "application/json")
                     .body(body))
             }
             Err(_) => Ok(HttpResponse::InternalServerError().into()),
-        }).responder()
+        })
 }
 
-fn queries(req: &HttpRequest<State>) -> FutureResponse<HttpResponse> {
+fn queries(
+    req: HttpRequest,
+    db: web::Data<Addr<db::DbExecutor>>,
+) -> impl Future<Item = HttpResponse, Error = Error> {
     // get queries parameter
-    let q = req
-        .query()
-        .get("q")
-        .map(|q| cmp::min(500, cmp::max(1, q.parse::<u16>().ok().unwrap_or(1))))
-        .unwrap_or(1);
+    let q = utils::get_query_param(req.query_string());
 
     // run sql queries
-    let mut resp = HttpResponse::build_from(req);
-    req.state()
-        .db
-        .send(db::RandomWorlds(q))
+    db.send(db::RandomWorlds(q))
         .from_err()
         .and_then(move |res| {
             if let Ok(worlds) = res {
                 let mut body = BytesMut::with_capacity(35 * worlds.len());
                 serde_json::to_writer(Writer(&mut body), &worlds).unwrap();
-                Ok(resp
+                Ok(HttpResponse::Ok()
                     .header(http::header::SERVER, "Actix")
-                    .content_type("application/json")
+                    .header(http::header::CONTENT_TYPE, "application/json")
                     .body(body))
             } else {
                 Ok(HttpResponse::InternalServerError().into())
             }
-        }).responder()
+        })
 }
 
-fn updates(req: &HttpRequest<State>) -> FutureResponse<HttpResponse> {
+fn updates(
+    req: HttpRequest,
+    db: web::Data<Addr<db::DbExecutor>>,
+) -> impl Future<Item = HttpResponse, Error = Error> {
     // get queries parameter
-    let q = if let Some(q) = req.query().get("q") {
-        q.parse::<usize>().ok().unwrap_or(1)
-    } else {
-        1
-    };
-    let q = cmp::min(500, cmp::max(1, q));
+    let q = utils::get_query_param(req.query_string());
 
     // update worlds
-    let mut resp = HttpResponse::build_from(req);
-    req.state()
-        .db
-        .send(db::UpdateWorld(q))
-        .from_err()
-        .and_then(move |res| {
-            if let Ok(worlds) = res {
-                let mut body = BytesMut::with_capacity(35 * worlds.len());
-                serde_json::to_writer(Writer(&mut body), &worlds).unwrap();
-                Ok(resp
-                    .header(http::header::SERVER, "Actix")
-                    .content_type("application/json")
-                    .body(body))
-            } else {
-                Ok(HttpResponse::InternalServerError().into())
-            }
-        }).responder()
+    db.send(db::UpdateWorld(q)).from_err().and_then(move |res| {
+        if let Ok(worlds) = res {
+            let mut body = BytesMut::with_capacity(35 * worlds.len());
+            serde_json::to_writer(Writer(&mut body), &worlds).unwrap();
+            Ok(HttpResponse::Ok()
+                .header(http::header::SERVER, "Actix")
+                .header(http::header::CONTENT_TYPE, "application/json")
+                .body(body))
+        } else {
+            Ok(HttpResponse::InternalServerError().into())
+        }
+    })
 }
 
 #[derive(Template)]
@@ -116,54 +87,46 @@ struct FortuneTemplate<'a> {
     items: &'a Vec<models::Fortune>,
 }
 
-fn fortune(req: &HttpRequest<State>) -> FutureResponse<HttpResponse> {
-    let mut resp = HttpResponse::build_from(req);
-    req.state()
-        .db
-        .send(db::TellFortune)
+fn fortune(
+    db: web::Data<Addr<db::DbExecutor>>,
+) -> impl Future<Item = HttpResponse, Error = Error> {
+    db.send(db::TellFortune)
         .from_err()
         .and_then(move |res| match res {
             Ok(rows) => {
                 let tmpl = FortuneTemplate { items: &rows };
                 let res = tmpl.render().unwrap();
 
-                Ok(resp
+                Ok(HttpResponse::Ok()
                     .header(http::header::SERVER, "Actix")
-                    .content_type("text/html; charset=utf-8")
+                    .header(http::header::CONTENT_TYPE, "text/html; charset=utf-8")
                     .body(res))
             }
             Err(_) => Ok(HttpResponse::InternalServerError().into()),
-        }).responder()
+        })
 }
 
-fn main() {
-    let sys = System::new("techempower");
+fn main() -> std::io::Result<()> {
+    let sys = actix_rt::System::new("techempower");
     let db_url = "postgres://benchmarkdbuser:benchmarkdbpass@tfb-database/hello_world";
 
-    // Avoid triggering "FATAL: the database system is starting up" error from
-    // postgres.
-    {
-        if PgConnection::establish(db_url).is_err() {
-            std::thread::sleep(std::time::Duration::from_secs(5));
-        }
-    }
-
     // Start db executor actors
     let addr =
         SyncArbiter::start(num_cpus::get() * 3, move || db::DbExecutor::new(db_url));
 
     // start http server
-    server::new(move || {
-        App::with_state(State { db: addr.clone() })
-            .resource("/db", |r| r.route().f(world_row))
-            .resource("/fortune", |r| r.route().f(fortune))
-            .resource("/queries", |r| r.route().f(queries))
-            .resource("/updates", |r| r.route().f(updates))
-    }).backlog(8192)
-    .bind("0.0.0.0:8080")
-    .unwrap()
-    .start();
+    Server::build()
+        .backlog(1024)
+        .bind("techempower", "0.0.0.0:8080", move || {
+            HttpService::build().keep_alive(KeepAlive::Os).h1(App::new()
+                .data(addr.clone())
+                .service(web::resource("/db").to_async(world_row))
+                .service(web::resource("/fortune").to_async(fortune))
+                .service(web::resource("/queries").to_async(queries))
+                .service(web::resource("/updates").to_async(updates)))
+        })?
+        .start();
 
     println!("Started http server: 127.0.0.1:8080");
-    let _ = sys.run();
+    sys.run()
 }

+ 90 - 97
frameworks/Rust/actix/src/main_pg.rs

@@ -1,24 +1,13 @@
-extern crate actix;
-extern crate actix_web;
-extern crate bytes;
-extern crate futures;
-extern crate num_cpus;
-extern crate rand;
-extern crate serde;
-extern crate serde_json;
-extern crate tokio_postgres;
-extern crate url;
 #[macro_use]
 extern crate serde_derive;
 #[macro_use]
 extern crate diesel;
-#[macro_use]
-extern crate askama;
 
 use actix::prelude::*;
-use actix_web::{
-    http, server, App, AsyncResponder, FutureResponse, HttpRequest, HttpResponse,
-};
+use actix_http::{HttpService, KeepAlive};
+use actix_server::Server;
+use actix_web::http::{header::CONTENT_TYPE, header::SERVER, HeaderValue, StatusCode};
+use actix_web::{dev::Body, web, App, Error, HttpRequest, HttpResponse};
 use askama::Template;
 use bytes::BytesMut;
 use futures::Future;
@@ -26,79 +15,78 @@ use futures::Future;
 mod db_pg;
 mod models;
 mod utils;
-use db_pg::{PgConnection, RandomWorld, RandomWorlds, TellFortune, UpdateWorld};
-use utils::Writer;
-
-struct State {
-    db: Addr<PgConnection>,
-}
+use crate::db_pg::{PgConnection, RandomWorld, RandomWorlds, TellFortune, UpdateWorld};
+use crate::utils::Writer;
 
-fn world_row(req: &HttpRequest<State>) -> FutureResponse<HttpResponse> {
-    let mut resp = HttpResponse::build_from(req);
-    req.state()
-        .db
-        .send(RandomWorld)
+fn world_row(
+    db: web::Data<Addr<PgConnection>>,
+) -> impl Future<Item = HttpResponse, Error = Error> {
+    db.send(RandomWorld)
         .from_err()
         .and_then(move |res| match res {
             Ok(row) => {
                 let mut body = BytesMut::with_capacity(31);
                 serde_json::to_writer(Writer(&mut body), &row).unwrap();
-                Ok(resp
-                    .header(http::header::SERVER, "Actix")
-                    .content_type("application/json")
-                    .body(body))
+                let mut res =
+                    HttpResponse::with_body(StatusCode::OK, Body::Bytes(body.freeze()));
+                res.headers_mut()
+                    .insert(SERVER, HeaderValue::from_static("Actix"));
+                res.headers_mut()
+                    .insert(CONTENT_TYPE, HeaderValue::from_static("application/json"));
+                Ok(res)
             }
             Err(_) => Ok(HttpResponse::InternalServerError().into()),
-        }).responder()
+        })
 }
 
-fn queries(req: &HttpRequest<State>) -> FutureResponse<HttpResponse> {
+fn queries(
+    req: HttpRequest,
+    db: web::Data<Addr<PgConnection>>,
+) -> impl Future<Item = HttpResponse, Error = Error> {
     // get queries parameter
-    let q = utils::get_query_param(req.uri());
+    let q = utils::get_query_param(req.query_string());
 
     // run sql queries
-    let mut resp = HttpResponse::build_from(req);
-    req.clone()
-        .state()
-        .db
-        .send(RandomWorlds(q))
-        .from_err()
-        .and_then(move |res| {
-            if let Ok(worlds) = res {
-                let mut body = BytesMut::with_capacity(35 * worlds.len());
-                serde_json::to_writer(Writer(&mut body), &worlds).unwrap();
-                Ok(resp
-                    .header(http::header::SERVER, "Actix")
-                    .content_type("application/json")
-                    .body(body))
-            } else {
-                Ok(HttpResponse::InternalServerError().into())
-            }
-        }).responder()
+    db.send(RandomWorlds(q)).from_err().and_then(move |res| {
+        if let Ok(worlds) = res {
+            let mut body = BytesMut::with_capacity(35 * worlds.len());
+            serde_json::to_writer(Writer(&mut body), &worlds).unwrap();
+            let mut res =
+                HttpResponse::with_body(StatusCode::OK, Body::Bytes(body.freeze()));
+            res.headers_mut()
+                .insert(SERVER, HeaderValue::from_static("Actix"));
+            res.headers_mut()
+                .insert(CONTENT_TYPE, HeaderValue::from_static("application/json"));
+            Ok(res)
+        } else {
+            Ok(HttpResponse::InternalServerError().into())
+        }
+    })
 }
 
-fn updates(req: &HttpRequest<State>) -> FutureResponse<HttpResponse> {
+fn updates(
+    req: HttpRequest,
+    db: web::Data<Addr<PgConnection>>,
+) -> impl Future<Item = HttpResponse, Error = Error> {
     // get queries parameter
-    let q = utils::get_query_param(req.uri());
+    let q = utils::get_query_param(req.query_string());
 
     // update db
-    let mut resp = HttpResponse::build_from(req);
-    req.state()
-        .db
-        .send(UpdateWorld(q))
-        .from_err()
-        .and_then(move |res| {
-            if let Ok(worlds) = res {
-                let mut body = BytesMut::with_capacity(35 * worlds.len());
-                serde_json::to_writer(Writer(&mut body), &worlds).unwrap();
-                Ok(resp
-                    .header(http::header::SERVER, "Actix")
-                    .content_type("application/json")
-                    .body(body))
-            } else {
-                Ok(HttpResponse::InternalServerError().into())
-            }
-        }).responder()
+    db.send(UpdateWorld(q)).from_err().and_then(move |res| {
+        if let Ok(worlds) = res {
+            let mut body = BytesMut::with_capacity(35 * worlds.len());
+            serde_json::to_writer(Writer(&mut body), &worlds).unwrap();
+            let mut res =
+                HttpResponse::with_body(StatusCode::OK, Body::Bytes(body.freeze()));
+            res.headers_mut()
+                .insert(SERVER, HeaderValue::from_static("Actix"));
+            res.headers_mut()
+                .insert(CONTENT_TYPE, HeaderValue::from_static("application/json"));
+            Ok(res)
+        } else {
+            Ok(HttpResponse::InternalServerError().into())
+        }
+    })
 }
 
 #[derive(Template)]
@@ -107,44 +95,49 @@ struct FortuneTemplate<'a> {
     items: &'a Vec<models::Fortune>,
 }
 
-fn fortune(req: &HttpRequest<State>) -> FutureResponse<HttpResponse> {
-    let mut resp = HttpResponse::build_from(req);
-    req.state()
-        .db
-        .send(TellFortune)
+fn fortune(
+    db: web::Data<Addr<PgConnection>>,
+) -> impl Future<Item = HttpResponse, Error = Error> {
+    db.send(TellFortune)
         .from_err()
         .and_then(move |res| match res {
             Ok(rows) => {
                 let tmpl = FortuneTemplate { items: &rows };
-                let res = tmpl.render().unwrap();
+                let body = tmpl.render().unwrap();
 
-                Ok(resp
-                    .header(http::header::SERVER, "Actix")
-                    .content_type("text/html; charset=utf-8")
-                    .body(res))
+                let mut res =
+                    HttpResponse::with_body(StatusCode::OK, Body::Bytes(body.into()));
+                res.headers_mut()
+                    .insert(SERVER, HeaderValue::from_static("Actix"));
+                res.headers_mut().insert(
+                    CONTENT_TYPE,
+                    HeaderValue::from_static("text/html; charset=utf-8"),
+                );
+                Ok(res)
             }
             Err(_) => Ok(HttpResponse::InternalServerError().into()),
-        }).responder()
+        })
 }
 
-fn main() {
-    let sys = System::new("techempower");
-    let db_url = "postgres://benchmarkdbuser:benchmarkdbpass@tfb-database/hello_world";
+fn main() -> std::io::Result<()> {
+    let sys = actix_rt::System::new("techempower");
+    const DB_URL: &str =
+        "postgres://benchmarkdbuser:benchmarkdbpass@tfb-database/hello_world";
 
     // start http server
-    server::new(move || {
-        let addr = PgConnection::connect(db_url);
-
-        App::with_state(State { db: addr })
-            .resource("/db", |r| r.route().f(world_row))
-            .resource("/queries", |r| r.route().f(queries))
-            .resource("/fortune", |r| r.route().f(fortune))
-            .resource("/updates", |r| r.route().f(updates))
-    }).backlog(8192)
-    .bind("0.0.0.0:8080")
-    .unwrap()
-    .start();
+    Server::build()
+        .backlog(1024)
+        .bind("techempower", "0.0.0.0:8080", || {
+            let addr = PgConnection::connect(DB_URL);
+            HttpService::build().keep_alive(KeepAlive::Os).h1(App::new()
+                .data(addr)
+                .service(web::resource("/db").to_async(world_row))
+                .service(web::resource("/queries").to_async(queries))
+                .service(web::resource("/fortune").to_async(fortune))
+                .service(web::resource("/updates").to_async(updates)))
+        })?
+        .start();
 
     println!("Started http server: 127.0.0.1:8080");
-    let _ = sys.run();
+    sys.run()
 }

+ 236 - 0
frameworks/Rust/actix/src/main_platform.rs

@@ -0,0 +1,236 @@
+#[macro_use]
+extern crate serde_derive;
+#[macro_use]
+extern crate diesel;
+
+use std::io::Write;
+
+use actix_http::body::Body;
+use actix_http::http::{header::CONTENT_TYPE, header::SERVER, HeaderValue, StatusCode};
+use actix_http::{Error, HttpService, KeepAlive, Request, Response};
+use actix_server::{Server, ServerConfig};
+use actix_service::{NewService, Service};
+use bytes::{Bytes, BytesMut};
+use futures::future::{join_all, ok, Either, FutureResult};
+use futures::{Async, Future, Poll};
+
+mod db_pg_direct;
+mod models;
+mod utils;
+
+use crate::db_pg_direct::PgConnection;
+use crate::utils::{escape, Message, Writer, SIZE};
+
+const FORTUNES_START: &[u8] = b"<!DOCTYPE html><html><head><title>Fortunes</title></head><body><table><tr><th>id</th><th>message</th></tr>";
+const FORTUNES_ROW_START: &[u8] = b"<tr><td>";
+const FORTUNES_COLUMN: &[u8] = b"</td><td>";
+const FORTUNES_ROW_END: &[u8] = b"</td></tr>";
+const FORTUNES_END: &[u8] = b"</table></body></html>";
+
+struct App {
+    dbs: Vec<PgConnection>,
+    useall: bool,
+    next: usize,
+}
+
+#[derive(PartialEq, Copy, Clone)]
+enum Db {
+    All,
+    Multi,
+    Update,
+}
+
+impl App {
+    fn get_db(&mut self, db: Db) -> &mut PgConnection {
+        if self.useall {
+            match db {
+                Db::All => {
+                    self.next = (self.next + 1) % 5;
+                    &mut self.dbs[self.next]
+                }
+                Db::Update => &mut self.dbs[0],
+                Db::Multi => {
+                    self.next = (self.next + 1) % 2;
+                    &mut self.dbs[self.next]
+                }
+            }
+        } else {
+            &mut self.dbs[0]
+        }
+    }
+}
+
+impl Service for App {
+    type Request = Request;
+    type Response = Response;
+    type Error = Error;
+    type Future = Either<
+        FutureResult<Self::Response, Self::Error>,
+        Box<Future<Item = Response, Error = Error>>,
+    >;
+
+    #[inline]
+    fn poll_ready(&mut self) -> Poll<(), Self::Error> {
+        Ok(Async::Ready(()))
+    }
+
+    fn call(&mut self, req: Request) -> Self::Future {
+        let path = req.path();
+        match path.len() {
+            10 if path == "/plaintext" => {
+                let mut res = Response::with_body(
+                    StatusCode::OK,
+                    Body::Bytes(Bytes::from_static(b"Hello, World!")),
+                );
+                res.headers_mut()
+                    .insert(SERVER, HeaderValue::from_static("Actix"));
+                res.headers_mut()
+                    .insert(CONTENT_TYPE, HeaderValue::from_static("text/plain"));
+                Either::A(ok(res))
+            }
+            5 if path == "/json" => {
+                let message = Message {
+                    message: "Hello, World!",
+                };
+                let mut body = BytesMut::with_capacity(SIZE);
+                serde_json::to_writer(Writer(&mut body), &message).unwrap();
+
+                let mut res =
+                    Response::with_body(StatusCode::OK, Body::Bytes(body.freeze()));
+                res.headers_mut()
+                    .insert(SERVER, HeaderValue::from_static("Actix"));
+                res.headers_mut()
+                    .insert(CONTENT_TYPE, HeaderValue::from_static("application/json"));
+                Either::A(ok(res))
+            }
+            3 if path == "/db" => {
+                let fut = self.get_db(Db::All).get_world();
+
+                Either::B(Box::new(fut.from_err().and_then(move |row| {
+                    let mut body = BytesMut::with_capacity(31);
+                    serde_json::to_writer(Writer(&mut body), &row).unwrap();
+                    let mut res =
+                        Response::with_body(StatusCode::OK, Body::Bytes(body.freeze()));
+                    res.headers_mut()
+                        .insert(SERVER, HeaderValue::from_static("Actix"));
+                    res.headers_mut().insert(
+                        CONTENT_TYPE,
+                        HeaderValue::from_static("application/json"),
+                    );
+                    Ok(res)
+                })))
+            }
+            8 if path == "/fortune" => {
+                let fut = self.get_db(Db::All).tell_fortune();
+
+                Either::B(Box::new(fut.from_err().and_then(move |fortunes| {
+                    let mut body = BytesMut::with_capacity(2048);
+                    let mut writer = Writer(&mut body);
+                    let _ = writer.write(FORTUNES_START);
+                    fortunes.into_iter().fold((), |_, row| {
+                        let _ = writer.write(FORTUNES_ROW_START);
+                        let _ = write!(&mut writer, "{}", row.id);
+                        let _ = writer.write(FORTUNES_COLUMN);
+                        escape(&mut writer, row.message);
+                        let _ = writer.write(FORTUNES_ROW_END);
+                        ()
+                    });
+                    let _ = writer.write(FORTUNES_END);
+                    let mut res =
+                        Response::with_body(StatusCode::OK, Body::Bytes(body.freeze()));
+                    res.headers_mut()
+                        .insert(SERVER, HeaderValue::from_static("Actix"));
+                    res.headers_mut().insert(
+                        CONTENT_TYPE,
+                        HeaderValue::from_static("text/html; charset=utf-8"),
+                    );
+                    Ok(res)
+                })))
+            }
+            8 if path == "/queries" => {
+                let q = utils::get_query_param(req.uri().query().unwrap_or("")) as usize;
+                let fut = self.get_db(Db::Multi).get_worlds(q);
+
+                Either::B(Box::new(fut.from_err().and_then(move |worlds| {
+                    let mut body = BytesMut::with_capacity(35 * worlds.len());
+                    serde_json::to_writer(Writer(&mut body), &worlds).unwrap();
+                    let mut res =
+                        Response::with_body(StatusCode::OK, Body::Bytes(body.freeze()));
+                    res.headers_mut()
+                        .insert(SERVER, HeaderValue::from_static("Actix"));
+                    res.headers_mut().insert(
+                        CONTENT_TYPE,
+                        HeaderValue::from_static("application/json"),
+                    );
+                    Ok(res)
+                })))
+            }
+            8 if path == "/updates" => {
+                let q = utils::get_query_param(req.uri().query().unwrap_or("")) as usize;
+                let fut = self.get_db(Db::Update).update(q);
+
+                Either::B(Box::new(fut.from_err().and_then(move |worlds| {
+                    let mut body = BytesMut::with_capacity(35 * worlds.len());
+                    serde_json::to_writer(Writer(&mut body), &worlds).unwrap();
+                    let mut res =
+                        Response::with_body(StatusCode::OK, Body::Bytes(body.freeze()));
+                    res.headers_mut()
+                        .insert(SERVER, HeaderValue::from_static("Actix"));
+                    res.headers_mut().insert(
+                        CONTENT_TYPE,
+                        HeaderValue::from_static("application/json"),
+                    );
+                    Ok(res)
+                })))
+            }
+            _ => Either::A(ok(Response::new(http::StatusCode::NOT_FOUND))),
+        }
+    }
+}
+
+#[derive(Clone)]
+struct AppFactory;
+
+impl NewService<ServerConfig> for AppFactory {
+    type Request = Request;
+    type Response = Response;
+    type Error = Error;
+    type Service = App;
+    type InitError = ();
+    type Future = Box<Future<Item = Self::Service, Error = Self::InitError>>;
+
+    fn new_service(&self, _: &ServerConfig) -> Self::Future {
+        const DB_URL: &str =
+            "postgres://benchmarkdbuser:benchmarkdbpass@tfb-database/hello_world";
+
+        let mut conns = Vec::new();
+        for _ in 0..5 {
+            conns.push(PgConnection::connect(DB_URL));
+        }
+        Box::new(join_all(conns).map(|dbs| App {
+            dbs,
+            next: 0,
+            useall: num_cpus::get() > 4,
+        }))
+    }
+}
+
+fn main() -> std::io::Result<()> {
+    let sys = actix_rt::System::builder()
+        .name("techempower")
+        .stop_on_panic(false)
+        .build();
+
+    // start http server
+    Server::build()
+        .backlog(1024)
+        .bind("techempower", "0.0.0.0:8080", || {
+            HttpService::build()
+                .keep_alive(KeepAlive::Os)
+                .h1(AppFactory)
+        })?
+        .start();
+
+    println!("Started http server: 127.0.0.1:8080");
+    sys.run()
+}

+ 0 - 338
frameworks/Rust/actix/src/main_raw.rs

@@ -1,338 +0,0 @@
-extern crate actix;
-extern crate actix_web;
-extern crate bytes;
-extern crate futures;
-extern crate serde;
-extern crate serde_json;
-#[macro_use]
-extern crate serde_derive;
-extern crate num_cpus;
-extern crate rand;
-extern crate url;
-#[macro_use]
-extern crate diesel;
-extern crate tokio_postgres;
-
-use std::cell::RefCell;
-use std::io::Write;
-use std::rc::Rc;
-use std::{io, mem};
-
-use actix::prelude::*;
-use actix_web::server::{
-    self, HttpHandler, HttpHandlerTask, HttpServer, KeepAlive, Request, Writer,
-};
-use actix_web::Error;
-use futures::{Async, Future, Poll};
-use rand::{thread_rng, Rng};
-
-mod db_pg_direct;
-mod models;
-mod utils;
-
-use db_pg_direct::PgConnection;
-use utils::{escape, Message, StackWriter, Writer as JsonWriter};
-
-const HTTPOK: &[u8] = b"HTTP/1.1 200 OK\r\n";
-const HDR_SERVER: &[u8] = b"Server: Actix\r\n";
-const HDR_CTPLAIN: &[u8] = b"Content-Type: text/plain";
-const HDR_CTJSON: &[u8] = b"Content-Type: application/json";
-const HDR_CTHTML: &[u8] = b"Content-Type: text/html; charset=utf-8";
-const BODY: &[u8] = b"Hello, World!";
-
-struct App {
-    dbs: Rc<RefCell<Vec<PgConnection>>>,
-    useall: bool,
-}
-
-impl HttpHandler for App {
-    type Task = Box<HttpHandlerTask>;
-
-    fn handle(&self, req: Request) -> Result<Box<HttpHandlerTask>, Request> {
-        {
-            let path = req.path();
-            match path.len() {
-                10 if path == "/plaintext" => return Ok(Box::new(Plaintext)),
-                5 if path == "/json" => return Ok(Box::new(Json)),
-                3 if path == "/db" => {
-                    if self.useall {
-                        if let Some(db) = thread_rng().choose(&*self.dbs.borrow()) {
-                            return Ok(Box::new(World {
-                                fut: db.get_world(),
-                            }));
-                        }
-                    } else {
-                        return Ok(Box::new(World {
-                            fut: self.dbs.borrow()[0].get_world(),
-                        }));
-                    }
-                }
-                8 if path == "/fortune" => {
-                    if let Some(db) = thread_rng().choose(&*self.dbs.borrow()) {
-                        return Ok(Box::new(Fortune {
-                            fut: db.tell_fortune(),
-                        }));
-                    }
-                }
-                8 if path == "/queries" => {
-                    let q = utils::get_query_param(req.uri());
-                    if self.useall {
-                        if let Some(db) = thread_rng().choose(&*self.dbs.borrow()) {
-                            return Ok(Box::new(Queries {
-                                fut: db.get_worlds(q as usize),
-                            }));
-                        }
-                    } else {
-                        return Ok(Box::new(Queries {
-                            fut: self.dbs.borrow()[0].get_worlds(q as usize),
-                        }));
-                    }
-                }
-                8 if path == "/updates" => {
-                    let q = utils::get_query_param(req.uri());
-                    if self.useall {
-                        if let Some(db) = thread_rng().choose(&*self.dbs.borrow()) {
-                            return Ok(Box::new(Updates {
-                                fut: db.update(q as usize),
-                            }));
-                        }
-                    } else {
-                        return Ok(Box::new(Updates {
-                            fut: self.dbs.borrow()[0].update(q as usize),
-                        }));
-                    }
-                }
-                _ => (),
-            }
-        }
-        Err(req)
-    }
-}
-
-struct Plaintext;
-
-impl HttpHandlerTask for Plaintext {
-    fn poll_io(&mut self, io: &mut Writer) -> Poll<bool, Error> {
-        {
-            let mut bytes = io.buffer();
-            bytes.reserve(196);
-            bytes.extend_from_slice(HTTPOK);
-            bytes.extend_from_slice(HDR_SERVER);
-            bytes.extend_from_slice(HDR_CTPLAIN);
-            server::write_content_length(13, &mut bytes);
-        }
-        io.set_date();
-        io.buffer().extend_from_slice(BODY);
-        Ok(Async::Ready(true))
-    }
-}
-
-struct Json;
-
-impl HttpHandlerTask for Json {
-    fn poll_io(&mut self, io: &mut Writer) -> Poll<bool, Error> {
-        let message = Message {
-            message: "Hello, World!",
-        };
-
-        {
-            let mut bytes = io.buffer();
-            bytes.reserve(196);
-            bytes.extend_from_slice(HTTPOK);
-            bytes.extend_from_slice(HDR_SERVER);
-            bytes.extend_from_slice(HDR_CTJSON);
-            server::write_content_length(27, &mut bytes);
-        }
-        io.set_date();
-        serde_json::to_writer(JsonWriter(io.buffer()), &message).unwrap();
-        Ok(Async::Ready(true))
-    }
-}
-
-struct Fortune<F> {
-    fut: F,
-}
-
-const FORTUNES_START: &[u8] = b"<!DOCTYPE html><html><head><title>Fortunes</title></head><body><table><tr><th>id</th><th>message</th></tr>";
-const FORTUNES_ROW_START: &[u8] = b"<tr><td>";
-const FORTUNES_COLUMN: &[u8] = b"</td><td>";
-const FORTUNES_ROW_END: &[u8] = b"</td></tr>";
-const FORTUNES_END: &[u8] = b"</table></body></html>";
-
-impl<F> HttpHandlerTask for Fortune<F>
-where
-    F: Future<Item = Vec<models::Fortune>, Error = io::Error>,
-{
-    fn poll_io(&mut self, io: &mut Writer) -> Poll<bool, Error> {
-        match self.fut.poll() {
-            Ok(Async::Ready(rows)) => {
-                let mut body: [u8; 2048] = unsafe { mem::uninitialized() };
-                let len = {
-                    let mut writer = StackWriter(&mut body, 0);
-                    let _ = writer.write(FORTUNES_START);
-                    for row in rows {
-                        let _ = writer.write(FORTUNES_ROW_START);
-                        let _ = write!(&mut writer, "{}", row.id);
-                        let _ = writer.write(FORTUNES_COLUMN);
-                        escape(&mut writer, row.message);
-                        let _ = writer.write(FORTUNES_ROW_END);
-                    }
-                    let _ = writer.write(FORTUNES_END);
-                    writer.1
-                };
-
-                {
-                    let mut bytes = io.buffer();
-                    bytes.reserve(196 + len);
-                    bytes.extend_from_slice(HTTPOK);
-                    bytes.extend_from_slice(HDR_SERVER);
-                    bytes.extend_from_slice(HDR_CTHTML);
-                    server::write_content_length(len, &mut bytes);
-                }
-                io.set_date();
-                io.buffer().extend_from_slice(&body[..len]);
-                Ok(Async::Ready(true))
-            }
-            Ok(Async::NotReady) => Ok(Async::NotReady),
-            Err(e) => Err(e.into()),
-        }
-    }
-}
-
-struct World<F> {
-    fut: F,
-}
-
-impl<F> HttpHandlerTask for World<F>
-where
-    F: Future<Item = models::World, Error = io::Error>,
-{
-    fn poll_io(&mut self, io: &mut Writer) -> Poll<bool, Error> {
-        match self.fut.poll() {
-            Ok(Async::Ready(row)) => {
-                let mut body: [u8; 48] = unsafe { mem::uninitialized() };
-                let len = {
-                    let mut writer = StackWriter(&mut body, 0);
-                    serde_json::to_writer(&mut writer, &row).unwrap();
-                    writer.1
-                };
-
-                {
-                    let mut bytes = io.buffer();
-                    bytes.reserve(196);
-                    bytes.extend_from_slice(HTTPOK);
-                    bytes.extend_from_slice(HDR_SERVER);
-                    bytes.extend_from_slice(HDR_CTJSON);
-                    server::write_content_length(len, &mut bytes);
-                }
-                io.set_date();
-                io.buffer().extend_from_slice(&body[..len]);
-                Ok(Async::Ready(true))
-            }
-            Ok(Async::NotReady) => Ok(Async::NotReady),
-            Err(e) => Err(e.into()),
-        }
-    }
-}
-
-struct Queries<F> {
-    fut: F,
-}
-
-impl<F> HttpHandlerTask for Queries<F>
-where
-    F: Future<Item = Vec<models::World>, Error = io::Error>,
-{
-    fn poll_io(&mut self, io: &mut Writer) -> Poll<bool, Error> {
-        match self.fut.poll() {
-            Ok(Async::Ready(worlds)) => {
-                let mut body: [u8; 24576] = unsafe { mem::uninitialized() };
-                let len = {
-                    let mut writer = StackWriter(&mut body, 0);
-                    serde_json::to_writer(&mut writer, &worlds).unwrap();
-                    writer.1
-                };
-
-                {
-                    let mut bytes = io.buffer();
-                    bytes.reserve(196 + len);
-                    bytes.extend_from_slice(HTTPOK);
-                    bytes.extend_from_slice(HDR_SERVER);
-                    bytes.extend_from_slice(HDR_CTJSON);
-                    server::write_content_length(len, &mut bytes);
-                }
-                io.set_date();
-                io.buffer().extend_from_slice(&body[..len]);
-                Ok(Async::Ready(true))
-            }
-            Ok(Async::NotReady) => Ok(Async::NotReady),
-            Err(e) => Err(e.into()),
-        }
-    }
-}
-
-struct Updates<F> {
-    fut: F,
-}
-
-impl<F> HttpHandlerTask for Updates<F>
-where
-    F: Future<Item = Vec<models::World>, Error = io::Error>,
-{
-    fn poll_io(&mut self, io: &mut Writer) -> Poll<bool, Error> {
-        match self.fut.poll() {
-            Ok(Async::Ready(worlds)) => {
-                let mut body: [u8; 24576] = unsafe { mem::uninitialized() };
-                let len = {
-                    let mut writer = StackWriter(&mut body, 0);
-                    serde_json::to_writer(&mut writer, &worlds).unwrap();
-                    writer.1
-                };
-
-                {
-                    let mut bytes = io.buffer();
-                    bytes.reserve(196 + len);
-                    bytes.extend_from_slice(HTTPOK);
-                    bytes.extend_from_slice(HDR_SERVER);
-                    bytes.extend_from_slice(HDR_CTJSON);
-                    server::write_content_length(len, &mut bytes);
-                }
-                io.set_date();
-                io.buffer().extend_from_slice(&body[..len]);
-                Ok(Async::Ready(true))
-            }
-            Ok(Async::NotReady) => Ok(Async::NotReady),
-            Err(e) => Err(e.into()),
-        }
-    }
-}
-
-fn main() {
-    let sys = System::new("techempower");
-    let db_url = "postgres://benchmarkdbuser:benchmarkdbpass@tfb-database/hello_world";
-
-    // start http server
-    HttpServer::new(move || {
-        let dbs = Rc::new(RefCell::new(Vec::new()));
-
-        for _ in 0..3 {
-            let db = dbs.clone();
-            Arbiter::spawn(PgConnection::connect(db_url).and_then(move |conn| {
-                db.borrow_mut().push(conn);
-                Ok(())
-            }));
-        }
-
-        vec![App {
-            dbs,
-            useall: num_cpus::get() > 4,
-        }]
-    }).backlog(8192)
-    .keep_alive(KeepAlive::Os)
-    .bind("0.0.0.0:8080")
-    .unwrap()
-    .start();
-
-    println!("Started http server: 127.0.0.1:8080");
-    let _ = sys.run();
-}

+ 1 - 1
frameworks/Rust/actix/src/models.rs

@@ -11,7 +11,7 @@ pub struct World {
 }
 
 #[allow(non_snake_case)]
-#[derive(Serialize, Queryable)]
+#[derive(Serialize, Queryable, Debug)]
 pub struct Fortune {
     pub id: i32,
     pub message: String,

+ 9 - 47
frameworks/Rust/actix/src/utils.rs

@@ -1,9 +1,7 @@
 #![allow(dead_code)]
-use bytes::BytesMut;
-use std::{cmp, fmt, io};
+use std::{cmp, io};
 
-use actix_web::http::Uri;
-use url::form_urlencoded;
+use bytes::BytesMut;
 
 pub const SIZE: usize = 31;
 
@@ -24,49 +22,13 @@ impl<'a> io::Write for Writer<'a> {
     }
 }
 
-pub struct StackWriter<'a>(pub &'a mut [u8], pub usize);
-
-impl<'a> io::Write for StackWriter<'a> {
-    #[inline]
-    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
-        let l = buf.len();
-        let new = self.1 + l;
-        self.0[self.1..new].copy_from_slice(buf);
-        self.1 = new;
-        Ok(l)
-    }
-    #[inline]
-    fn flush(&mut self) -> io::Result<()> {
-        Ok(())
-    }
-}
-
-impl<'a> fmt::Write for StackWriter<'a> {
-    #[inline]
-    fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> {
-        if !s.is_empty() {
-            let b = s.as_bytes();
-            let l = b.len();
-            let new = self.1 + l;
-            self.0[self.1..new].copy_from_slice(b);
-            self.1 = new;
-        }
-        Ok(())
-    }
-}
-
-pub fn get_query_param(uri: &Uri) -> u16 {
-    let mut q = None;
-    let q_str = if let Some(s) = uri.query() { s } else { "" };
-    for (key, val) in form_urlencoded::parse(q_str.as_ref()) {
-        if key == "q" {
-            q = Some(val);
-            break;
-        }
-    }
-
-    q.map(|q| cmp::min(500, cmp::max(1, q.parse::<u16>().ok().unwrap_or(1))))
-        .unwrap_or(1)
+pub fn get_query_param(query: &str) -> u16 {
+    let q = if let Some(pos) = query.find("q") {
+        query.split_at(pos + 2).1.parse::<u16>().ok().unwrap_or(1)
+    } else {
+        1
+    };
+    cmp::min(500, cmp::max(1, q))
 }
 
 fn escapable(b: u8) -> bool {

이 변경점에서 너무 많은 파일들이 변경되어 몇몇 파일들은 표시되지 않았습니다.