Flesh out the connection pool class.
This commit is contained in:
parent
07b73e7f7f
commit
f5abbcb8c9
@ -15,7 +15,8 @@
|
|||||||
"dotenv-org/phpdotenv-vault": "^0.2.4",
|
"dotenv-org/phpdotenv-vault": "^0.2.4",
|
||||||
"react/react": "^1.4",
|
"react/react": "^1.4",
|
||||||
"robmorgan/phinx": "^0.16.1",
|
"robmorgan/phinx": "^0.16.1",
|
||||||
"react/mysql": "^0.7dev"
|
"react/mysql": "^0.7dev",
|
||||||
|
"react/async": "^4.3"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"phpunit/phpunit": "^11.1",
|
"phpunit/phpunit": "^11.1",
|
||||||
|
2
app/composer.lock
generated
2
app/composer.lock
generated
@ -4,7 +4,7 @@
|
|||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "525ed6c2ef7a52e8447108c1427f1b7d",
|
"content-hash": "df12c4f8e3bfd8ecbaa4864a9d702c27",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "cakephp/chronos",
|
"name": "cakephp/chronos",
|
||||||
|
@ -32,6 +32,3 @@ try {
|
|||||||
fprintf(STDERR, $e->getMessage() . "\n");
|
fprintf(STDERR, $e->getMessage() . "\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -15,7 +15,13 @@ interface ConnectionPoolInterface
|
|||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function hasIdleConnection(): bool;
|
public function hasIdleConnection(): bool;
|
||||||
public function setWaitTimeout(int $seconds): void;
|
|
||||||
|
/**
|
||||||
|
* Sets the new wait timeout for acquiring a connection.
|
||||||
|
*
|
||||||
|
* @param int $ms The amount of time in seconds.
|
||||||
|
*/
|
||||||
|
public function setWaitTimeout(int $s): void;
|
||||||
public function getWaitTimeout(): int;
|
public function getWaitTimeout(): int;
|
||||||
public function getConnectionLimit(): int;
|
public function getConnectionLimit(): int;
|
||||||
|
|
||||||
|
@ -2,65 +2,84 @@
|
|||||||
|
|
||||||
namespace Slovocast\Infrastructure\Database;
|
namespace Slovocast\Infrastructure\Database;
|
||||||
|
|
||||||
use React\Mysql\MysqlClient;
|
|
||||||
use Slovocast\Infrastructure\Api\Database\ConnectionPoolInterface;
|
use Slovocast\Infrastructure\Api\Database\ConnectionPoolInterface;
|
||||||
use Slovocast\Infrastructure\Api\Database\PooledConnectionInterface;
|
use Slovocast\Infrastructure\Api\Database\PooledConnectionInterface;
|
||||||
|
use SplObjectStorage;
|
||||||
|
|
||||||
class ConnectionPool implements ConnectionPoolInterface
|
class ConnectionPool implements ConnectionPoolInterface
|
||||||
{
|
{
|
||||||
/**
|
private int $waitTimeout;
|
||||||
* Set a default wait timeout for acquiring a connection to 100ms
|
private SplObjectStorage $idleConnections;
|
||||||
*/
|
private SplObjectStorage $activeConnections;
|
||||||
const int DEFAULT_WAIT_TIMEOUT = 100;
|
|
||||||
private array $idleConnections;
|
|
||||||
private array $activeConnections;
|
|
||||||
private ConnectionPoolConfig $config;
|
private ConnectionPoolConfig $config;
|
||||||
|
|
||||||
public function __construct(ConnectionPoolConfig $config)
|
public function __construct(ConnectionPoolConfig $config)
|
||||||
{
|
{
|
||||||
$this->config = $config;
|
$this->idleConnections = new SplObjectStorage();
|
||||||
for ($i = 0; $i < $config->getTotalConnections(); $i++) {
|
$this->activeConnections = new SplObjectStorage();
|
||||||
$this->idleConnections[] = new MysqlClient($this->config->getDsn());
|
|
||||||
|
for ($i = 0; $i < $this->config->getTotalConnections(); $i++) {
|
||||||
|
$pooledConnection = new PooledConnection($this->config->getDsnString());
|
||||||
|
$this->idleConnections->attach($$pooledConnection);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->waitTimeout = $config->getPoolWaitTimeout();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getTotalIdleConnections(): int
|
public function getTotalIdleConnections(): int
|
||||||
{
|
{
|
||||||
// TODO: Implement getTotalIdleConnections() method.
|
return $this->idleConnections->count();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getTotalActiveConnections(): int
|
public function getTotalActiveConnections(): int
|
||||||
{
|
{
|
||||||
// TODO: Implement getTotalActiveConnections() method.
|
return $this->activeConnections->count();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function hasIdleConnection(): bool
|
public function hasIdleConnection(): bool
|
||||||
{
|
{
|
||||||
// TODO: Implement hasIdleConnection() method.
|
return $this->idleConnections->count() > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setWaitTimeout(int $seconds): void
|
public function setWaitTimeout(int $s): void
|
||||||
{
|
{
|
||||||
// TODO: Implement setWaitTimeout() method.
|
$this->waitTimeout = $s;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getWaitTimeout(): int
|
public function getWaitTimeout(): int
|
||||||
{
|
{
|
||||||
// TODO: Implement getWaitTimeout() method.
|
return $this->waitTimeout;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getConnectionLimit(): int
|
public function getConnectionLimit(): int
|
||||||
{
|
{
|
||||||
// TODO: Implement getConnectionLimit() method.
|
return $this->config->getTotalConnections();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @TODO Throw an exception when a total timeout is exceeded. We do not want
|
||||||
|
* to get into an infinite loop.
|
||||||
|
*
|
||||||
|
* @return PooledConnectionInterface
|
||||||
|
*/
|
||||||
public function getConnection(): PooledConnectionInterface
|
public function getConnection(): PooledConnectionInterface
|
||||||
{
|
{
|
||||||
// TODO: Implement getConnection() method.
|
if (!$this->hasIdleConnection()) {
|
||||||
|
\React\Async\delay((float) $this->getWaitTimeout());
|
||||||
|
return this->getConnection();
|
||||||
|
}
|
||||||
|
|
||||||
|
$conn = $this->idleConnections->current();
|
||||||
|
$this->idleConnections->detach($conn);
|
||||||
|
$this->activeConnections->attach($conn);
|
||||||
|
return $conn;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function releaseConnection(PooledConnectionInterface $connection): void
|
public function releaseConnection(PooledConnectionInterface $connection): void
|
||||||
{
|
{
|
||||||
// TODO: Implement releaseConnection() method.
|
if ($this->activeConnections->contains($connection)) {
|
||||||
|
$this->activeConnections->detach($connection);
|
||||||
|
$this->idleConnections->attach($connection);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,18 +2,19 @@
|
|||||||
|
|
||||||
namespace Slovocast\Infrastructure\Database;
|
namespace Slovocast\Infrastructure\Database;
|
||||||
|
|
||||||
use React\Mysql\MysqlClient;
|
|
||||||
|
|
||||||
class ConnectionPoolConfig
|
class ConnectionPoolConfig
|
||||||
{
|
{
|
||||||
|
const DEFAULT_WAIT_TIMEOUT = 60;
|
||||||
|
const DEFAULT_TOTAL_CONNECTIONS = 10;
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
public readonly string $username,
|
public readonly string $username,
|
||||||
public readonly string $password,
|
public readonly string $password,
|
||||||
public readonly string $database,
|
public readonly string $database,
|
||||||
public readonly string $host,
|
public readonly string $host,
|
||||||
protected int $port = 3306,
|
protected int $port = 3306,
|
||||||
protected int $poolWaitTimeout = ConnectionPool::DEFAULT_WAIT_TIMEOUT,
|
protected int $poolWaitTimeout = self::DEFAULT_WAIT_TIMEOUT,
|
||||||
protected int $totalConnections = 10,
|
protected int $totalConnections = self::DEFAULT_TOTAL_CONNECTIONS
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
public function getPort(): int
|
public function getPort(): int
|
||||||
@ -31,7 +32,7 @@ class ConnectionPoolConfig
|
|||||||
return $this->totalConnections;
|
return $this->totalConnections;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getDsn(): string
|
public function getDsnString(): string
|
||||||
{
|
{
|
||||||
return sprintf(
|
return sprintf(
|
||||||
"%s:%s@%s/%s",
|
"%s:%s@%s/%s",
|
||||||
|
Loading…
Reference in New Issue
Block a user