Massively speed up indexing for local files

pull/37/head
Varun Patil 2022-08-23 09:19:19 +00:00
parent e9fab264fc
commit e933c1c457
2 changed files with 92 additions and 14 deletions

View File

@ -83,12 +83,6 @@ class Index extends Command {
} catch (ContainerExceptionInterface $e) { } catch (ContainerExceptionInterface $e) {
$this->globalService = null; $this->globalService = null;
} }
// Refuse to run without exiftool
if (!$this->testExif()) {
error_log('FATAL: exiftool could not be found or test failed');
exit(1);
}
} }
/** Make sure exiftool is available */ /** Make sure exiftool is available */
@ -115,6 +109,13 @@ class Index extends Command {
} }
protected function execute(InputInterface $input, OutputInterface $output): int { protected function execute(InputInterface $input, OutputInterface $output): int {
// Refuse to run without exiftool
\OCA\Memories\Exif::ensureStaticExiftoolProc();
if (!$this->testExif()) {
error_log('FATAL: exiftool could not be found or test failed');
exit(1);
}
if ($this->encryptionManager->isEnabled()) { if ($this->encryptionManager->isEnabled()) {
$output->writeln('Encryption is enabled. Aborted.'); $output->writeln('Encryption is enabled. Aborted.');
return 1; return 1;
@ -125,6 +126,9 @@ class Index extends Command {
$this->generateUserEntries($user); $this->generateUserEntries($user);
}); });
// Close the exiftool process
\OCA\Memories\Exif::closeStaticExiftoolProc();
return 0; return 0;
} }

View File

@ -8,6 +8,53 @@ use OCP\Files\File;
use OCP\IConfig; use OCP\IConfig;
class Exif { class Exif {
/** Opened instance of exiftool when running in command mode */
private static $staticProc = null;
private static $staticPipes = null;
private static $noStaticProc = false;
/** Initialize static exiftool process for local reads */
private static function initializeStaticExiftoolProc() {
self::closeStaticExiftoolProc();
self::$staticProc = proc_open(['exiftool', '-stay_open', 'true', '-@', '-'], [
0 => array('pipe', 'r'),
1 => array('pipe', 'w'),
2 => array('pipe', 'w'),
], self::$staticPipes);
}
public static function closeStaticExiftoolProc() {
try {
if (self::$staticProc) {
fclose(self::$staticPipes[0]);
fclose(self::$staticPipes[1]);
fclose(self::$staticPipes[2]);
proc_terminate(self::$staticProc);
}
} catch (\Exception $ex) {}
}
public static function ensureStaticExiftoolProc() {
if (self::$noStaticProc) {
return;
}
if (!self::$staticProc) {
self::initializeStaticExiftoolProc();
if (!proc_get_status(self::$staticProc)["running"]) {
error_log("Failed to create stay_open exiftool process");
self::$noStaticProc = true;
self::$staticProc = null;
}
return;
}
if (!proc_get_status(self::$staticProc)["running"]) {
self::$staticProc = null;
self::ensureStaticExiftoolProc();
}
}
/** /**
* Get the path to the user's configured photos directory. * Get the path to the user's configured photos directory.
* @param IConfig $config * @param IConfig $config
@ -47,7 +94,35 @@ class Exif {
} }
/** Get exif data as a JSON object from a local file path */ /** Get exif data as a JSON object from a local file path */
public static function getExifFromLocalPath(string $path) { public static function getExifFromLocalPath(string &$path) {
self::ensureStaticExiftoolProc();
if (!is_null(self::$staticProc)) {
return self::getExifFromLocalPathWithStaticProc($path);
} else {
return self::getExifFromLocalPathWithSeparateProc($path);
}
}
private static function getExifFromLocalPathWithStaticProc(string &$path) {
fwrite(self::$staticPipes[0], "$path\n-json\n-execute\n");
fflush(self::$staticPipes[0]);
$buf = "";
$readyToken = "\n{ready}\n";
while (!str_ends_with($buf, $readyToken)) {
$r = fread(self::$staticPipes[1], 1);
if ($r === false) {
error_log("Something went wrong with static exiftool process");
exit(1);
}
$buf .= $r;
}
$buf = substr($buf, 0, strrpos($buf, $readyToken));
return self::processStdout($buf);
}
private static function getExifFromLocalPathWithSeparateProc(string &$path) {
$pipes = []; $pipes = [];
$proc = proc_open(['exiftool', '-json', $path], [ $proc = proc_open(['exiftool', '-json', $path], [
1 => array('pipe', 'w'), 1 => array('pipe', 'w'),
@ -60,12 +135,7 @@ class Exif {
fclose($pipes[2]); fclose($pipes[2]);
proc_close($proc); proc_close($proc);
// Parse the json return self::processStdout($stdout);
$json = json_decode($stdout, true);
if (!$json) {
throw new \Exception('Could not read exif data');
}
return $json[0];
} }
/** /**
@ -94,7 +164,11 @@ class Exif {
fclose($pipes[2]); fclose($pipes[2]);
proc_close($proc); proc_close($proc);
// Parse the json return self::processStdout($stdout);
}
/** Get json array from stdout of exiftool */
private static function processStdout(string &$stdout) {
$json = json_decode($stdout, true); $json = json_decode($stdout, true);
if (!$json) { if (!$json) {
throw new \Exception('Could not read exif data'); throw new \Exception('Could not read exif data');