StyleURLChecker performance issue with local ExternalGraphic files on large shared data directory

We are seeing a significant WMS rendering slowdown after upgrading from a GeoServer version that did not have URL Checks to GeoServer 2.27.4, when SLD styles use local file-based ExternalGraphic resources in the GeoServer data directory.

The issue does not appear to be specific to the image format. We have reproduced it with both SVG and PNG external graphics. Disabling URL Checks resolves the performance issue. Adding a configured regex URL check for local style images also resolves it, which suggests the fallback StyleURLChecker path is the bottleneck.

Our GeoServer data directory is mounted in Kubernetes using cloud file storage. The issue appears to depend on the amount of content in the data directory. We only see the slowdown in an environment with a large data directory containing thousands of style files. A comparable environment with the same GeoServer version and storage setup, but a much smaller data directory, does not show the same performance issue.

From reading the code, StyleURLChecker calls getCanonicalFile() on both the external graphic path and the data directory root during each check. Since GeoTools ImageGraphicFactory.getIcon() calls URLCheckers.confirm(location) before using the image, this seems to happen repeatedly during point rendering.

Relevant code:

Workaround:

At present, our workaround is to add an explicit URL Check regex allowing local style images under the GeoServer data directory, so URL Checks remain enabled but local style images do not fall through to StyleURLChecker.

Example regex:

(?i)^file:/*/geoserver_data/data/(styles|workspaces/[^/]+/styles)/[^?#]+\.(png|gif|jpe?g|svg)(\?.*)?$

This allows local style images under:

  • /geoserver_data/data/styles/
  • /geoserver_data/data/workspaces/<workspace>/styles/

I also checked the current GeoServer 2.28.x, 3.0-RC.x, and main branches, and the relevant StyleURLChecker behaviour appears unchanged. GeoTools ImageGraphicFactory also still appears to call URLCheckers.confirm(location) before using the image cache.

Question:

Would the project consider caching URL check results for static external graphics with invalidation when URL Checks/config changes, or caching canonical data-directory paths inside StyleURLChecker?

Caching the “file to canonical paths” inside StyleURLChecker is probably better, but the cache would have to be:

  • Bounded (no more than N items in it, to prevent potential OOM or contribution to one)
  • The StyleURLChecker should become a GeoServerLifecycleHandler and drop the cache contents on reload/reset from the UI
  • The canonicalization might be invalidated if the paths involved a symlink that has been modified, I would probably add an expiry to the cache entries
  • Have a system variable that can act as a kill switch on the cache, disabling it completely

All of the above should be doable with a Guava cache… I hope

Cheers
Andrea