Fixes album export by reducing memory usage of the scripts. #18
2
app.php
@ -27,6 +27,6 @@ set_error_handler('ErrorHandler::handleError');
|
||||
ini_set("display_errors", DEBUG ? "On" : "Off");
|
||||
|
||||
// The real magic starts here!
|
||||
ob_start();
|
||||
ob_start(null, 32768);
|
||||
|
|
||||
Dispatcher::dispatch();
|
||||
ob_end_flush();
|
||||
|
||||
@ -53,20 +53,6 @@ class Download extends HTMLController
|
||||
{
|
||||
$files = array();
|
||||
|
||||
$album_ids = array_merge(array($album->id_tag), $this->getChildAlbumIds($album->id_tag));
|
||||
foreach($album_ids as $album_id)
|
||||
{
|
||||
$iterator = AssetIterator::getByOptions(
|
||||
array(
|
||||
'id_tag' => $album_id
|
||||
)
|
||||
);
|
||||
while($asset = $iterator->Next())
|
||||
{
|
||||
$files[] = join(DIRECTORY_SEPARATOR, array('.', $asset->getSubdir(), $asset->getFilename()));
|
||||
|
minnozz
commented
Is this change still useful? It seems like an array with only paths ( Is this change still useful? It seems like an array with only paths (`$files`) and not the file contents should not get so large as to hit a memory limit.
Roflin
commented
In the old situation the export would fail on the first chunk leaving behind a .tar of ~0kb, This means that the list of files of an album of around 270 pictures already consumed a considerable amount of memory. So I would still like to keep this more "streaming" approach as a optimization. In the old situation the export would fail on the first chunk leaving behind a .tar of ~0kb, This means that the list of files of an album of around 270 pictures already consumed a considerable amount of memory. So I would still like to keep this more "streaming" approach as a optimization.
minnozz
commented
I don't think that's possible, because if the memory limit was hit while building the array of file names, there would be no tar file at all, since While I don't think the streaming approach is wrong, this feels like a premature optimization (and certainly one that should not be necessary). I don't think that's possible, because if the memory limit was hit while building the array of file names, there would be no tar file at all, since `tar` is invoked after `$files` has been built.
While I don't think the streaming approach is wrong, this feels like a premature optimization (and certainly one that should not be necessary).
|
||||
}
|
||||
}
|
||||
|
||||
$descriptorspec = array(
|
||||
|
minnozz
commented
Roflin
commented
I'm currently using ther tar's -T functionality to read a list of files in a file seperated by a "\0" byte. and I skipping the file all together by using - as the argument to -T and feeding it the files on STDIN. After a quick look at the passthru i don't think such a thing is possible. and I think i will run out of "command line" space to execute the tar command with passthru. I'm currently using ther tar's -T functionality to read a list of files in a file seperated by a "\0" byte. and I skipping the file all together by using - as the argument to -T and feeding it the files on STDIN. After a quick look at the passthru i don't think such a thing is possible. and I think i will run out of "command line" space to execute the tar command with passthru.
Aaron
commented
Agreed that I do not think the proposed solution to use Agreed that `passthru` is probably the better solution, especially if you're not expecting to handle anything on `STDOUT` or `STDERR`.
I do not think the proposed solution to use `STDIN` to manually feed filenames will provide much in the way of performance benefit. If anything, I think `tar` can enumerate files more quickly than a PHP script.
|
||||
0 => array('pipe', 'r'),
|
||||
1 => array('pipe', 'w'),
|
||||
@ -93,8 +79,19 @@ class Download extends HTMLController
|
||||
header('Content-Type: application/octet-stream');
|
||||
header('Content-Transfer-Encoding: binary');
|
||||
|
||||
foreach($files as $file)
|
||||
fwrite($pipes[0], $file . "\0");
|
||||
$album_ids = array_merge(array($album->id_tag), $this->getChildAlbumIds($album->id_tag));
|
||||
foreach($album_ids as $album_id)
|
||||
{
|
||||
$iterator = AssetIterator::getByOptions(
|
||||
array(
|
||||
|
Aaron
commented
This is an aside, but I'd like to stick to new-style (bracketed) arrays, that is This is an aside, but I'd like to stick to new-style (bracketed) arrays, that is `[]` instead of `array()`.
|
||||
'id_tag' => $album_id
|
||||
)
|
||||
);
|
||||
while($asset = $iterator->Next())
|
||||
{
|
||||
fwrite($pipes[0], join(DIRECTORY_SEPARATOR, array('.', $asset->getSubdir(), $asset->getFilename())) . "\0");
|
||||
}
|
||||
}
|
||||
|
||||
fclose($pipes[0]);
|
||||
|
||||
|
||||
I haven't looked at the rest of the framework, but you might want to consider disabling the output buffer before calling
tar. This code could then check whether an output buffer is still active withob_get_level.@aaron what are your thoughts on this? I'm not familiar enough to comment on this.
I agree with @minnozz; much better to disable it locally (i.e. in the download controller) with
ob_end_flush. In general, output buffering is quite useful.