Browse Source

actix: reduce mem allocations (#5564)

Nikolay Kim 5 years ago
parent
commit
24d0f626d6
2 changed files with 67 additions and 26 deletions
  1. 55 10
      frameworks/Rust/actix/src/db_pg_direct.rs
  2. 12 16
      frameworks/Rust/actix/src/main_platform.rs

+ 55 - 10
frameworks/Rust/actix/src/db_pg_direct.rs

@@ -1,6 +1,6 @@
 use std::collections::HashMap;
-use std::fmt::Write;
-use std::io;
+use std::fmt::Write as FmtWrite;
+use std::io::{self, Write};
 
 use actix_http::Error;
 use bytes::{Bytes, BytesMut};
@@ -8,11 +8,54 @@ use futures::stream::futures_unordered::FuturesUnordered;
 use futures::{Future, FutureExt, StreamExt, TryStreamExt};
 use rand::rngs::SmallRng;
 use rand::{Rng, SeedableRng};
+use tokio_postgres::row::Row;
 use tokio_postgres::types::ToSql;
 use tokio_postgres::{connect, Client, NoTls, Statement};
 
 use crate::models::World;
-use crate::utils::{Fortune, Writer};
+use crate::utils::Writer;
+
+pub enum Message {
+    Row(Row),
+    Str(&'static str),
+}
+
+impl Message {
+    fn as_str(&self) -> &str {
+        match self {
+            Message::Row(ref row) => row.get(1),
+            Message::Str(s) => s,
+        }
+    }
+}
+
+#[allow(non_snake_case)]
+pub struct Fortune {
+    pub id: i32,
+    pub message: Message,
+}
+
+markup::define! {
+    FortunesTemplate(items: Vec<Fortune>) {
+        {markup::doctype()}
+        html {
+            head {
+                title { "Fortunes" }
+            }
+            body {
+                table {
+                    tr { th { "id" } th { "message" } }
+                    @for item in {items} {
+                        tr {
+                            td { {item.id} }
+                            td { {markup::raw(v_htmlescape::escape(item.message.as_str()))} }
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
 
 /// Postgres interface
 pub struct PgConnection {
@@ -157,12 +200,10 @@ impl PgConnection {
         }
     }
 
-    pub fn tell_fortune(
-        &mut self,
-    ) -> impl Future<Output = Result<Vec<Fortune>, io::Error>> {
+    pub fn tell_fortune(&mut self) -> impl Future<Output = Result<Bytes, io::Error>> {
         let mut items = vec![Fortune {
             id: 0,
-            message: "Additional fortune added at request time.".to_string(),
+            message: Message::Str("Additional fortune added at request time."),
         }];
 
         let fut = self.cl.query_raw(&self.fortune, &[]);
@@ -178,12 +219,16 @@ impl PgConnection {
                 })?;
                 items.push(Fortune {
                     id: row.get(0),
-                    message: row.get(1),
+                    message: Message::Row(row),
                 });
             }
+            items.sort_by(|it, next| it.message.as_str().cmp(next.message.as_str()));
 
-            items.sort_by(|it, next| it.message.cmp(&next.message));
-            Ok(items)
+            let mut body = BytesMut::with_capacity(2048);
+            let mut writer = Writer(&mut body);
+            let _ = write!(writer, "{}", FortunesTemplate { items });
+
+            Ok(body.freeze())
         }
     }
 }

+ 12 - 16
frameworks/Rust/actix/src/main_platform.rs

@@ -7,7 +7,6 @@ extern crate serde_derive;
 extern crate diesel;
 
 use std::future::Future;
-use std::io::Write;
 use std::pin::Pin;
 use std::task::{Context, Poll};
 
@@ -26,7 +25,7 @@ mod models;
 mod utils;
 
 use crate::db_pg_direct::PgConnection;
-use crate::utils::{FortunesTemplate, Writer};
+use crate::utils::Writer;
 
 struct App {
     db: PgConnection,
@@ -49,32 +48,29 @@ impl Service for App {
     fn call(&mut self, req: Request) -> Self::Future {
         let path = req.path();
         match path {
-            "/db" => {
+            "/fortune" => {
                 let h_srv = self.hdr_srv.clone();
-                let h_ct = self.hdr_ctjson.clone();
-                let fut = self.db.get_world();
+                let h_ct = self.hdr_cthtml.clone();
+                let fut = self.db.tell_fortune();
 
                 Box::pin(async move {
-                    let body = fut.await?;
-                    let mut res = Response::with_body(StatusCode::OK, Body::Bytes(body));
+                    let fortunes = fut.await?;
+                    let mut res =
+                        Response::with_body(StatusCode::OK, Body::Bytes(fortunes));
                     let hdrs = res.headers_mut();
                     hdrs.insert(SERVER, h_srv);
                     hdrs.insert(CONTENT_TYPE, h_ct);
                     Ok(res)
                 })
             }
-            "/fortune" => {
+            "/db" => {
                 let h_srv = self.hdr_srv.clone();
-                let h_ct = self.hdr_cthtml.clone();
-                let fut = self.db.tell_fortune();
+                let h_ct = self.hdr_ctjson.clone();
+                let fut = self.db.get_world();
 
                 Box::pin(async move {
-                    let fortunes = fut.await?;
-                    let mut body = BytesMut::with_capacity(2048);
-                    let mut writer = Writer(&mut body);
-                    let _ = write!(writer, "{}", FortunesTemplate { fortunes });
-                    let mut res =
-                        Response::with_body(StatusCode::OK, Body::Bytes(body.freeze()));
+                    let body = fut.await?;
+                    let mut res = Response::with_body(StatusCode::OK, Body::Bytes(body));
                     let hdrs = res.headers_mut();
                     hdrs.insert(SERVER, h_srv);
                     hdrs.insert(CONTENT_TYPE, h_ct);