Gouri Sankar A created WW-5832:
----------------------------------
Summary: FreeMarker template cache is not bounded by default and
is keyed on the request-derived locale
Key: WW-5832
URL: https://issues.apache.org/jira/browse/WW-5832
Project: Struts 2
Issue Type: Bug
Components: Core
Affects Versions: 7.4.0, 7.3.0, 7.0.0, 6.12.0
Reporter: Gouri Sankar A
With struts.freemarker.mru.max.strong.size=0 (the default in
default.properties), FreemarkerManager.createConfiguration does not set a cache
storage, so FreeMarker's template cache uses its default SoftCacheStorage,
which has no entry limit. The cache key includes the locale. For actions that
provide a locale (LocaleProvider, for example ActionSupport), FreemarkerResult
uses the ActionContext locale, which by default comes from the request
(Accept-Language). Every distinct locale therefore adds template cache entries,
with no count bound. Same class as WW-5668 (localized-text caches, capped at
10000) and WW-5716 (Tiles locale caches, capped at 1000).
Reproduction (main, against a running Struts Boot app): an ActionSupport action
rendering a FreeMarker template, requested with 12,000 distinct Accept-Language
headers. The template cache (Configuration.getCacheStorage(), a
DefaultSoftCacheStorage) grew from 1 to 12,001 entries. Repeating the same
locales added none.
Impact: the entries are soft references, so this alone does not exhaust the
heap; they are kept until the GC clears them, and each locale re-reads and
re-parses the template.
Affected versions: the same createConfiguration code (no cache storage is set
when the value is 0, the default) is present in the 6.12.0, 7.0.0, 7.3.0 and
7.4.0 tags, by source inspection. The reproduction was only run on main.
Fix: when mru.max.strong.size is 0, use a SoftCacheStorage subclass that
empties itself at 10000 entries. It stays a ConcurrentCacheStorage, so lookups
remain lock-free (soft:10000 would create an MruCacheStorage, which
TemplateCache synchronizes on, see WW-3766). The strong:N path is unchanged.
The bound is approximate under concurrency.
Tests: FreemarkerManagerTest#testTemplateCacheIsBoundedByDefault (fails without
the change, passes with it). With the fix, the same 12,000-locale run on a live
app ends with 2,002 entries instead of 12,001.
--
This message was sent by Atlassian Jira
(v10.3.26#10030026)