swoole-server.php 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376
  1. <?php
  2. error_reporting(0);
  3. use Swoole\Http\Request;
  4. use Swoole\Http\Response;
  5. $server = new swoole_http_server('0.0.0.0', 8080, SWOOLE_BASE);
  6. $server->set([
  7. 'worker_num' => swoole_cpu_num(),
  8. 'log_file' => '/dev/null',
  9. 'log_level' => 5,
  10. 'open_tcp_nodelay' => true,
  11. ]);
  12. $pool = new \DatabasePool('postgres');
  13. /**
  14. * On start of the PHP worker. One worker per server process is started.
  15. */
  16. $server->on('workerStart', function ($srv) use ($pool) {
  17. $pool->init(\intdiv(512, $srv->setting['worker_num']));
  18. });
  19. /**
  20. * The DB test
  21. *
  22. * @param string $database_type
  23. * @param int $queries
  24. *
  25. * @return string
  26. */
  27. $db_postgres = function (int $queries = 0) use ($pool): string {
  28. $db = $pool->get();
  29. // Read number of queries to run from URL parameter
  30. $query_count = 1;
  31. if ($queries > 1) {
  32. $query_count = $queries > 500 ? 500 : $queries;
  33. }
  34. // Create an array with the response string.
  35. $arr = [];
  36. $db->s ??= $db->prepare('s', 'SELECT id, randomnumber FROM World WHERE id = $1');
  37. // For each query, store the result set values in the response array
  38. while ($query_count--) {
  39. $id = mt_rand(1, 10000);
  40. $res = $db->execute('s', [$id]);
  41. $ret = $db->fetchAssoc($res);
  42. // Store result in array.
  43. $arr[] = ['id' => $id, 'randomnumber' => $ret['randomnumber']];
  44. }
  45. // Use the PHP standard JSON encoder.
  46. // http://www.php.net/manual/en/function.json-encode.php
  47. if ($queries === -1) {
  48. $arr = $arr[0];
  49. }
  50. $pool->put($db);
  51. return \json_encode($arr, JSON_NUMERIC_CHECK);
  52. };
  53. /**
  54. * The Fortunes test
  55. *
  56. * @param string $database_type
  57. *
  58. * @return string
  59. */
  60. $fortunes_postgres = function () use ($pool): string {
  61. $db = $pool->get();
  62. $fortune = [];
  63. $db->f ??= $db->prepare('f', 'SELECT id, message FROM Fortune');
  64. $res = $db->execute('f', []);
  65. $arr = $db->fetchAll($res);
  66. foreach ($arr as $row) {
  67. $fortune[$row['id']] = $row['message'];
  68. }
  69. $fortune[0] = 'Additional fortune added at request time.';
  70. \asort($fortune);
  71. $html = '';
  72. foreach ($fortune as $id => $message) {
  73. $message = \htmlspecialchars($message, ENT_QUOTES, 'UTF-8');
  74. $html .= "<tr><td>{$id}</td><td>{$message}</td></tr>";
  75. }
  76. $pool->put($db);
  77. return '<!DOCTYPE html><html><head><title>Fortunes</title></head><body><table><tr><th>id</th><th>message</th></tr>'
  78. .$html.
  79. '</table></body></html>';
  80. };
  81. /**
  82. * The Updates test
  83. *
  84. * @param string $database_type
  85. * @param int $queries
  86. *
  87. * @return string
  88. */
  89. $updates_postgres = function (int $queries = 0) use ($pool): string {
  90. $db = $pool->get();
  91. $query_count = 1;
  92. if ($queries > 1) {
  93. $query_count = $queries > 500 ? 500 : $queries;
  94. }
  95. $arr = [];
  96. $db->us ??= $db->prepare('us', 'SELECT id,randomnumber FROM World WHERE id = $1');
  97. $db->uu ??= $db->prepare('uu', 'UPDATE World SET randomnumber = $1 WHERE id = $2');
  98. while ($query_count--) {
  99. $id = \mt_rand(1, 10000);
  100. $randomNumber = \mt_rand(1, 10000);
  101. $res = $db->execute('us', [$id]);
  102. $ret = $db->fetchAssoc($res);
  103. // Store result in array.
  104. $world = ['id' => $id, 'randomnumber' => $ret['randomnumber']];
  105. $world['randomnumber'] = $randomNumber;
  106. $res = $db->execute('uu', [$randomNumber, $id]);
  107. $arr[] = $world;
  108. }
  109. $pool->put($db);
  110. return \json_encode($arr, JSON_NUMERIC_CHECK);
  111. };
  112. /**
  113. * The DB test
  114. *
  115. * @param string $database_type
  116. * @param int $queries
  117. *
  118. * @return string
  119. */
  120. $db_mysql = function (int $queries = 0) use ($pool): string {
  121. $db = $pool->get();
  122. // Read number of queries to run from URL parameter
  123. $query_count = 1;
  124. if ($queries > 1) {
  125. $query_count = $queries > 500 ? 500 : $queries;
  126. }
  127. // Create an array with the response string.
  128. $arr = [];
  129. // Define query
  130. $db->db_test ??= $db->prepare('SELECT id, randomNumber FROM World WHERE id = ?');
  131. // For each query, store the result set values in the response array
  132. while ($query_count--) {
  133. $id = \mt_rand(1, 10000);
  134. $ret = $db->db_test->execute([$id]);
  135. // Store result in array.
  136. $arr[] = ['id' => $id, 'randomNumber' => $ret[0]['randomNumber']];
  137. }
  138. // Use the PHP standard JSON encoder.
  139. // http://www.php.net/manual/en/function.json-encode.php
  140. if ($queries === -1) {
  141. $arr = $arr[0];
  142. }
  143. $pool->put($db);
  144. return \json_encode($arr, JSON_NUMERIC_CHECK);
  145. };
  146. /**
  147. * The Fortunes test
  148. *
  149. * @param string $database_type
  150. *
  151. * @return string
  152. */
  153. $fortunes_mysql = function () use ($pool): string {
  154. $db = $pool->get();
  155. $fortune = [];
  156. $db->fortune_test ??= $db->prepare('SELECT id, message FROM Fortune');
  157. $arr = $db->fortune_test->execute();
  158. foreach ($arr as $row) {
  159. $fortune[$row['id']] = $row['message'];
  160. }
  161. $fortune[0] = 'Additional fortune added at request time.';
  162. \asort($fortune);
  163. $html = '';
  164. foreach ($fortune as $id => $message) {
  165. $message = \htmlspecialchars($message, ENT_QUOTES, 'UTF-8');
  166. $html .= "<tr><td>{$id}</td><td>{$message}</td></tr>";
  167. }
  168. $pool->put($db);
  169. return '<!DOCTYPE html><html><head><title>Fortunes</title></head><body><table><tr><th>id</th><th>message</th></tr>'
  170. .$html.
  171. '</table></body></html>';
  172. };
  173. /**
  174. * The Updates test
  175. *
  176. * @param string $database_type
  177. * @param int $queries
  178. *
  179. * @return string
  180. */
  181. $updates_mysql = function (int $queries = 0) use ($pool): string {
  182. $db = $pool->get();
  183. $query_count = 1;
  184. if ($queries > 1) {
  185. $query_count = $queries > 500 ? 500 : $queries;
  186. }
  187. $arr = [];
  188. $db->updates_test_select ??= $db->prepare('SELECT id,randomNumber FROM World WHERE id = ?');
  189. $db->updates_test_update ??= $db->prepare('UPDATE World SET randomNumber = ? WHERE id = ?');
  190. while ($query_count--) {
  191. $id = \mt_rand(1, 10000);
  192. $randomNumber = \mt_rand(1, 10000);
  193. $ret = $db->updates_test_select->execute([$id]);
  194. // Store result in array.
  195. $world = ['id' => $id, 'randomNumber' => $ret[0]['randomNumber']];
  196. $world['randomNumber'] = $randomNumber;
  197. $db->updates_test_update->execute([$randomNumber, $id]);
  198. $arr[] = $world;
  199. }
  200. $pool->put($db);
  201. return \json_encode($arr, JSON_NUMERIC_CHECK);
  202. };
  203. /**
  204. * On every request to the (web)server, execute the following code
  205. */
  206. $server->on('request', function (Request $req, Response $res) use ($db, $fortunes, $updates) {
  207. try {
  208. switch ($req->server['request_uri']) {
  209. case '/json':
  210. $res->header('Content-Type', 'application/json');
  211. $res->header('Server', 'openswoole');
  212. $res->end(json_encode(['message' => 'Hello, World!']));
  213. break;
  214. case '/plaintext':
  215. $res->header('Content-Type', 'text/plain; charset=utf-8');
  216. $res->header('Server', 'openswoole');
  217. $res->end('Hello, World!');
  218. break;
  219. case '/db':
  220. $res->header('Content-Type', 'application/json');
  221. $res->header('Server', 'openswoole');
  222. if (isset($req->get['queries'])) {
  223. $res->end($db((int)$req->get['queries']));
  224. } else {
  225. $res->end($db(-1));
  226. }
  227. break;
  228. case '/fortunes':
  229. $res->header('Content-Type', 'text/html; charset=utf-8');
  230. $res->header('Server', 'openswoole');
  231. $res->end($fortunes());
  232. break;
  233. case '/updates':
  234. $res->header('Content-Type', 'application/json');
  235. $res->header('Server', 'openswoole');
  236. if (isset($req->get['queries'])) {
  237. $res->end($updates((int)$req->get['queries']));
  238. } else {
  239. $res->end($updates(-1));
  240. }
  241. break;
  242. default:
  243. $res->status(404);
  244. $res->end('Error 404');
  245. }
  246. } catch (\Throwable $e) {
  247. $res->status(500);
  248. $res->end('Error 500');
  249. }
  250. });
  251. $server->start();
  252. /**
  253. * Class DatabasePool
  254. *
  255. * Deal with the fact that Open Swoole 2.1.3 has no build in database pooling
  256. */
  257. class DatabasePool
  258. {
  259. private $server = [
  260. 'host' => '',
  261. 'user' => 'benchmarkdbuser',
  262. 'password' => 'benchmarkdbpass',
  263. 'database' => 'hello_world'
  264. ];
  265. private $pool;
  266. private $type;
  267. public function __construct($type)
  268. {
  269. $this->server['host'] = \gethostbyname('tfb-database');
  270. $this->type = $type;
  271. }
  272. public function init($capacity)
  273. {
  274. $this->pool=new \Swoole\Coroutine\Channel($capacity);
  275. while($capacity>0){
  276. $db=$this->createDbInstance();
  277. if($db!==false){
  278. $this->pool->push($db);
  279. $capacity--;
  280. }
  281. }
  282. }
  283. private function createDbInstance()
  284. {
  285. if ($this->type === 'postgres') {
  286. $db = new Swoole\Coroutine\PostgreSql;
  287. if ($db->connect("host={$this->server['host']} port=5432 dbname={$this->server['database']} user={$this->server['user']} password={$this->server['password']}")){
  288. return $db;
  289. }
  290. } else if($this->type === 'mysql') {
  291. $db = new Swoole\Coroutine\Mysql;
  292. if ($db->connect($this->server)){
  293. return $db;
  294. }
  295. }
  296. return false;
  297. }
  298. public function put($db)
  299. {
  300. $this->pool->push($db);
  301. }
  302. public function get()
  303. {
  304. return $this->pool->pop();
  305. }
  306. }