diff --git a/apps/files_external/lib/Command/Notify.php b/apps/files_external/lib/Command/Notify.php index b859a825c809d..556687e693015 100644 --- a/apps/files_external/lib/Command/Notify.php +++ b/apps/files_external/lib/Command/Notify.php @@ -2,6 +2,7 @@ /** * @copyright Copyright (c) 2016 Robin Appelman * + * @author Ari Selseng * @author Robin Appelman * @author Roeland Jago Douma * @@ -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; @@ -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; @@ -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() { @@ -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); }); } @@ -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('Needed to reconnect to the database'); + $this->updateQuery = $this->getUpdateQuery($this->connection); + $this->updateQuery->execute([$parent, $mountId]); + } } private function logUpdate(IChange $change, OutputInterface $output) { @@ -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("Error while disconnecting from database: {$ex->getMessage()}"); + } + 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("Error while re-connecting to database: {$ex->getMessage()}"); + 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');