Skip to content

Commit

Permalink
Partially bring forward lobsters
Browse files Browse the repository at this point in the history
Currently semi-blocked on rust-lang/rust#64477.

Or rather, it would take a bunch of work to fix the last error in our
code. Instead, there's a small change to std that would also fix it, so
waiting on that:

rust-lang/rust#64477 (comment)
  • Loading branch information
jonhoo committed Sep 27, 2019
1 parent 943e125 commit 1602be4
Show file tree
Hide file tree
Showing 33 changed files with 3,898 additions and 4,048 deletions.
18 changes: 10 additions & 8 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 4 additions & 3 deletions noria-benchmarks/lobsters/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,12 @@ orchestration = ["tsunami", "rusoto_core", "rusoto_sts", "failure", "ssh2", "she
default = []

[dependencies]
trawler = "0.6.3"
trawler = "0.7.0-alpha.1"
mysql_async = "0.21.0-alpha.1"
tokio = "0.1"
tokio = "0.2.0-alpha.5"
clap = "2.31"
futures = "0.1"
futures-core-preview = "0.3.0-alpha.18"
futures-util-preview = "0.3.0-alpha.18"
chrono = "0.4"

yansi = { version = "0.5", optional = true }
Expand Down
265 changes: 127 additions & 138 deletions noria-benchmarks/lobsters/src/endpoints/natural/comment.rs
Original file line number Diff line number Diff line change
@@ -1,154 +1,143 @@
use chrono;
use futures;
use futures::Future;
use my;
use my::prelude::*;
use std::future::Future;
use trawler::{CommentId, StoryId, UserId};

pub(crate) fn handle<F>(
pub(crate) async fn handle<F>(
c: F,
acting_as: Option<UserId>,
id: CommentId,
story: StoryId,
parent: Option<CommentId>,
) -> Box<dyn Future<Item = (my::Conn, bool), Error = my::error::Error> + Send>
) -> Result<(my::Conn, bool), my::error::Error>
where
F: 'static + Future<Item = my::Conn, Error = my::error::Error> + Send,
F: 'static + Future<Output = Result<my::Conn, my::error::Error>> + Send,
{
let c = c.await?;
let user = acting_as.unwrap();
Box::new(
c.and_then(move |c| {
c.first_exec::<_, _, my::Row>(
"SELECT `stories`.* \
FROM `stories` \
WHERE `stories`.`short_id` = ?",
(::std::str::from_utf8(&story[..]).unwrap(),),
)
.map(|(c, story)| (c, story.unwrap()))
})
.and_then(|(c, story)| {
let author = story.get::<u32, _>("user_id").unwrap();
let id = story.get::<u32, _>("id").unwrap();
c.drop_exec(
"SELECT `users`.* FROM `users` WHERE `users`.`id` = ?",
(author,),
)
.map(move |c| (c, id))
})
.and_then(move |(c, story)| {
let fut = if let Some(parent) = parent {
// check that parent exists
futures::future::Either::A(
c.first_exec::<_, _, my::Row>(
"SELECT `comments`.* FROM `comments` \
WHERE `comments`.`story_id` = ? \
AND `comments`.`short_id` = ?",
(story, ::std::str::from_utf8(&parent[..]).unwrap()),
)
.map(move |(c, p)| {
if let Some(p) = p {
(
c,
Some((
p.get::<u32, _>("id").unwrap(),
p.get::<Option<u32>, _>("thread_id").unwrap(),
)),
)
} else {
eprintln!(
"failed to find parent comment {} in story {}",
::std::str::from_utf8(&parent[..]).unwrap(),
story
);
(c, None)
}
}),
)
} else {
futures::future::Either::B(futures::future::ok((c, None)))
};
fut.map(move |(c, parent)| (c, story, parent))
})
.map(|c| {
// TODO: real site checks for recent comments by same author with same
// parent to ensure we don't double-post accidentally
c
})
.and_then(move |(c, story, parent)| {
// check that short id is available
c.drop_exec(
"SELECT 1 AS one FROM `comments` \
WHERE `comments`.`short_id` = ?",
(::std::str::from_utf8(&id[..]).unwrap(),),
let (c, story) = c
.first_exec::<_, _, my::Row>(
"SELECT `stories`.* \
FROM `stories` \
WHERE `stories`.`short_id` = ?",
(::std::str::from_utf8(&story[..]).unwrap(),),
)
.await?;
let story = story.unwrap();
let author = story.get::<u32, _>("user_id").unwrap();
let story = story.get::<u32, _>("id").unwrap();
c = c
.drop_exec(
"SELECT `users`.* FROM `users` WHERE `users`.`id` = ?",
(author,),
)
.await?;

let parent = if let Some(parent) = parent {
// check that parent exists
let (x, p) = c
.first_exec::<_, _, my::Row>(
"SELECT `comments`.* FROM `comments` \
WHERE `comments`.`story_id` = ? \
AND `comments`.`short_id` = ?",
(story, ::std::str::from_utf8(&parent[..]).unwrap()),
)
.map(move |c| (c, story, parent))
})
.and_then(move |(c, story, parent)| {
// TODO: real impl checks *new* short_id *again*
.await?;
c = x;

if let Some(p) = p {
Some((
p.get::<u32, _>("id").unwrap(),
p.get::<Option<u32>, _>("thread_id").unwrap(),
))
} else {
eprintln!(
"failed to find parent comment {} in story {}",
::std::str::from_utf8(&parent[..]).unwrap(),
story
);
None
}
} else {
None
};

// TODO: real site checks for recent comments by same author with same
// parent to ensure we don't double-post accidentally

// check that short id is available
c = c
.drop_exec(
"SELECT 1 AS one FROM `comments` \
WHERE `comments`.`short_id` = ?",
(::std::str::from_utf8(&id[..]).unwrap(),),
)
.await?;

// TODO: real impl checks *new* short_id *again*

// NOTE: MySQL technically does everything inside this and_then in a transaction,
// but let's be nice to it
let now = chrono::Local::now().naive_local();
let q = if let Some((parent, thread)) = parent {
c.prep_exec(
"INSERT INTO `comments` \
(`created_at`, `updated_at`, `short_id`, `story_id`, \
`user_id`, `parent_comment_id`, `thread_id`, \
`comment`, `markeddown_comment`) \
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)",
(
now,
now,
::std::str::from_utf8(&id[..]).unwrap(),
story,
user,
parent,
thread,
"moar benchmarking", // lorem ipsum?
"<p>moar benchmarking</p>\n",
),
)
.await?
} else {
c.prep_exec(
"INSERT INTO `comments` \
(`created_at`, `updated_at`, `short_id`, `story_id`, \
`user_id`, `comment`, `markeddown_comment`) \
VALUES (?, ?, ?, ?, ?, ?, ?)",
(
now,
now,
::std::str::from_utf8(&id[..]).unwrap(),
story,
user,
"moar benchmarking", // lorem ipsum?
"<p>moar benchmarking</p>\n",
),
)
.await?
};
let comment = q.last_insert_id().unwrap();
let c = q.drop_result().await?;
// but why?!
c = c
.drop_exec(
"SELECT `votes`.* FROM `votes` \
WHERE `votes`.`user_id` = ? \
AND `votes`.`story_id` = ? \
AND `votes`.`comment_id` = ?",
(user, story, comment),
)
.await?;
c = c
.drop_exec(
"INSERT INTO `votes` \
(`user_id`, `story_id`, `comment_id`, `vote`) \
VALUES (?, ?, ?, ?)",
(user, story, comment, 1),
)
.await?;

// NOTE: MySQL technically does everything inside this and_then in a transaction,
// but let's be nice to it
let now = chrono::Local::now().naive_local();
if let Some((parent, thread)) = parent {
futures::future::Either::A(c.prep_exec(
"INSERT INTO `comments` \
(`created_at`, `updated_at`, `short_id`, `story_id`, \
`user_id`, `parent_comment_id`, `thread_id`, \
`comment`, `markeddown_comment`) \
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)",
(
now,
now,
::std::str::from_utf8(&id[..]).unwrap(),
story,
user,
parent,
thread,
"moar benchmarking", // lorem ipsum?
"<p>moar benchmarking</p>\n",
),
))
} else {
futures::future::Either::B(c.prep_exec(
"INSERT INTO `comments` \
(`created_at`, `updated_at`, `short_id`, `story_id`, \
`user_id`, `comment`, `markeddown_comment`) \
VALUES (?, ?, ?, ?, ?, ?, ?)",
(
now,
now,
::std::str::from_utf8(&id[..]).unwrap(),
story,
user,
"moar benchmarking", // lorem ipsum?
"<p>moar benchmarking</p>\n",
),
))
}
.and_then(|q| {
let comment = q.last_insert_id().unwrap();
q.drop_result().map(move |t| (t, comment))
})
.and_then(move |(t, comment)| {
// but why?!
t.drop_exec(
"SELECT `votes`.* FROM `votes` \
WHERE `votes`.`user_id` = ? \
AND `votes`.`story_id` = ? \
AND `votes`.`comment_id` = ?",
(user, story, comment),
)
.map(move |t| (t, comment))
})
.and_then(move |(t, comment)| {
t.drop_exec(
"INSERT INTO `votes` \
(`user_id`, `story_id`, `comment_id`, `vote`) \
VALUES (?, ?, ?, ?)",
(user, story, comment, 1),
)
})
})
.map(|c| (c, false)),
)
Ok((c, false))
}
Loading

0 comments on commit 1602be4

Please sign in to comment.