swoole-server.php 6.2 KB

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