set([ 'worker_num' => swoole_cpu_num(), 'log_file' => '/dev/null', 'log_level' => 5, ]); $pool = new \DatabasePool('postgres'); /** * On start of the PHP worker. One worker per server process is started. */ $server->on('workerStart', function ($srv) use ($pool) { $pool->init(\intdiv(512, $srv->setting['worker_num'])); }); /** * The DB test * * @param string $database_type * @param int $queries * * @return string */ $db_postgres = function (int $queries = 0) use ($pool): string { $db = $pool->get(); // Read number of queries to run from URL parameter $query_count = 1; if ($queries > 1) { $query_count = $queries > 500 ? 500 : $queries; } // Create an array with the response string. $arr = []; $db->s ??= $db->prepare('s', 'SELECT id, randomnumber FROM World WHERE id = $1'); // For each query, store the result set values in the response array while ($query_count--) { $id = mt_rand(1, 10000); $res = $db->execute('s', [$id]); $ret = $db->fetchAssoc($res); // Store result in array. $arr[] = ['id' => $id, 'randomnumber' => $ret['randomnumber']]; } // Use the PHP standard JSON encoder. // http://www.php.net/manual/en/function.json-encode.php if ($queries === -1) { $arr = $arr[0]; } $pool->put($db); return \json_encode($arr, JSON_NUMERIC_CHECK); }; /** * The Fortunes test * * @param string $database_type * * @return string */ $fortunes_postgres = function () use ($pool): string { $db = $pool->get(); $fortune = []; $db->f ??= $db->prepare('f', 'SELECT id, message FROM Fortune'); $res = $db->execute('f', []); $arr = $db->fetchAll($res); foreach ($arr as $row) { $fortune[$row['id']] = $row['message']; } $fortune[0] = 'Additional fortune added at request time.'; \asort($fortune); $html = ''; foreach ($fortune as $id => $message) { $message = \htmlspecialchars($message, ENT_QUOTES, 'UTF-8'); $html .= "{$id}{$message}"; } $pool->put($db); return 'Fortunes' .$html. '
idmessage
'; }; /** * The Updates test * * @param string $database_type * @param int $queries * * @return string */ $updates_postgres = function (int $queries = 0) use ($pool): string { $db = $pool->get(); $query_count = 1; if ($queries > 1) { $query_count = $queries > 500 ? 500 : $queries; } $arr = []; $db->us ??= $db->prepare('us', 'SELECT id,randomnumber FROM World WHERE id = $1'); $db->uu ??= $db->prepare('uu', 'UPDATE World SET randomnumber = $1 WHERE id = $2'); while ($query_count--) { $id = \mt_rand(1, 10000); $randomNumber = \mt_rand(1, 10000); $res = $db->execute('us', [$id]); $ret = $db->fetchAssoc($res); // Store result in array. $world = ['id' => $id, 'randomnumber' => $ret['randomnumber']]; $world['randomnumber'] = $randomNumber; $res = $db->execute('uu', [$randomNumber, $id]); $arr[] = $world; } $pool->put($db); return \json_encode($arr, JSON_NUMERIC_CHECK); }; /** * The DB test * * @param string $database_type * @param int $queries * * @return string */ $db_mysql = function (int $queries = 0) use ($pool): string { $db = $pool->get(); // Read number of queries to run from URL parameter $query_count = 1; if ($queries > 1) { $query_count = $queries > 500 ? 500 : $queries; } // Create an array with the response string. $arr = []; // Define query $db->db_test ??= $db->prepare('SELECT id, randomNumber FROM World WHERE id = ?'); // For each query, store the result set values in the response array while ($query_count--) { $id = \mt_rand(1, 10000); $ret = $db->db_test->execute([$id]); // Store result in array. $arr[] = ['id' => $id, 'randomNumber' => $ret[0]['randomNumber']]; } // Use the PHP standard JSON encoder. // http://www.php.net/manual/en/function.json-encode.php if ($queries === -1) { $arr = $arr[0]; } $pool->put($db); return \json_encode($arr, JSON_NUMERIC_CHECK); }; /** * The Fortunes test * * @param string $database_type * * @return string */ $fortunes_mysql = function () use ($pool): string { $db = $pool->get(); $fortune = []; $db->fortune_test ??= $db->prepare('SELECT id, message FROM Fortune'); $arr = $db->fortune_test->execute(); foreach ($arr as $row) { $fortune[$row['id']] = $row['message']; } $fortune[0] = 'Additional fortune added at request time.'; \asort($fortune); $html = ''; foreach ($fortune as $id => $message) { $message = \htmlspecialchars($message, ENT_QUOTES, 'UTF-8'); $html .= "{$id}{$message}"; } $pool->put($db); return 'Fortunes' .$html. '
idmessage
'; }; /** * The Updates test * * @param string $database_type * @param int $queries * * @return string */ $updates_mysql = function (int $queries = 0) use ($pool): string { $db = $pool->get(); $query_count = 1; if ($queries > 1) { $query_count = $queries > 500 ? 500 : $queries; } $arr = []; $db->updates_test_select ??= $db->prepare('SELECT id,randomNumber FROM World WHERE id = ?'); $db->updates_test_update ??= $db->prepare('UPDATE World SET randomNumber = ? WHERE id = ?'); while ($query_count--) { $id = \mt_rand(1, 10000); $randomNumber = \mt_rand(1, 10000); $ret = $db->updates_test_select->execute([$id]); // Store result in array. $world = ['id' => $id, 'randomNumber' => $ret[0]['randomNumber']]; $world['randomNumber'] = $randomNumber; $db->updates_test_update->execute([$randomNumber, $id]); $arr[] = $world; } $pool->put($db); return \json_encode($arr, JSON_NUMERIC_CHECK); }; /** * On every request to the (web)server, execute the following code */ $server->on('request', function (Request $req, Response $res) use ($db, $fortunes, $updates) { try { switch ($req->server['request_uri']) { case '/json': $res->header('Content-Type', 'application/json'); $res->end(json_encode(['message' => 'Hello, World!'])); break; case '/plaintext': $res->header('Content-Type', 'text/plain; charset=utf-8'); $res->end('Hello, World!'); break; case '/db': $res->header('Content-Type', 'application/json'); if (isset($req->get['queries'])) { $res->end($db((int)$req->get['queries'])); } else { $res->end($db(-1)); } break; case '/fortunes': $res->header('Content-Type', 'text/html; charset=utf-8'); $res->end($fortunes()); break; case '/updates': $res->header('Content-Type', 'application/json'); if (isset($req->get['queries'])) { $res->end($updates((int)$req->get['queries'])); } else { $res->end($updates(-1)); } break; default: $res->status(404); $res->end('Error 404'); } } catch (\Throwable $e) { $res->status(500); $res->end('Error 500'); } }); $server->start(); /** * Class DatabasePool * * Deal with the fact that Swoole 2.1.3 has no build in database pooling */ class DatabasePool { private $server = [ 'host' => '', 'user' => 'benchmarkdbuser', 'password' => 'benchmarkdbpass', 'database' => 'hello_world' ]; private $pool; private $type; public function __construct($type) { $this->server['host'] = \gethostbyname('tfb-database'); $this->type = $type; } public function init($capacity) { $this->pool=new \Swoole\Coroutine\Channel($capacity); while($capacity>0){ $db=$this->createDbInstance(); if($db!==false){ $this->pool->push($db); $capacity--; } } } private function createDbInstance() { if ($this->type === 'postgres') { $db = new Swoole\Coroutine\PostgreSql; if ($db->connect("host={$this->server['host']} port=5432 dbname={$this->server['database']} user={$this->server['user']} password={$this->server['password']}")){ return $db; } } else if($this->type === 'mysql') { $db = new Swoole\Coroutine\Mysql; if ($db->connect($this->server)){ return $db; } } return false; } public function put($db) { $this->pool->push($db); } public function get() { return $this->pool->pop(); } }