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\Files\File;
use OCP\IDBConnection;
use OCP\Lock\ILockingProvider;
require_once __DIR__.'/../ExifFields.php';
@ -22,28 +23,54 @@ class TimelineWrite
use TimelineWritePlaces;
protected IDBConnection $connection;
protected LivePhoto $livePhoto;
protected ILockingProvider $lockingProvider;
public function __construct(
IDBConnection $connection,
LivePhoto $livePhoto
LivePhoto $livePhoto,
ILockingProvider $lockingProvider
) {
$this->connection = $connection;
$this->livePhoto = $livePhoto;
$this->lockingProvider = $lockingProvider;
}
/**
* Process a file to insert Exif data into the database.
*
* @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
*
* @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
if (!Index::isSupported($file)) {
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
$mtime = $file->getMtime();
$fileId = $file->getId();

View File

@ -27,14 +27,19 @@ use OCP\EventDispatcher\Event;
use OCP\EventDispatcher\IEventListener;
use OCP\Files\Events\Node\NodeTouchedEvent;
use OCP\Files\Events\Node\NodeWrittenEvent;
use Psr\Log\LoggerInterface;
class PostWriteListener implements IEventListener
{
private TimelineWrite $timelineWrite;
private LoggerInterface $logger;
public function __construct(TimelineWrite $timelineWrite)
{
public function __construct(
TimelineWrite $timelineWrite,
LoggerInterface $logger
) {
$this->timelineWrite = $timelineWrite;
$this->logger = $logger;
}
public function handle(Event $event): void
@ -64,6 +69,12 @@ class PostWriteListener implements IEventListener
// 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
{
$path = $file->getPath();
try {
$this->log("Indexing file {$file->getPath()}", true);
$this->log("Indexing file {$path}", true);
$this->timelineWrite->processFile($file);
} catch (\OCP\Lock\LockedException $e) {
$this->log("Skipping file {$path} due to lock\n", true);
} catch (\Exception $e) {
$this->error("Failed to index file {$file->getPath()}: {$e->getMessage()}");
$this->error("Failed to index file {$path}: {$e->getMessage()}");
} finally {
$this->tempManager->clean();
}