Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve Dockerman icon caching. #1146

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

dcflachs
Copy link
Contributor

@dcflachs dcflachs commented Aug 5, 2022

In 6.10.1+ the dockerman icon caching mechanism does not work correctly for icons specified by the net.unraid.docker.icon container label on containers without a dockerman template. For containers created with this label outside of dockerman the caching mechanism initially downloads and displays the correct icon. If the icon url is changed however the new icon is never downloaded because the old icon remains cached and there is no mechanism in place for invalidating the icon in the absence of a dockerman template. To fix this i propose the following changes to dockerman.

global $docroot, $dockerManPaths;
$imgUrl = $this->getTemplateValue($Repository, 'Icon','all',$contName);
if (!$imgUrl) $imgUrl = $tmpIconUrl;
$imgUrl = $iconUrl ?: $this->getTemplateValue($Repository, 'Icon','all',$contName);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Prefer iconUrl specified by container label if it exists.

$iconRAM = sprintf('%s/%s-%s.png', $dockerManPaths['images-ram'], $contName, 'icon');
$icon = sprintf('%s/%s-%s.png', $dockerManPaths['images'], $contName, 'icon');
$imgUrlHash = sha1($imgUrl);
$iconFile = sprintf('%s-%s.png', 'icon', $imgUrlHash);
Copy link
Contributor Author

@dcflachs dcflachs Aug 5, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of storing the icons by container name only, this change uses a sha1 hash of the imgUrl. This way a change to the icon url will automatically invalidate the cached icon.

$iconFile = sprintf('%s-%s.png', 'icon', $imgUrlHash);

$iconRAM = sprintf('%s/%s-%s', $dockerManPaths['images-ram'], $contName, $iconFile);
$icon = sprintf('%s/%s', $dockerManPaths['images'], $iconFile);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In images-ram the icon file name contains both the container name and the urlHash so that it is unique for each container.
In images the icons are store by urlHash alone. This has the benefit of storing only a single copy of identical icons.

}

return (is_file($iconRAM)) ? str_replace($docroot, '', $iconRAM) : '';
}

public function purgeUnusedIconFiles($contName, $keepIcon='') {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This new function better handles the more complex removal process for this caching mechanism.

if ( ($keepIcon === '') || !(strpos($filename, $keepIcon) !== false) ) {
@unlink($filename);
}
}
Copy link
Contributor Author

@dcflachs dcflachs Aug 5, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The first block removes all icons associated with contName in images-ram except the one specified by keepIcon.

@unlink($filename);
}
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The next block removes all icons stored in the old style from the images directory. Ideally this would only need to be run once when the caching mechanism was first upgraded to purge all old icons. Unfortunately i could not think of a good way to make that happen so i settled for always running this check.

@unlink($filename);
}
}
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The final block removes any of the shared icons in images that share the same hash as icons removed in the first block that are not referenced by another icon in images-ram.

if (!$imgUrl || trim($imgUrl) == "/plugins/dynamix.docker.manager/images/question.png") return '';

$imageName = $contName ?: $name;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I removed this line specifically because i could not figure out what it was doing. So far as i can tell $name is never set anywhere.

$iconPath = $DockerTemplates->getIcon($Repository,$Name);
@unlink("$docroot/$iconPath");
@unlink("{$dockerManPaths['images']}/".basename($iconPath));
$DockerTemplates->purgeUnusedIconFiles($Name);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since removing an icon from the cache is a bit more complex I use a new function specifically for that purpose.

@dcflachs
Copy link
Contributor Author

dcflachs commented Aug 5, 2022

My unRAID server has ~42 containers running with about ~30 unique icons. In my testing the changes to the caching mechanism do not seem to greatly effect the execution time of the getAllInfo function.

@@ -303,7 +303,7 @@ public function getAllInfo($reload=false,$com=true,$communityApplications=false)
if ($ct['Url'] && !$tmp['url']) $tmp['url'] = $ct['Url'];
if ($ct['Icon']) $tmp['icon'] = $ct['Icon'];
if ( ! $communityApplications ) {
if (!is_file($tmp['icon']) || $reload) $tmp['icon'] = $this->getIcon($image,$name,$tmp['icon']);
if (!is_file($tmp['icon']) || $reload) $tmp['icon'] = $this->getIcon($image,$name,$ct['Icon']);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this change is not made then subsequent calls to getAllInfo will invalidate the cache by passing in the icon file path via tmp['icon'] instead of the icon url.

@dcflachs
Copy link
Contributor Author

dcflachs commented Sep 3, 2022

Any chance you would have time to look this pull request over and provide feedback?
@limetech @bergware

@teambvd
Copy link

teambvd commented Dec 27, 2022

It'd be great to get some eyes on this whenever someone has time - I've got between 50 and 60 containers on each of my unraid servers, and loading the docker tab's gotten to feeling pretty clunky at this point, so any performance improvement would be great!

@dcflachs
Copy link
Contributor Author

dcflachs commented Dec 1, 2023

Rebased changes onto latest rev

@dcflachs
Copy link
Contributor Author

I would love to get some feedback on this issue and proposed fix.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants