swoole-server.php 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  1. <?php
  2. use Swoole\Http\Request;
  3. use Swoole\Http\Response;
  4. $server = new swoole_http_server('0.0.0.0', 8080, SWOOLE_BASE);
  5. $server->set([
  6. 'worker_num' => swoole_cpu_num()
  7. ]);
  8. $pool = new DatabasePool();
  9. /**
  10. * The DB test
  11. *
  12. * @param string $database_type
  13. * @param int $queries
  14. *
  15. * @return string
  16. */
  17. $db = function (string $database_type, int $queries = 0) use ($pool): string {
  18. $db = $pool->get($database_type);
  19. // Read number of queries to run from URL parameter
  20. $query_count = 1;
  21. if ($queries > 1) {
  22. $query_count = $queries > 500 ? 500 : $queries;
  23. }
  24. // Create an array with the response string.
  25. $arr = [];
  26. // Define query
  27. $db->db_test = $db->db_test ?? $db->prepare('SELECT randomNumber FROM World WHERE id = ?');
  28. // For each query, store the result set values in the response array
  29. while ($query_count--) {
  30. $id = mt_rand(1, 10000);
  31. $ret = $db->db_test->execute([$id]);
  32. // Store result in array.
  33. $arr[] = ['id' => $id, 'randomNumber' => $ret[0]['randomNumber']];
  34. }
  35. // Use the PHP standard JSON encoder.
  36. // http://www.php.net/manual/en/function.json-encode.php
  37. if ($queries === -1) {
  38. $arr = $arr[0];
  39. }
  40. $pool->put($db);
  41. return json_encode($arr);
  42. };
  43. /**
  44. * The Fortunes test
  45. *
  46. * @param string $database_type
  47. *
  48. * @return string
  49. */
  50. $fortunes = function (string $database_type) use ($pool): string {
  51. $db = $pool->get($database_type);
  52. $fortune = [];
  53. $db->fortune_test = $db->fortune_test ?? $db->prepare('SELECT id, message FROM Fortune');
  54. $arr = $db->fortune_test->execute();
  55. foreach ($arr as $row) {
  56. $fortune[$row['id']] = $row['message'];
  57. }
  58. $fortune[0] = 'Additional fortune added at request time.';
  59. asort($fortune);
  60. $html = '';
  61. foreach ($fortune as $id => $message) {
  62. $message = htmlspecialchars($message, ENT_QUOTES, 'UTF-8');
  63. $html .= "<tr><td>{$id}</td><td>{$message}</td></tr>";
  64. }
  65. $pool->put($db);
  66. return '<!DOCTYPE html><html><head><title>Fortunes</title></head><body><table><tr><th>id</th><th>message</th></tr>'
  67. .$html.
  68. '</table></body></html>';
  69. };
  70. /**
  71. * The Updates test
  72. *
  73. * @param string $database_type
  74. * @param int $queries
  75. *
  76. * @return string
  77. */
  78. $updates = function (string $database_type, int $queries = 0) use ($pool): string {
  79. $db = $pool->get($database_type);
  80. $query_count = 1;
  81. if ($queries > 1) {
  82. $query_count = $queries > 500 ? 500 : $queries;
  83. }
  84. $arr = [];
  85. $db->updates_test_select = $db->updates_test_select ?? $db->prepare('SELECT randomNumber FROM World WHERE id = ?');
  86. $db->updates_test_update = $db->updates_test_update ?? $db->prepare('UPDATE World SET randomNumber = ? WHERE id = ?');
  87. while ($query_count--) {
  88. $id = mt_rand(1, 10000);
  89. $randomNumber = mt_rand(1, 10000);
  90. $ret = $db->updates_test_select->execute([$id]);
  91. // Store result in array.
  92. $world = ['id' => $id, 'randomNumber' => $ret[0]['randomNumber']];
  93. $world['randomNumber'] = $randomNumber;
  94. $db->updates_test_update->execute([$randomNumber, $id]);
  95. $arr[] = $world;
  96. }
  97. $pool->put($db);
  98. return json_encode($arr);
  99. };
  100. /**
  101. * On start of the PHP worker. One worker per server process is started.
  102. */
  103. //$server->on('workerStart', function () use ($pool) {
  104. //});
  105. /**
  106. * On every request to the (web)server, execute the following code
  107. */
  108. $server->on('request', function (Request $req, Response $res) use ($db, $fortunes, $updates) {
  109. try {
  110. switch ($req->server['request_uri']) {
  111. case '/json':
  112. $res->header('Content-Type', 'application/json');
  113. $res->end(json_encode(['message' => 'Hello, World!']));
  114. break;
  115. case '/plaintext':
  116. $res->header('Content-Type', 'text/plain; charset=utf-8');
  117. $res->end('Hello, World!');
  118. break;
  119. case '/db':
  120. $res->header('Content-Type', 'application/json');
  121. if (isset($req->get['queries'])) {
  122. $res->end($db('mysql', (int)$req->get['queries']));
  123. } else {
  124. $res->end($db('mysql', -1));
  125. }
  126. break;
  127. case '/fortunes':
  128. $res->header('Content-Type', 'text/html; charset=utf-8');
  129. $res->end($fortunes('mysql'));
  130. break;
  131. case '/updates':
  132. $res->header('Content-Type', 'application/json');
  133. if (isset($req->get['queries'])) {
  134. $res->end($updates('mysql', (int)$req->get['queries']));
  135. } else {
  136. $res->end($updates('mysql', -1));
  137. }
  138. break;
  139. case '/db_postgres':
  140. $res->header('Content-Type', 'application/json');
  141. if (isset($req->get['queries'])) {
  142. $res->end($db('postgres', (int)$req->get['queries']));
  143. } else {
  144. $res->end($db('postgres', -1));
  145. }
  146. break;
  147. case '/fortunes_postgres':
  148. $res->header('Content-Type', 'text/html; charset=utf-8');
  149. $res->end($fortunes('postgres'));
  150. break;
  151. case '/updates_postgres':
  152. $res->header('Content-Type', 'application/json');
  153. if (isset($req->get['queries'])) {
  154. $res->end($updates('postgres', (int)$req->get['queries']));
  155. } else {
  156. $res->end($updates('postgres', -1));
  157. }
  158. break;
  159. default:
  160. $res->status(404);
  161. $res->end('Error 404');
  162. }
  163. } catch (\Throwable $e) {
  164. $res->status(500);
  165. $res->end('Error 500');
  166. }
  167. });
  168. $server->start();
  169. /**
  170. * Class DatabasePool
  171. *
  172. * Deal with the fact that Swoole 2.1.3 has no build in database pooling
  173. */
  174. class DatabasePool
  175. {
  176. private $server = [
  177. 'host' => '',
  178. 'user' => 'benchmarkdbuser',
  179. 'password' => 'benchmarkdbpass',
  180. 'database' => 'hello_world'
  181. ];
  182. private $pool;
  183. private $pool_count = 0;
  184. function __construct()
  185. {
  186. $this->pool = new \SplQueue;
  187. $this->server['host'] = gethostbyname('tfb-database');
  188. }
  189. function put($db)
  190. {
  191. $this->pool->enqueue($db);
  192. $this->pool_count++;
  193. }
  194. function get(string $server_type)
  195. {
  196. if ($this->pool_count > 0) {
  197. $this->pool_count--;
  198. return $this->pool->dequeue();
  199. }
  200. // No idle connection, time to create a new connection
  201. if ($server_type === 'mysql') {
  202. $db = new Swoole\Coroutine\Mysql;
  203. }
  204. if ($server_type === 'postgres') {
  205. $db = new Swoole\Coroutine\PostgreSql;
  206. }
  207. $db->connect($this->server);
  208. return $db;
  209. }
  210. }