Skip to content

Commit

Permalink
Merge pull request #14480 from cowai/reconnect-db-notify
Browse files Browse the repository at this point in the history
Reconnect to DB after timeout for Notify command. Fixes #14479
  • Loading branch information
rullzer committed Mar 4, 2019
2 parents eb17558 + 1ac9a9a commit 243bc96
Showing 1 changed file with 56 additions and 11 deletions.
67 changes: 56 additions & 11 deletions apps/files_external/lib/Command/Notify.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
/**
* @copyright Copyright (c) 2016 Robin Appelman <robin@icewind.nl>
*
* @author Ari Selseng <ari@selseng.net>
* @author Robin Appelman <robin@icewind.nl>
* @author Roeland Jago Douma <roeland@famdouma.nl>
*
Expand All @@ -24,6 +25,7 @@

namespace OCA\Files_External\Command;

use Doctrine\DBAL\Exception\DriverException;
use OC\Core\Command\Base;
use OCA\Files_External\Lib\InsufficientDataForMeaningfulAnswerException;
use OCA\Files_External\Lib\StorageConfig;
Expand All @@ -35,6 +37,7 @@
use OCP\Files\Storage\IStorage;
use OCP\Files\StorageNotAvailableException;
use OCP\IDBConnection;
use OCP\ILogger;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
Expand All @@ -47,17 +50,15 @@ class Notify extends Base {
private $connection;
/** @var \OCP\DB\QueryBuilder\IQueryBuilder */
private $updateQuery;
/** @var ILogger */
private $logger;

function __construct(GlobalStoragesService $globalService, IDBConnection $connection) {
function __construct(GlobalStoragesService $globalService, IDBConnection $connection, ILogger $logger) {
parent::__construct();
$this->globalService = $globalService;
$this->connection = $connection;
// the query builder doesn't really like subqueries with parameters
$this->updateQuery = $this->connection->prepare(
'UPDATE *PREFIX*filecache SET size = -1
WHERE `path` = ?
AND `storage` IN (SELECT storage_id FROM *PREFIX*mounts WHERE mount_id = ?)'
);
$this->logger = $logger;
$this->updateQuery = $this->getUpdateQuery($this->connection);
}

protected function configure() {
Expand Down Expand Up @@ -143,9 +144,9 @@ protected function execute(InputInterface $input, OutputInterface $output) {
$this->logUpdate($change, $output);
}
if ($change instanceof IRenameChange) {
$this->markParentAsOutdated($mount->getId(), $change->getTargetPath());
$this->markParentAsOutdated($mount->getId(), $change->getTargetPath(), $output);
}
$this->markParentAsOutdated($mount->getId(), $change->getPath());
$this->markParentAsOutdated($mount->getId(), $change->getPath(), $output);
});
}

Expand All @@ -154,12 +155,21 @@ private function createStorage(StorageConfig $mount) {
return new $class($mount->getBackendOptions());
}

private function markParentAsOutdated($mountId, $path) {
private function markParentAsOutdated($mountId, $path, OutputInterface $output) {
$parent = ltrim(dirname($path), '/');
if ($parent === '.') {
$parent = '';
}
$this->updateQuery->execute([$parent, $mountId]);

try {
$this->updateQuery->execute([$parent, $mountId]);
} catch (DriverException $ex) {
$this->logger->logException($ex, ['app' => 'files_external', 'message' => 'Error while trying to mark folder as outdated', 'level' => ILogger::WARN]);
$this->connection = $this->reconnectToDatabase($this->connection, $output);
$output->writeln('<info>Needed to reconnect to the database</info>');
$this->updateQuery = $this->getUpdateQuery($this->connection);
$this->updateQuery->execute([$parent, $mountId]);
}
}

private function logUpdate(IChange $change, OutputInterface $output) {
Expand Down Expand Up @@ -188,6 +198,41 @@ private function logUpdate(IChange $change, OutputInterface $output) {
$output->writeln($text);
}

/**
* @return \Doctrine\DBAL\Statement
*/
private function getUpdateQuery(IDBConnection $connection) {
// the query builder doesn't really like subqueries with parameters
return $connection->prepare(
'UPDATE *PREFIX*filecache SET size = -1
WHERE `path` = ?
AND `storage` IN (SELECT storage_id FROM *PREFIX*mounts WHERE mount_id = ?)'
);
}

/**
* @return \OCP\IDBConnection
*/
private function reconnectToDatabase(IDBConnection $connection, OutputInterface $output) {
try {
$connection->close();
} catch (\Exception $ex) {
$this->logger->logException($ex, ['app' => 'files_external', 'message' => 'Error while disconnecting from DB', 'level' => ILogger::WARN]);
$output->writeln("<info>Error while disconnecting from database: {$ex->getMessage()}</info>");
}
while (!$connection->isConnected()) {
try {
$connection->connect();
} catch (\Exception $ex) {
$this->logger->logException($ex, ['app' => 'files_external', 'message' => 'Error while re-connecting to database', 'level' => ILogger::WARN]);
$output->writeln("<info>Error while re-connecting to database: {$ex->getMessage()}</info>");
sleep(60);
}
}
return $connection;
}


private function selfTest(IStorage $storage, INotifyHandler $notifyHandler, $verbose, OutputInterface $output) {
usleep(100 * 1000); //give time for the notify to start
$storage->file_put_contents('/.nc_test_file.txt', 'test content');
Expand Down

0 comments on commit 243bc96

Please sign in to comment.