diff --git a/System/Abstracts/Pool.php b/System/Abstracts/Pool.php index 72b44915..42f43e53 100644 --- a/System/Abstracts/Pool.php +++ b/System/Abstracts/Pool.php @@ -6,6 +6,7 @@ namespace Snowflake\Abstracts; use Exception; +use HttpServer\Http\Context; use Swoole\Coroutine; use Swoole\Coroutine\Channel; @@ -99,6 +100,27 @@ abstract class Pool extends Component throw new Exception('Undefined system processing function.'); } + + /** + * @param array $config + * @param string $coroutineName + * @param callable $createHandler + */ + public function createConnect(array $config, string $coroutineName, callable $createHandler): void + { + if (Context::hasContext('create:connect:' . $coroutineName)) { + return; + } + Context::setContext('create:connect:' . $coroutineName, 1); + + $client = call_user_func($createHandler, ...$config); + + $this->push($coroutineName, $client); + + Context::deleteId('create:connect:' . $coroutineName); + } + + /** * @param $name * @return bool diff --git a/System/Pool/Connection.php b/System/Pool/Connection.php index 8ad44182..88b791b3 100644 --- a/System/Pool/Connection.php +++ b/System/Pool/Connection.php @@ -207,45 +207,44 @@ class Connection extends Pool return Context::getContext($coroutineName); } if ($this->size($coroutineName) < 1 && $this->hasCreate[$coroutineName] < $this->max) { - return $this->saveClient($coroutineName, $this->nowClient($coroutineName, $config)); + $this->newClient($config, $coroutineName); } - $connections = $client = $this->get($coroutineName); - if ($connections[1] instanceof PDO) { - return $this->saveClient($coroutineName, $connections[1]); + [$time, $connections] = $this->get($coroutineName); + if ($connections instanceof PDO) { + throw new Exception('Database exception.'); } - return $this->saveClient($coroutineName, $this->nowClient($coroutineName, $config)); + return Context::setContext($coroutineName, $connections); } /** - * @param $coroutineName - * @param $client - * @return mixed - */ - private function saveClient($coroutineName, $client): mixed - { - return Context::setContext($coroutineName, $client); - } - - - /** - * @param $coroutineName * @param $config - * @return PDO - * @throws Exception + * @param $coroutineName */ - private function nowClient($coroutineName, $config): PDO + private function newClient($config, $coroutineName) { - - $this->createConnect($coroutineName, ...$this->parseConfig($config)); - [$time, $client] = $this->get($coroutineName); - if ($number = Context::getContext('begin_' . $coroutineName, Coroutine::getCid())) { - $number > 0 && $client->beginTransaction(); - } - if ($this->creates === 0) { - $this->creates = Timer::tick(10000, [$this, 'Heartbeat_detection']); - } - return $client; + $this->createConnect($this->parseConfig($config, $coroutineName), $coroutineName, function ($cds, $username, $password, $charset, $coroutineName) { + $link = new PDO($cds, $username, $password, [ + PDO::ATTR_EMULATE_PREPARES => false, + PDO::ATTR_CASE => PDO::CASE_NATURAL, + PDO::ATTR_TIMEOUT => $this->timeout, + ]); + $link->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + $link->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, false); + $link->setAttribute(PDO::ATTR_ORACLE_NULLS, PDO::NULL_EMPTY_STRING); + if (!empty($charset)) { + $link->query('SET NAMES ' . $charset); + } + $this->success('create db client -> ' . $cds . ':' . $this->hasCreate[$coroutineName] . ':' . $this->size($coroutineName)); + $this->incr($coroutineName); + if ($number = Context::getContext('begin_' . $coroutineName, Coroutine::getCid())) { + $number > 0 && $link->beginTransaction(); + } + if ($this->creates === 0) { + $this->creates = Timer::tick(10000, [$this, 'Heartbeat_detection']); + } + return $link; + }); } @@ -253,9 +252,9 @@ class Connection extends Pool * @param $config * @return array */ - private function parseConfig($config): array + private function parseConfig($config, $name): array { - return [$config['cds'], $config['username'], $config['password'], $config['charset'] ?? 'utf8mb4']; + return [$config['cds'], $config['username'], $config['password'], $config['charset'] ?? 'utf8mb4', $name]; } @@ -359,37 +358,43 @@ class Connection extends Pool * @param string $charset * @throws Exception */ - public function createConnect($coroutineName, $cds, $username, $password, $charset = 'utf8mb4'): void - { - try { - if (Context::hasContext('at_create_db')) { - return; - } - Context::setContext('at_create_db',1); - $link = new PDO($cds, $username, $password, [ - PDO::ATTR_EMULATE_PREPARES => false, - PDO::ATTR_CASE => PDO::CASE_NATURAL, - PDO::ATTR_TIMEOUT => $this->timeout, - ]); - $link->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); - $link->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, false); - $link->setAttribute(PDO::ATTR_ORACLE_NULLS, PDO::NULL_EMPTY_STRING); - if (!empty($charset)) { - $link->query('SET NAMES ' . $charset); - } - $this->success('create db client -> ' . $cds . ':' . $this->hasCreate[$coroutineName] . ':' . $this->size($coroutineName)); - $this->incr($coroutineName); - $this->push($coroutineName, $link); - } catch (\Throwable $exception) { - $this->addError($cds . ' -> ' . $exception->getMessage()); - if ($exception->getCode() === 2006) { - $this->createConnect($coroutineName, $cds, $username, $password, $charset); - } - throw new Exception($exception->getMessage()); - } finally { - Context::deleteId('at_create_db'); - } - } +// public function createConnect($coroutineName, $cds, $username, $password, $charset = 'utf8mb4'): void +// { +// try { +// if (Context::hasContext('at_create_db')) { +// return; +// } +// Context::setContext('at_create_db', 1); +// $link = new PDO($cds, $username, $password, [ +// PDO::ATTR_EMULATE_PREPARES => false, +// PDO::ATTR_CASE => PDO::CASE_NATURAL, +// PDO::ATTR_TIMEOUT => $this->timeout, +// ]); +// $link->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); +// $link->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, false); +// $link->setAttribute(PDO::ATTR_ORACLE_NULLS, PDO::NULL_EMPTY_STRING); +// if (!empty($charset)) { +// $link->query('SET NAMES ' . $charset); +// } +// $this->success('create db client -> ' . $cds . ':' . $this->hasCreate[$coroutineName] . ':' . $this->size($coroutineName)); +// $this->incr($coroutineName); +// if ($number = Context::getContext('begin_' . $coroutineName, Coroutine::getCid())) { +// $number > 0 && $link->beginTransaction(); +// } +// if ($this->creates === 0) { +// $this->creates = Timer::tick(10000, [$this, 'Heartbeat_detection']); +// } +// $this->push($coroutineName, $link); +// } catch (\Throwable $exception) { +// $this->addError($cds . ' -> ' . $exception->getMessage()); +// if ($exception->getCode() === 2006) { +// $this->createConnect($coroutineName, $cds, $username, $password, $charset); +// } +// throw new Exception($exception->getMessage()); +// } finally { +// Context::deleteId('at_create_db'); +// } +// } /** * @param $coroutineName diff --git a/System/Pool/Redis.php b/System/Pool/Redis.php index a9a60714..41ee7946 100644 --- a/System/Pool/Redis.php +++ b/System/Pool/Redis.php @@ -58,7 +58,7 @@ class Redis extends Pool public function getByChannel($coroutineName, $config): mixed { if ($this->_create < $this->max && !$this->hasItem($coroutineName)) { - $this->createConnect($config, $coroutineName); + $this->newClient($config, $coroutineName); } [$time, $clients] = $this->get($coroutineName); if ($clients === null) { @@ -68,6 +68,29 @@ class Redis extends Pool } + private function newClient($config, $coroutineName) + { + $this->createConnect([$config, $coroutineName], $coroutineName, function ($config, $coroutineName) { + $redis = new SRedis(); + if (!$redis->connect($config['host'], (int)$config['port'], $config['timeout'])) { + throw new RedisConnectException(sprintf('The Redis Connect %s::%d Fail.', $config['host'], $config['port'])); + } + if (empty($config['auth']) || !$redis->auth($config['auth'])) { + throw new RedisConnectException(sprintf('Redis Error: %s, Host %s, Auth %s', $redis->getLastError(), $config['host'], $config['auth'])); + } + $this->success('create redis client -> ' . $config['host'] . ':' . $this->size($coroutineName)); + if (!isset($config['read_timeout'])) { + $config['read_timeout'] = 10; + } + $redis->select($config['databases']); + $redis->setOption(SRedis::OPT_READ_TIMEOUT, $config['read_timeout']); + $redis->setOption(SRedis::OPT_PREFIX, $config['prefix']); + + return $redis; + }); + } + + /** * @param $coroutineName * @param $client @@ -85,40 +108,40 @@ class Redis extends Pool * @param string $coroutineName * @throws Exception */ - private function createConnect(array $config, string $coroutineName): void - { - try { - if ($this->_create >= $this->max) { - return; - } - $this->_create += 1; - if (Context::hasContext('at_create_db')) { - return; - } - Context::setContext('at_create_db', 1); - $redis = new SRedis(); - if (!$redis->connect($config['host'], (int)$config['port'], $config['timeout'])) { - throw new RedisConnectException(sprintf('The Redis Connect %s::%d Fail.', $config['host'], $config['port'])); - } - if (empty($config['auth']) || !$redis->auth($config['auth'])) { - throw new RedisConnectException(sprintf('Redis Error: %s, Host %s, Auth %s', $redis->getLastError(), $config['host'], $config['auth'])); - } - $this->success('create redis client -> ' . $config['host'] . ':' . $this->size($coroutineName)); - if (!isset($config['read_timeout'])) { - $config['read_timeout'] = 10; - } - $redis->select($config['databases']); - $redis->setOption(SRedis::OPT_READ_TIMEOUT, $config['read_timeout']); - $redis->setOption(SRedis::OPT_PREFIX, $config['prefix']); - - $this->push($coroutineName, $redis); - } catch (\Throwable $exception) { - $this->addError($exception->getMessage()); - } finally { - Context::deleteId('at_create_db'); - } - - } +// private function createConnect(array $config, string $coroutineName): void +// { +// try { +// if ($this->_create >= $this->max) { +// return; +// } +// $this->_create += 1; +// if (Context::hasContext('at_create_db')) { +// return; +// } +// Context::setContext('at_create_db', 1); +// $redis = new SRedis(); +// if (!$redis->connect($config['host'], (int)$config['port'], $config['timeout'])) { +// throw new RedisConnectException(sprintf('The Redis Connect %s::%d Fail.', $config['host'], $config['port'])); +// } +// if (empty($config['auth']) || !$redis->auth($config['auth'])) { +// throw new RedisConnectException(sprintf('Redis Error: %s, Host %s, Auth %s', $redis->getLastError(), $config['host'], $config['auth'])); +// } +// $this->success('create redis client -> ' . $config['host'] . ':' . $this->size($coroutineName)); +// if (!isset($config['read_timeout'])) { +// $config['read_timeout'] = 10; +// } +// $redis->select($config['databases']); +// $redis->setOption(SRedis::OPT_READ_TIMEOUT, $config['read_timeout']); +// $redis->setOption(SRedis::OPT_PREFIX, $config['prefix']); +// +// $this->push($coroutineName, $redis); +// } catch (\Throwable $exception) { +// $this->addError($exception->getMessage()); +// } finally { +// Context::deleteId('at_create_db'); +// } +// +// } /** * @param array $config