1
0
Fork 0
mirror of synced 2024-07-08 07:55:48 +12:00

feat: review comments

This commit is contained in:
Christy Jacob 2022-08-03 00:26:45 +05:30
parent 9e183f8994
commit 561e7b43e1
6 changed files with 132 additions and 91 deletions

View file

@ -85,7 +85,7 @@ App::post('/v1/projects')
throw new Exception("'console' is a reserved project.", 400, Exception::PROJECT_RESERVED_PROJECT); throw new Exception("'console' is a reserved project.", 400, Exception::PROJECT_RESERVED_PROJECT);
} }
[$dbForProject, $returnDB, $dbName] = $dbPool->getAnyFromPool($cache); [$dbForProject, $dbName] = $dbPool->getAnyFromPool($cache);
$project = $dbForConsole->createDocument('projects', new Document([ $project = $dbForConsole->createDocument('projects', new Document([
'$id' => $projectId, '$id' => $projectId,
@ -161,8 +161,6 @@ App::post('/v1/projects')
$dbForProject->createCollection($key, $attributes, $indexes); $dbForProject->createCollection($key, $attributes, $indexes);
} }
call_user_func($returnDB);
$response->setStatusCode(Response::STATUS_CODE_CREATED); $response->setStatusCode(Response::STATUS_CODE_CREATED);
$response->dynamic($project, Response::MODEL_PROJECT); $response->dynamic($project, Response::MODEL_PROJECT);
}); });

View file

@ -2,6 +2,7 @@
require_once __DIR__ . '/../vendor/autoload.php'; require_once __DIR__ . '/../vendor/autoload.php';
use Appwrite\Database\DatabasePool;
use Appwrite\Utopia\Response; use Appwrite\Utopia\Response;
use Swoole\Process; use Swoole\Process;
use Swoole\Http\Server; use Swoole\Http\Server;
@ -63,8 +64,9 @@ $http->on('start', function (Server $http) use ($payloadSize, $register) {
App::setResource('cache', fn() => $redis); App::setResource('cache', fn() => $redis);
$dbPool = $register->get('dbPool'); $dbPool = $register->get('dbPool');
[$dbForConsole, $returnDatabase] = $dbPool->getDBFromPool('console', $redis); App::setResource('dbPool', fn() => $dbPool);
App::setResource('dbForConsole', fn() => $dbForConsole);
$dbForConsole = $app->getResource('dbForConsole'); /** @var Utopia\Database\Database $dbForConsole */
Console::success('[Setup] - Server database init started...'); Console::success('[Setup] - Server database init started...');
$collections = Config::getParam('collections', []); /** @var array $collections */ $collections = Config::getParam('collections', []); /** @var array $collections */
@ -196,7 +198,7 @@ $http->on('start', function (Server $http) use ($payloadSize, $register) {
$dbForConsole->createCollection('bucket_' . $bucket->getInternalId(), $attributes, $indexes); $dbForConsole->createCollection('bucket_' . $bucket->getInternalId(), $attributes, $indexes);
} }
call_user_func($returnDatabase); $dbPool->reset();
Console::success('[Setup] - Server database init completed...'); Console::success('[Setup] - Server database init completed...');
}); });
@ -236,13 +238,6 @@ $http->on('request', function (SwooleRequest $swooleRequest, SwooleResponse $swo
$dbPool = $register->get('dbPool'); $dbPool = $register->get('dbPool');
App::setResource('dbPool', fn() => $dbPool); App::setResource('dbPool', fn() => $dbPool);
[$dbForConsole, $returnConsoleDB] = $dbPool->getDBFromPool('console', $redis);
App::setResource('dbForConsole', fn() => $dbForConsole);
$projectId = $request->getParam('project', $request->getHeader('x-appwrite-project', 'console'));
[$dbForProject, $returnProjectDB] = $dbPool->getDBFromPool($projectId, $redis);
App::setResource('dbForProject', fn() => $dbForProject);
try { try {
Authorization::cleanRoles(); Authorization::cleanRoles();
Authorization::setRole('role:all'); Authorization::setRole('role:all');
@ -332,9 +327,8 @@ $http->on('request', function (SwooleRequest $swooleRequest, SwooleResponse $swo
$swooleResponse->end(\json_encode($output)); $swooleResponse->end(\json_encode($output));
} finally { } finally {
call_user_func($returnConsoleDB); $dbPool->reset();
call_user_func($returnProjectDB);
/** @var RedisPool $redisPool */ /** @var RedisPool $redisPool */
$redisPool = $register->get('redisPool'); $redisPool = $register->get('redisPool');
$redisPool->put($redis); $redisPool->put($redis);

View file

@ -861,25 +861,30 @@ App::setResource('console', function () {
]); ]);
}, []); }, []);
// App::setResource('dbForProject', function ($db, $cache, Document $project) { App::setResource('dbForProject', function ($dbPool, $cache, Document $project) {
// $cache = new Cache(new RedisCache($cache)); $database = $project->getAttribute('database', '');
if (empty($database)) {
$database = $dbPool->getConsoleDB();
}
$pdo = $dbPool->getDBFromPool($database);
$cache = new Cache(new RedisCache($cache));
$database = new Database(new MariaDB($pdo), $cache);
$database->setDefaultDatabase(App::getEnv('_APP_DB_SCHEMA', 'appwrite'));
$database->setNamespace("_{$project->getInternalId()}");
// $database = new Database(new MariaDB($db), $cache); return $database;
// $database->setDefaultDatabase(App::getEnv('_APP_DB_SCHEMA', 'appwrite')); }, ['dbPool', 'cache', 'project']);
// $database->setNamespace("_{$project->getInternalId()}");
// return $database; App::setResource('dbForConsole', function ($dbPool, $cache) {
// }, ['db', 'cache', 'project']); $database = $dbPool->getConsoleDB();
$pdo = $dbPool->getDBFromPool($database);
$cache = new Cache(new RedisCache($cache));
$database = new Database(new MariaDB($pdo), $cache);
$database->setDefaultDatabase(App::getEnv('_APP_DB_SCHEMA', 'appwrite'));
$database->setNamespace('_console');
// App::setResource('dbForConsole', function ($dbPool, $cache) { return $database;
// $cache = new Cache(new RedisCache($cache)); }, ['dbPool', 'cache']);
// $database = new Database(new MariaDB($db), $cache);
// $database->setDefaultDatabase(App::getEnv('_APP_DB_SCHEMA', 'appwrite'));
// $database->setNamespace('_console');
// return $database;
// }, ['dbPool', 'cache']);
App::setResource('deviceLocal', function () { App::setResource('deviceLocal', function () {
return new Local(); return new Local();

View file

@ -91,12 +91,12 @@ $server->error($logError);
function getDatabase(Registry &$register, string $projectID) function getDatabase(Registry &$register, string $projectID)
{ {
$redis = $register->get('redisPool')->get(); $redis = $register->get('redisPool')->get();
[$database, $returnDatabase] = $register->get('dbPool')->getDBFromPool($projectID, $redis); $database = $register->get('dbPool')->getDBFromPool($projectID, $redis);
return [ return [
$database, $database,
function () use ($register, $returnDatabase, $redis) { function () use ($register, $redis) {
call_user_func($returnDatabase); $register->get('dbPool')->reset();
$register->get('redisPool')->put($redis); $register->get('redisPool')->put($redis);
} }
]; ];
@ -345,7 +345,7 @@ $server->onOpen(function (int $connection, SwooleRequest $request) use ($server,
/** @var \Utopia\Database\Document $console */ /** @var \Utopia\Database\Document $console */
$console = $app->getResource('console'); $console = $app->getResource('console');
[$dbForConsole, $returnConsoleDB] = $dbPool->getDBFromPool('console', $redis); $dbForConsole = $dbPool->getDBFromPool('console', $redis);
App::setResource('dbForConsole', fn() => $dbForConsole); App::setResource('dbForConsole', fn() => $dbForConsole);
/** @var \Utopia\Database\Document $project */ /** @var \Utopia\Database\Document $project */
@ -358,7 +358,7 @@ $server->onOpen(function (int $connection, SwooleRequest $request) use ($server,
throw new Exception('Missing or unknown project ID', 1008); throw new Exception('Missing or unknown project ID', 1008);
} }
[$dbForProject, $returnProjectDB] = $dbPool->getDBFromPool($project->getId(), $redis); $dbForProject = $dbPool->getDBFromPool($project->getId(), $redis);
App::setResource('dbForProject', fn() => $dbForProject); App::setResource('dbForProject', fn() => $dbForProject);
/** @var \Utopia\Database\Document $user */ /** @var \Utopia\Database\Document $user */
@ -448,8 +448,7 @@ $server->onOpen(function (int $connection, SwooleRequest $request) use ($server,
/** /**
* Put used PDO and Redis Connections back into their pools. * Put used PDO and Redis Connections back into their pools.
*/ */
call_user_func($returnConsoleDB); $dbPool->reset();
call_user_func($returnProjectDB);
$register->get('redisPool')->put($redis); $register->get('redisPool')->put($redis);
} }
}); });
@ -463,7 +462,7 @@ $server->onMessage(function (int $connection, string $message) use ($server, $re
$redis = $register->get('redisPool')->get(); $redis = $register->get('redisPool')->get();
$dbPool = $register->get('dbPool'); $dbPool = $register->get('dbPool');
[$dbForProject, $returnProjectDB] = $dbPool->getDBFromPool($projectId, $redis); $dbForProject = $dbPool->getDBFromPool($projectId, $redis);
/* /*
* Abuse Check * Abuse Check

View file

@ -7,10 +7,10 @@ use Utopia\App;
use Appwrite\DSN\DSN; use Appwrite\DSN\DSN;
use Utopia\CLI\Console; use Utopia\CLI\Console;
use Utopia\Cache\Cache; use Utopia\Cache\Cache;
use Swoole\Database\PDOPool;
use Swoole\Database\PDOProxy; use Swoole\Database\PDOProxy;
use Utopia\Database\Database; use Utopia\Database\Database;
use Appwrite\Extend\Exception; use Appwrite\Extend\Exception;
use Appwrite\Database\PDOPool;
use Swoole\Database\PDOConfig; use Swoole\Database\PDOConfig;
use Utopia\Database\Adapter\MariaDB; use Utopia\Database\Adapter\MariaDB;
use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Authorization;
@ -62,24 +62,23 @@ class DatabasePool
/** Create PDO pool instances for all the dsns */ /** Create PDO pool instances for all the dsns */
foreach ($this->dsns as $name => $dsn) { foreach ($this->dsns as $name => $dsn) {
$dsn = new DSN($dsn); $dsn = new DSN($dsn);
$pool = new PDOPool( $pdoConfig = (new PDOConfig())
(new PDOConfig()) ->withHost($dsn->getHost())
->withHost($dsn->getHost()) ->withPort($dsn->getPort())
->withPort($dsn->getPort()) ->withDbName($dsn->getDatabase())
->withDbName($dsn->getDatabase()) ->withCharset('utf8mb4')
->withCharset('utf8mb4') ->withUsername($dsn->getUser())
->withUsername($dsn->getUser()) ->withPassword($dsn->getPassword())
->withPassword($dsn->getPassword()) ->withOptions([
->withOptions([ PDO::ATTR_ERRMODE => App::isDevelopment() ? PDO::ERRMODE_WARNING : PDO::ERRMODE_SILENT, // If in production mode, warnings are not displayed
PDO::ATTR_ERRMODE => App::isDevelopment() ? PDO::ERRMODE_WARNING : PDO::ERRMODE_SILENT, // If in production mode, warnings are not displayed PDO::ATTR_TIMEOUT => 3, // Seconds
PDO::ATTR_TIMEOUT => 3, // Seconds PDO::ATTR_PERSISTENT => true,
PDO::ATTR_PERSISTENT => true, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, PDO::ATTR_EMULATE_PREPARES => true,
PDO::ATTR_EMULATE_PREPARES => true, PDO::ATTR_STRINGIFY_FETCHES => true
PDO::ATTR_STRINGIFY_FETCHES => true ]);
]),
64 $pool = new PDOPool($pdoConfig, 64);
);
$this->pools[$name] = $pool; $this->pools[$name] = $pool;
} }
@ -191,41 +190,37 @@ class DatabasePool
* *
* @return array * @return array
*/ */
public function getDBFromPool(string $projectID, \Redis $redis): array public function getDBFromPool(string $name): PDO|PDOProxy
{ {
/** Get DB name from the console database */ /** Get DB name from the console database */
[$name, $internalID] = $this->getName($projectID, $redis); // [$name, $internalID] = $this->getName($projectID, $redis);
$pool = $this->pools[$name] ?? throw new Exception("Database pool with name : $name not found. Check the value of _APP_DB_PROJECT in .env", 500); $pool = $this->pools[$name] ?? throw new Exception("Database pool with name : $name not found. Check the value of _APP_DB_PROJECT in .env", 500);
$pdo = $pool->get();
$namespace = "_$internalID"; // $namespace = "_$internalID";
$attempts = 0; // $attempts = 0;
do { // do {
try { // try {
$attempts++; // $attempts++;
$pdo = $pool->get(); // $pdo = $pool->get();
$database = $this->getDatabase($pdo, $redis); // $database = $this->getDatabase($pdo, $redis);
$database->setDefaultDatabase(App::getEnv('_APP_DB_SCHEMA', 'appwrite')); // $database->setDefaultDatabase(App::getEnv('_APP_DB_SCHEMA', 'appwrite'));
$database->setNamespace($namespace); // $database->setNamespace($namespace);
// if (!$database->exists($database->getDefaultDatabase(), 'metadata')) { // // if (!$database->exists($database->getDefaultDatabase(), 'metadata')) {
// throw new Exception('Collection not ready'); // // throw new Exception('Collection not ready');
// } // // }
break; // leave loop if successful // break; // leave loop if successful
} catch (\Exception $e) { // } catch (\Exception $e) {
Console::warning("Database not ready. Retrying connection ({$attempts})..."); // Console::warning("Database not ready. Retrying connection ({$attempts})...");
if ($attempts >= DATABASE_RECONNECT_MAX_ATTEMPTS) { // if ($attempts >= DATABASE_RECONNECT_MAX_ATTEMPTS) {
throw new \Exception('Failed to connect to database: ' . $e->getMessage()); // throw new \Exception('Failed to connect to database: ' . $e->getMessage());
} // }
sleep(DATABASE_RECONNECT_SLEEP); // sleep(DATABASE_RECONNECT_SLEEP);
} // }
} while ($attempts < DATABASE_RECONNECT_MAX_ATTEMPTS); // } while ($attempts < DATABASE_RECONNECT_MAX_ATTEMPTS);
return [ return $pdo;
$database,
function () use ($pdo, $name) {
$this->put($pdo, $name);
}
];
} }
/** /**
@ -261,13 +256,17 @@ class DatabasePool
return [ return [
$database, $database,
function () use ($pdo, $name) {
$this->put($pdo, $name);
},
$name $name
]; ];
} }
public function reset(): void
{
foreach ($this->pools as $pool) {
$pool->reset();
}
}
/** /**
* Return a PDO instance back to its database pool * Return a PDO instance back to its database pool
* *

View file

@ -0,0 +1,46 @@
<?php
namespace Appwrite\Database;
use Swoole\Database\PDOConfig;
use Swoole\Database\PDOPool as SwoolePDOPool;
class PDOPool
{
private array $activeConnections = [];
private SwoolePDOPool $pool;
public function __construct(PDOConfig $pdoConfig, int $size = SwoolePDOPool::DEFAULT_SIZE)
{
$this->pool = new SwoolePDOPool($pdoConfig, $size);
}
public function getActiveConnections()
{
return $this->activeConnections;
}
public function get(float $timeout = -1)
{
$connection = $this->pool->get($timeout);
$this->activeConnections[] = $connection;
return $connection;
}
public function put($connection): void
{
$this->pool->put($connection);
unset($this->activeConnections[array_search($connection, $this->activeConnections)]);
}
public function reset(): void
{
foreach($this->activeConnections as $connection) {
$this->pool->put($connection);
}
$this->activeConnections = [];
}
}