benchmark.cpp 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366
  1. #include <signal.h>
  2. #include <cstdlib>
  3. #include <string>
  4. #include <vector>
  5. #include <algorithm>
  6. #include <mutex>
  7. #include <Wt/WServer>
  8. #include <Wt/WResource>
  9. #include <Wt/Http/Request>
  10. #include <Wt/Http/Response>
  11. #include <Wt/WTemplate>
  12. #include <Wt/Utils>
  13. #include <Wt/Dbo/Dbo>
  14. #include <Wt/Dbo/Json>
  15. #ifndef BENCHMARK_USE_POSTGRES
  16. #include <Wt/Dbo/backend/MySQL>
  17. #else
  18. #include <Wt/Dbo/backend/Postgres>
  19. #endif
  20. #include <boost/random/uniform_int_distribution.hpp>
  21. #include <boost/random/taus88.hpp>
  22. #include <boost/thread/tss.hpp>
  23. class MyMessage {
  24. public:
  25. std::string message;
  26. template<class Action>
  27. void persist(Action& a) {
  28. Wt::Dbo::field(a, message, "message");
  29. }
  30. };
  31. class World {
  32. public:
  33. int randomNumber;
  34. template<class Action>
  35. void persist(Action& a) {
  36. Wt::Dbo::field(a, randomNumber, "randomnumber");
  37. }
  38. };
  39. class Fortune {
  40. public:
  41. std::string message;
  42. template<class Action>
  43. void persist(Action& a) {
  44. Wt::Dbo::field(a, message, "message");
  45. }
  46. };
  47. namespace Wt {
  48. namespace Dbo {
  49. template<>
  50. struct dbo_traits<World> : public dbo_default_traits {
  51. static const char *versionField() {
  52. return 0;
  53. }
  54. static IdType invalidId() {
  55. return 0;
  56. }
  57. };
  58. template<>
  59. struct dbo_traits<Fortune> : public dbo_default_traits {
  60. static const char *versionField() {
  61. return 0;
  62. }
  63. static IdType invalidId() {
  64. return 0;
  65. }
  66. };
  67. }
  68. }
  69. class JsonResource : public Wt::WResource {
  70. public:
  71. virtual void handleRequest(const Wt::Http::Request &request, Wt::Http::Response &response) {
  72. response.setMimeType("application/json");
  73. response.addHeader("Server", "Wt");
  74. MyMessage message;
  75. message.message = "Hello, World!";
  76. Wt::Dbo::JsonSerializer writer(response.out());
  77. writer.serialize(message);
  78. }
  79. };
  80. class MyConnection : public
  81. #ifdef BENCHMARK_USE_POSTGRES
  82. Wt::Dbo::backend::Postgres
  83. #else
  84. Wt::Dbo::backend::MySQL
  85. #endif
  86. {
  87. public:
  88. #ifdef BENCHMARK_USE_POSTGRES
  89. MyConnection(const std::string &db) :
  90. Wt::Dbo::backend::Postgres(db) {}
  91. #else
  92. MyConnection(const std::string &db, const std::string &dbuser, const std::string &dbpasswd, const std::string &dbhost, unsigned int dbport) :
  93. Wt::Dbo::backend::MySQL(db, dbuser, dbpasswd, dbhost, dbport) {}
  94. #endif
  95. virtual void startTransaction() { }
  96. virtual void commitTransaction() { }
  97. virtual void rollbackTransaction() { }
  98. };
  99. struct DbStruct {
  100. MyConnection connection;
  101. Wt::Dbo::Session session;
  102. boost::taus88 rng;
  103. boost::random::uniform_int_distribution<int> distribution;
  104. #ifndef BENCHMARK_USE_POSTGRES
  105. DbStruct() : connection("hello_world", "benchmarkdbuser", "benchmarkdbpass", "INSERT_DB_HOST_HERE", 3306),
  106. #else
  107. DbStruct() : connection("host=INSERT_DB_HOST_HERE port=5432 user=benchmarkdbuser password=benchmarkdbpass dbname=hello_world"),
  108. #endif
  109. rng(clock()),
  110. distribution(1, 10000) {
  111. session.setConnection(connection);
  112. session.mapClass<World>("world");
  113. session.mapClass<Fortune>("fortune");
  114. }
  115. int rand() {
  116. return distribution(rng);
  117. }
  118. };
  119. namespace {
  120. boost::thread_specific_ptr<DbStruct> dbStruct_;
  121. }
  122. class DbResource : public Wt::WResource {
  123. public:
  124. virtual void handleRequest(const Wt::Http::Request &request, Wt::Http::Response &response) {
  125. response.setMimeType("application/json");
  126. response.addHeader("Server", "Wt");
  127. DbStruct* db = dbStruct_.get();
  128. if (!db) {
  129. db = new DbStruct();
  130. dbStruct_.reset(db);
  131. }
  132. Wt::Dbo::Transaction transaction(db->session);
  133. Wt::Dbo::ptr<World> entry = db->session.load<World>(db->rand());
  134. Wt::Dbo::JsonSerializer writer(response.out());
  135. writer.serialize(entry);
  136. }
  137. };
  138. class QueriesResource : public Wt::WResource {
  139. public:
  140. virtual void handleRequest(const Wt::Http::Request &request, Wt::Http::Response &response) {
  141. int n;
  142. if (const std::string *queries = request.getParameter("queries")) {
  143. n = atoi(queries->c_str());
  144. if (n < 1)
  145. n = 1;
  146. else if (n > 500)
  147. n = 500;
  148. } else {
  149. n = 1;
  150. }
  151. response.setMimeType("application/json");
  152. response.addHeader("Server", "Wt");
  153. DbStruct* db = dbStruct_.get();
  154. if (!db) {
  155. db = new DbStruct();
  156. dbStruct_.reset(db);
  157. }
  158. Wt::Dbo::Transaction transaction(db->session);
  159. std::vector<Wt::Dbo::ptr<World> > results;
  160. results.reserve(n);
  161. for (int i = 0; i < n; ++i) {
  162. results.push_back(db->session.load<World>(db->rand()));
  163. }
  164. Wt::Dbo::JsonSerializer writer(response.out());
  165. writer.serialize(results);
  166. }
  167. };
  168. typedef Wt::Dbo::collection< Wt::Dbo::ptr<Fortune> > Fortunes;
  169. typedef std::vector<Wt::Dbo::ptr<Fortune> > VFortunes;
  170. bool fortuneCmp(const Wt::Dbo::ptr<Fortune>& f1, const Wt::Dbo::ptr<Fortune>& f2) {
  171. return strcmp(f1->message.c_str(), f2->message.c_str()) < 0;
  172. }
  173. class FortuneTemplate : public Wt::WTemplate {
  174. private:
  175. const VFortunes *fortunes_;
  176. mutable std::vector<Wt::Dbo::ptr<Fortune> >::const_iterator it_;
  177. public:
  178. FortuneTemplate(const std::vector<Wt::Dbo::ptr<Fortune> >& fortunes) : fortunes_(&fortunes), it_(fortunes.end()), Wt::WTemplate(Wt::WString::tr("fortunes")) {
  179. addFunction("while", &Wt::WTemplate::Functions::while_f);
  180. }
  181. virtual bool conditionValue(const std::string& name) const {
  182. if (name == "next-fortune") {
  183. if (it_ == fortunes_->end())
  184. it_ = fortunes_->begin();
  185. else
  186. ++it_;
  187. if (it_ == fortunes_->end())
  188. return false;
  189. return true;
  190. } else
  191. return Wt::WTemplate::conditionValue(name);
  192. }
  193. virtual void resolveString(const std::string& varName, const std::vector<Wt::WString>& vars, std::ostream& result) {
  194. if (varName == "id")
  195. result << it_->id();
  196. else if (varName == "message")
  197. format(result, Wt::WString::fromUTF8((*it_)->message));
  198. else
  199. Wt::WTemplate::resolveString(varName, vars, result);
  200. }
  201. };
  202. class FortuneResource : public Wt::WResource {
  203. public:
  204. virtual void handleRequest(const Wt::Http::Request &request, Wt::Http::Response &response) {
  205. response.setMimeType("text/html; charset=utf-8");
  206. response.addHeader("Server", "Wt");
  207. DbStruct* db = dbStruct_.get();
  208. if (!db) {
  209. db = new DbStruct();
  210. dbStruct_.reset(db);
  211. }
  212. Wt::Dbo::Transaction transaction(db->session);
  213. Fortunes fortunes = db->session.find<Fortune>();
  214. VFortunes vFortunes;
  215. for (Fortunes::const_iterator i = fortunes.begin(); i != fortunes.end(); ++i)
  216. vFortunes.push_back(*i);
  217. Fortune* additionalFortune = new Fortune();
  218. additionalFortune->message = "Additional fortune added at request time.";
  219. vFortunes.push_back(Wt::Dbo::ptr<Fortune>(additionalFortune));
  220. std::sort(vFortunes.begin(), vFortunes.end(), fortuneCmp);
  221. FortuneTemplate tpl(vFortunes);
  222. response.out() << "<!DOCTYPE html>";
  223. tpl.renderTemplate(response.out());
  224. }
  225. };
  226. class UpdateResource : public Wt::WResource {
  227. public:
  228. virtual void handleRequest(const Wt::Http::Request &request, Wt::Http::Response &response) {
  229. int n;
  230. if (const std::string *queries = request.getParameter("queries")) {
  231. n = atoi(queries->c_str());
  232. if (n < 1)
  233. n = 1;
  234. else if (n > 500)
  235. n = 500;
  236. } else {
  237. n = 1;
  238. }
  239. response.setMimeType("application/json");
  240. response.addHeader("Server", "Wt");
  241. DbStruct* db = dbStruct_.get();
  242. if (!db) {
  243. db = new DbStruct();
  244. dbStruct_.reset(db);
  245. }
  246. std::vector<Wt::Dbo::ptr<World> > results;
  247. for (int i = 0; i < n; ++i) {
  248. bool success = false;
  249. while (!success) {
  250. try {
  251. Wt::Dbo::Transaction transaction(db->session);
  252. Wt::Dbo::ptr<World> world = db->session.load<World>(db->rand());
  253. world.modify()->randomNumber = db->rand();
  254. transaction.commit();
  255. results.push_back(world);
  256. success = true;
  257. } catch (Wt::Dbo::Exception& e) {
  258. // Retry
  259. }
  260. }
  261. }
  262. Wt::Dbo::JsonSerializer writer(response.out());
  263. writer.serialize(results);
  264. }
  265. };
  266. class PlaintextResource : public Wt::WResource {
  267. virtual void handleRequest(const Wt::Http::Request &request, Wt::Http::Response &response) {
  268. response.setMimeType("text/plain");
  269. response.addHeader("Server", "Wt");
  270. response.out() << "Hello, World!";
  271. }
  272. };
  273. int main(int argc, char** argv) {
  274. try {
  275. Wt::WServer server(argv[0]);
  276. Wt::WMessageResourceBundle *bundle = new Wt::WMessageResourceBundle();
  277. bundle->use("fortunes");
  278. server.setLocalizedStrings(bundle);
  279. server.setServerConfiguration(argc, argv, WTHTTP_CONFIGURATION);
  280. JsonResource jsonResource;
  281. server.addResource(&jsonResource, "/json");
  282. DbResource dbResource;
  283. server.addResource(&dbResource, "/db");
  284. QueriesResource queriesResource;
  285. server.addResource(&queriesResource, "/queries");
  286. FortuneResource fortuneResource;
  287. server.addResource(&fortuneResource, "/fortune");
  288. UpdateResource updateResource;
  289. server.addResource(&updateResource, "/updates");
  290. PlaintextResource plaintextResource;
  291. server.addResource(&plaintextResource, "/plaintext");
  292. if (server.start()) {
  293. int sig = Wt::WServer::waitForShutdown(argv[0]);
  294. std::cerr << "Shutdown (signal = " << sig << ")" << std::endl;
  295. server.stop();
  296. if (sig == SIGHUP)
  297. Wt::WServer::restart(argc, argv, environ);
  298. }
  299. } catch (Wt::WServer::Exception& e) {
  300. std::cerr << e.what() << "\n";
  301. return 1;
  302. } catch (std::exception& e) {
  303. std::cerr << "exception: " << e.what() << "\n";
  304. return 1;
  305. }
  306. }