Reconnect to DB after timeout for Notify command. Fixes #14479

Signed-off-by: Ari Selseng <ari@selseng.net>
This commit is contained in:
Ari Selseng 2019-03-03 01:36:27 +01:00 committed by Robin Appelman
parent 3acee4f1b4
commit 576711ac19
No known key found for this signature in database
GPG Key ID: 42B69D8A64526EFB
1 changed files with 48 additions and 10 deletions

View File

@ -2,6 +2,7 @@
/** /**
* @copyright Copyright (c) 2016 Robin Appelman <robin@icewind.nl> * @copyright Copyright (c) 2016 Robin Appelman <robin@icewind.nl>
* *
* @author Ari Selseng <ari@selseng.net>
* @author Robin Appelman <robin@icewind.nl> * @author Robin Appelman <robin@icewind.nl>
* @author Roeland Jago Douma <roeland@famdouma.nl> * @author Roeland Jago Douma <roeland@famdouma.nl>
* *
@ -24,6 +25,7 @@
namespace OCA\Files_External\Command; namespace OCA\Files_External\Command;
use Doctrine\DBAL\Exception\DriverException;
use OC\Core\Command\Base; use OC\Core\Command\Base;
use OCA\Files_External\Lib\InsufficientDataForMeaningfulAnswerException; use OCA\Files_External\Lib\InsufficientDataForMeaningfulAnswerException;
use OCA\Files_External\Lib\StorageConfig; use OCA\Files_External\Lib\StorageConfig;
@ -52,12 +54,7 @@ class Notify extends Base {
parent::__construct(); parent::__construct();
$this->globalService = $globalService; $this->globalService = $globalService;
$this->connection = $connection; $this->connection = $connection;
// the query builder doesn't really like subqueries with parameters $this->updateQuery = $this->getUpdateQuery($this->connection);
$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 = ?)'
);
} }
protected function configure() { protected function configure() {
@ -143,9 +140,9 @@ class Notify extends Base {
$this->logUpdate($change, $output); $this->logUpdate($change, $output);
} }
if ($change instanceof IRenameChange) { 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 +151,20 @@ class Notify extends Base {
return new $class($mount->getBackendOptions()); return new $class($mount->getBackendOptions());
} }
private function markParentAsOutdated($mountId, $path) { private function markParentAsOutdated($mountId, $path, OutputInterface $output) {
$parent = ltrim(dirname($path), '/'); $parent = ltrim(dirname($path), '/');
if ($parent === '.') { if ($parent === '.') {
$parent = ''; $parent = '';
} }
try {
$this->updateQuery->execute([$parent, $mountId]); $this->updateQuery->execute([$parent, $mountId]);
} catch (DriverException $th) {
$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) { private function logUpdate(IChange $change, OutputInterface $output) {
@ -188,6 +193,39 @@ class Notify extends Base {
$output->writeln($text); $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) {
$output->writeln("<info>Error while disconnecting from database: {$ex->getMessage()}</info>");
}
while (!$connection->isConnected()) {
try {
$connection->connect();
} catch (\Exception $ex) {
$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) { private function selfTest(IStorage $storage, INotifyHandler $notifyHandler, $verbose, OutputInterface $output) {
usleep(100 * 1000); //give time for the notify to start usleep(100 * 1000); //give time for the notify to start
$storage->file_put_contents('/.nc_test_file.txt', 'test content'); $storage->file_put_contents('/.nc_test_file.txt', 'test content');