tw: acquire lock before processing

Signed-off-by: Varun Patil <varunpatil@ucla.edu>
pull/579/head
Varun Patil 2023-04-15 12:02:07 -07:00
parent 039115d8f4
commit 9f62a23895
3 changed files with 50 additions and 8 deletions

View File

@ -9,6 +9,7 @@ use OCA\Memories\Service\Index;
use OCP\DB\QueryBuilder\IQueryBuilder; use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\Files\File; use OCP\Files\File;
use OCP\IDBConnection; use OCP\IDBConnection;
use OCP\Lock\ILockingProvider;
require_once __DIR__.'/../ExifFields.php'; require_once __DIR__.'/../ExifFields.php';
@ -22,28 +23,54 @@ class TimelineWrite
use TimelineWritePlaces; use TimelineWritePlaces;
protected IDBConnection $connection; protected IDBConnection $connection;
protected LivePhoto $livePhoto; protected LivePhoto $livePhoto;
protected ILockingProvider $lockingProvider;
public function __construct( public function __construct(
IDBConnection $connection, IDBConnection $connection,
LivePhoto $livePhoto LivePhoto $livePhoto,
ILockingProvider $lockingProvider
) { ) {
$this->connection = $connection; $this->connection = $connection;
$this->livePhoto = $livePhoto; $this->livePhoto = $livePhoto;
$this->lockingProvider = $lockingProvider;
} }
/** /**
* Process a file to insert Exif data into the database. * Process a file to insert Exif data into the database.
* *
* @param File $file File node to process * @param File $file File node to process
* @param bool $lock Lock the file before processing
* @param bool $force Update the record even if the file has not changed * @param bool $force Update the record even if the file has not changed
*
* @return bool True if the file was processed
*
* @throws \OCP\Lock\LockedException If the file is locked
* @throws \OCP\DB\Exception If the database query fails
*/ */
public function processFile(File $file, bool $force = false): bool public function processFile(
{ File $file,
bool $lock = true,
bool $force = false
): bool {
// Check if we want to process this file // Check if we want to process this file
if (!Index::isSupported($file)) { if (!Index::isSupported($file)) {
return false; return false;
} }
// Check if we need to lock the file
if ($lock) {
$lockKey = 'memories/'.$file->getId();
$lockType = ILockingProvider::LOCK_EXCLUSIVE;
try {
$this->lockingProvider->acquireLock($lockKey, $lockType);
return $this->processFile($file, false, $force);
} finally {
$this->lockingProvider->releaseLock($lockKey, $lockType);
}
}
// Get parameters // Get parameters
$mtime = $file->getMtime(); $mtime = $file->getMtime();
$fileId = $file->getId(); $fileId = $file->getId();

View File

@ -27,14 +27,19 @@ use OCP\EventDispatcher\Event;
use OCP\EventDispatcher\IEventListener; use OCP\EventDispatcher\IEventListener;
use OCP\Files\Events\Node\NodeTouchedEvent; use OCP\Files\Events\Node\NodeTouchedEvent;
use OCP\Files\Events\Node\NodeWrittenEvent; use OCP\Files\Events\Node\NodeWrittenEvent;
use Psr\Log\LoggerInterface;
class PostWriteListener implements IEventListener class PostWriteListener implements IEventListener
{ {
private TimelineWrite $timelineWrite; private TimelineWrite $timelineWrite;
private LoggerInterface $logger;
public function __construct(TimelineWrite $timelineWrite) public function __construct(
{ TimelineWrite $timelineWrite,
LoggerInterface $logger
) {
$this->timelineWrite = $timelineWrite; $this->timelineWrite = $timelineWrite;
$this->logger = $logger;
} }
public function handle(Event $event): void public function handle(Event $event): void
@ -64,6 +69,12 @@ class PostWriteListener implements IEventListener
// and getParent() is called on it. // and getParent() is called on it.
} }
$this->timelineWrite->processFile($node); try {
$this->timelineWrite->processFile($node);
} catch (\Exception $e) {
$this->logger->error('Memories failed to process file: {message}', [
'message' => $e->getMessage(),
]);
}
} }
} }

View File

@ -185,11 +185,15 @@ class Index
*/ */
public function indexFile(File $file): void public function indexFile(File $file): void
{ {
$path = $file->getPath();
try { try {
$this->log("Indexing file {$file->getPath()}", true); $this->log("Indexing file {$path}", true);
$this->timelineWrite->processFile($file); $this->timelineWrite->processFile($file);
} catch (\OCP\Lock\LockedException $e) {
$this->log("Skipping file {$path} due to lock\n", true);
} catch (\Exception $e) { } catch (\Exception $e) {
$this->error("Failed to index file {$file->getPath()}: {$e->getMessage()}"); $this->error("Failed to index file {$path}: {$e->getMessage()}");
} finally { } finally {
$this->tempManager->clean(); $this->tempManager->clean();
} }