feat: realtime db pool

This commit is contained in:
Christy Jacob 2022-07-16 00:19:50 +04:00
parent 42f0bddd60
commit ebc971f8dc
3 changed files with 29 additions and 92 deletions

View file

@ -61,7 +61,7 @@ $http->on('start', function (Server $http) use ($payloadSize, $register) {
$redis = $register->get('redisPool')->get(); $redis = $register->get('redisPool')->get();
App::setResource('cache', fn() => $redis); App::setResource('cache', fn() => $redis);
$dbPool = $register->get('dbPool'); $dbPool = $register->get('dbPool');
[$dbForConsole, $returnDatabase] = $dbPool->getDBFromPool('console', $redis); [$dbForConsole, $returnDatabase] = $dbPool->getDBFromPool('console', $redis);
App::setResource('dbForConsole', fn() => $dbForConsole); App::setResource('dbForConsole', fn() => $dbForConsole);
@ -101,13 +101,6 @@ $http->on('start', function (Server $http) use ($payloadSize, $register) {
if (!$dbForConsole->getCollection($key)->isEmpty()) { if (!$dbForConsole->getCollection($key)->isEmpty()) {
continue; continue;
} }
/**
* Skip to prevent 0.15 migration issues.
*/
if ($key === 'databases' && $dbForConsole->exists(App::getEnv('_APP_DB_SCHEMA', 'appwrite'), 'collections')) {
continue;
}
Console::success('[Setup] - Creating collection: ' . $collection['$id'] . '...'); Console::success('[Setup] - Creating collection: ' . $collection['$id'] . '...');
$attributes = []; $attributes = [];

View file

@ -333,70 +333,48 @@ $server->onOpen(function (int $connection, SwooleRequest $request) use ($server,
$request = new Request($request); $request = new Request($request);
$response = new Response(new SwooleResponse()); $response = new Response(new SwooleResponse());
/** @var PDO $db */ App::setResource('request', fn() => $request);
$dbPool = $register->get('dbPool'); App::setResource('response', fn() => $response);
$consoleDB = $dbPool->getConsoleDBFromPool();
/** @var Redis $redis */ /** @var Redis $redis */
$redis = $register->get('redisPool')->get(); $redis = $register->get('redisPool')->get();
App::setResource('cache', fn() => $redis);
/** @var PDO $db */
$dbPool = $register->get('dbPool');
App::setResource('dbPool', fn() => $dbPool);
Console::info("Connection open (user: {$connection})"); Console::info("Connection open (user: {$connection})");
App::setResource('consoleDB', fn() => $consoleDB);
App::setResource('cache', fn () => $redis);
App::setResource('request', fn () => $request);
App::setResource('response', fn () => $response);
try { try {
/** @var \Utopia\Database\Document $project */
$project = $app->getResource('project');
/** @var \Utopia\Database\Document $console */ /** @var \Utopia\Database\Document $console */
$console = $app->getResource('console'); $console = $app->getResource('console');
$cache = new Cache(new RedisCache($redis)); [$dbForConsole, $returnConsoleDB] = $dbPool->getDBFromPool('console', $redis);
$database = new Database(new MariaDB($db), $cache); App::setResource('dbForConsole', fn() => $dbForConsole);
$database->setDefaultDatabase(App::getEnv('_APP_DB_SCHEMA', 'appwrite'));
$database->setNamespace("_{$project->getInternalId()}"); /** @var \Utopia\Database\Document $project */
$project = $app->getResource('project');
/* /*
* Project Check * Project Check
*/ */
// var_dump($project);
if (empty($project->getId())) { if (empty($project->getId())) {
throw new Exception('Missing or unknown project ID', 1008); throw new Exception('Missing or unknown project ID', 1008);
} }
$projectId = $project->getId(); [$dbForProject, $returnProjectDB] = $dbPool->getDBFromPool($project->getId(), $redis);
$projectDB = $consoleDB; App::setResource('dbForProject', fn() => $dbForProject);
if ($projectId !== 'console') {
$dbForConsole = $app->getResource('dbForConsole'); /** @var Utopia\Database\Database $dbForConsole */
$project = Authorization::skip(fn() => $dbForConsole->getDocument('projects', $projectId));
$dbName = $project->getAttribute('database', '');
if (!empty($dbName)) {
$projectDB = $dbPool->getDBFromPool($dbName);
}
}
App::setResource('projectDB', fn() => $projectDB);
/** @var \Utopia\Database\Document $user */ /** @var \Utopia\Database\Document $user */
$user = $app->getResource('user'); $user = $app->getResource('user');
/** @var \Utopia\Database\Document $console */
$console = $app->getResource('console');
$cache = new Cache(new RedisCache($redis));
$database = new Database(new MariaDB($projectDB), $cache);
$database->setDefaultDatabase(App::getEnv('_APP_DB_SCHEMA', 'appwrite'));
$database->setNamespace("_{$project->getId()}");
/* /*
* Abuse Check * Abuse Check
* *
* Abuse limits are connecting 128 times per minute and ip address. * Abuse limits are connecting 128 times per minute and ip address.
*/ */
$timeLimit = new TimeLimit('url:{url},ip:{ip}', 128, 60, $database); $timeLimit = new TimeLimit('url:{url},ip:{ip}', 128, 60, $dbForProject);
$timeLimit $timeLimit
->setParam('{ip}', $request->getIP()) ->setParam('{ip}', $request->getIP())
->setParam('{url}', $request->getURI()); ->setParam('{url}', $request->getURI());
@ -475,13 +453,8 @@ $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.
*/ */
/** @var PDOPool $consolePool */ call_user_func($returnConsoleDB);
$dbPool->putConsoleDb($consoleDB); call_user_func($returnProjectDB);
if (!empty($dbName) && !empty($projectDB)) {
$dbPool->put($projectDB, $dbName);
}
$register->get('redisPool')->put($redis); $register->get('redisPool')->put($redis);
} }
}); });
@ -489,43 +462,20 @@ $server->onOpen(function (int $connection, SwooleRequest $request) use ($server,
$server->onMessage(function (int $connection, string $message) use ($server, $register, $realtime, $containerId) { $server->onMessage(function (int $connection, string $message) use ($server, $register, $realtime, $containerId) {
try { try {
$response = new Response(new SwooleResponse()); $response = new Response(new SwooleResponse());
$dbPool = $register->get('dbPool'); $projectId = $realtime->connections[$connection]['projectId'];
$consoleDB = $dbPool->getConsoleDBFromPool();
$redis = $register->get('redisPool')->get(); $redis = $register->get('redisPool')->get();
$cache = new Cache(new RedisCache($redis));
$dbPool = $register->get('dbPool');
$projectId = $realtime->connections[$connection]['projectId']; [$dbForProject, $returnProjectDB] = $dbPool->getDBFromPool($projectId, $redis);
$projectDB = $consoleDB;
if ($projectId !== 'console') {
$dbForConsole = new Database(new MariaDB($projectDB), $cache);
$dbForConsole->setDefaultDatabase(App::getEnv('_APP_DB_SCHEMA', 'appwrite'));
$dbForConsole->setNamespace("_console");
$project = Authorization::skip(fn() => $dbForConsole->getDocument('projects', $projectId));
$dbName = $project->getAttribute('database', '');
if (!empty($dbName)) {
$projectDB = $dbPool->getDBFromPool($dbName);
}
}
$database = new Database(new MariaDB($projectDB), $cache);
$database->setDefaultDatabase(App::getEnv('_APP_DB_SCHEMA', 'appwrite'));
$database->setNamespace("_console");
$projectId = $realtime->connections[$connection]['projectId'];
if ($projectId !== 'console') {
$project = Authorization::skip(fn() => $database->getDocument('projects', $projectId));
$database->setNamespace("_{$project->getInternalId()}");
}
/* /*
* Abuse Check * Abuse Check
* *
* Abuse limits are sending 32 times per minute and connection. * Abuse limits are sending 32 times per minute and connection.
*/ */
$timeLimit = new TimeLimit('url:{url},connection:{connection}', 32, 60, $database); $timeLimit = new TimeLimit('url:{url},connection:{connection}', 32, 60, $dbForProject);
$timeLimit $timeLimit
->setParam('{connection}', $connection) ->setParam('{connection}', $connection)
@ -556,7 +506,7 @@ $server->onMessage(function (int $connection, string $message) use ($server, $re
Auth::$unique = $session['id'] ?? ''; Auth::$unique = $session['id'] ?? '';
Auth::$secret = $session['secret'] ?? ''; Auth::$secret = $session['secret'] ?? '';
$user = $database->getDocument('users', Auth::$unique); $user = $dbForProject->getDocument('users', Auth::$unique);
if ( if (
empty($user->getId()) // Check a document has been found in the DB empty($user->getId()) // Check a document has been found in the DB
@ -601,13 +551,7 @@ $server->onMessage(function (int $connection, string $message) use ($server, $re
$server->close($connection, $th->getCode()); $server->close($connection, $th->getCode());
} }
} finally { } finally {
/** @var PDOPool $consolePool */ call_user_func($returnProjectDB);
$dbPool->putConsoleDb($consoleDB);
if (!empty($dbName) && !empty($projectDB)) {
$dbPool->put($projectDB, $dbName);
}
$register->get('redisPool')->put($redis); $register->get('redisPool')->put($redis);
} }
}); });

View file

@ -130,7 +130,7 @@ class DatabasePool {
$cache = new Cache(new RedisCache($redis)); $cache = new Cache(new RedisCache($redis));
$database = new Database(new MariaDB($pdo), $cache); $database = new Database(new MariaDB($pdo), $cache);
$database->setDefaultDatabase(App::getEnv('_APP_DB_SCHEMA', 'appwrite')); $database->setDefaultDatabase(App::getEnv('_APP_DB_SCHEMA', 'appwrite'));
$namespace = "_project_console"; $namespace = "_console";
$database->setNamespace($namespace); $database->setNamespace($namespace);
$project = Authorization::skip(fn() => $database->getDocument('projects', $projectID)); $project = Authorization::skip(fn() => $database->getDocument('projects', $projectID));
@ -161,7 +161,7 @@ class DatabasePool {
$cache = new Cache(new RedisCache($redis)); $cache = new Cache(new RedisCache($redis));
$database = new Database(new MariaDB($pdo), $cache); $database = new Database(new MariaDB($pdo), $cache);
$database->setDefaultDatabase(App::getEnv('_APP_DB_SCHEMA', 'appwrite')); $database->setDefaultDatabase(App::getEnv('_APP_DB_SCHEMA', 'appwrite'));
$namespace = "_project_$internalID"; $namespace = "_$internalID";
$database->setNamespace($namespace); $database->setNamespace($namespace);
return $database; return $database;
@ -186,7 +186,7 @@ class DatabasePool {
[$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_PROJECT_DB in .env", 500); $pool = $this->pools[$name] ?? throw new Exception("Database pool with name : $name not found. Check the value of _APP_PROJECT_DB in .env", 500);
$namespace = "_project_$internalID"; $namespace = "_$internalID";
$attempts = 0; $attempts = 0;
do { do {
try { try {