freemarker-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Woonsan Ko <>
Subject Re: [FM3] Solving FM2 caching problems due to locale etc.
Date Tue, 21 Mar 2017 14:12:38 GMT
On Sat, Mar 18, 2017 at 6:47 PM, Daniel Dekany <> wrote:
> The problem in FM2
> ------------------
> In FM2, if you write `cfg.getTemplate("foo.ftl", Locale.GERMANY)`,
> then FreeMarker will return a Template where template.getLocale() is
> Locale.GERMANY, even if there's no foo_de.ftl or such, and it has just
> fallen back to the most generic foo.ftl template. In the template
> cache, we will have an entry like
>   ("foo.ftl", GERMANY) -> Template where getLocale() returns GERMANY
> Then if you do `cfg.getTemplate("foo.ftl", Locale.ITALY)`, then you
> will have yet another cache entry:
>   ("foo.ftl", ITALY) -> Template where getLocale() returns ITALY
> So far you loaded (I/O!) and parsed foo.ftl twice, and you also store
> the parsed template (the AST, which includes all the static text too)
> in the memory twice. You see the problem; you don't reuse a single
> Template object, despite there's not foo_de.ftl or foo_it.ftl. It's
> wasteful, and users has complained about it too (if you use the
> preferred locale of the browser of the visitor, the bloat can be
> disastrous).
> Actually, the are multiple Template properties that have the same
> problem (cache inefficiency):
> - locale: See earlier
> - name: This stores the name used for the lookup (such as for the
>   localized lookup, but note that the lookup strategy is pluggable).
>   This is the normalized form of what you pass to
>   Configuration.getTemplate(...).
> - customLookupCondition: Used by some custom lookup strategies. Also
>   passed to Configuration.getTemplate(...)
> - (There's also `encoding` and `parsed`, but those will get out of the
>   way according the proposal from 2017-02-06.)
> Possible solution  in FM3
> -------------------------
> We could introduce something like LookupIndependentTemplate, which
> stores:
> - The parsed template (the AST)
> - The sourceName of the template (it's the name used as the parameter
>   of the TemplateLoader that has actually loaded the template "file",
>   so this is past lookup)
> - The template specific configuration settings (provided by
>   the Configuration.templateConfigurations setting, also by the #ftl
>   header in the template)
> - Reference to the Configuration
> Then there's Template, which is familiar from FM2, but this time it
> only contains:
> - The lookup parameters:
>   - locale used for the lookup
>   - name (the one used for the lookup)
>   - customLookupCondition
> - The LookupIndependentTemplate. Multiple Template-s may use the same
>   LookupIndependentTemplate.
> The template cache split to two layers:
> - Level 1: Looks up the Template with the lookup parameters. So this
>   is very similar to the FM2 cache.
> - Level 2: Looks up the UnboundTempalate based solely on the
>   sourceName (the TemplateLoader parameter).

Is UnboundTemplate the same as LookupIndependentTemplate mentioned above?

> So if you have a level 1 cache miss (or stale entry hit), then during
> the lookup, we get the templates from the level 2 cache. So in the
> original example, you will still have two Template-s (one for GERMANY
> and one for ITALY), but they are quite light and share the single
> UnboundTemplate that belongs to "foo.ftl". You have two entries in the
> level 1 cache merely to speed up the lookup. (Though the lookup on top
> of a level 2 cache that has already warmed up is quite fast, because
> just as in FM2, we would cache negative results, on both levels. Like
> we cache the fact that there was no "foo_de_DE.ftl" and "foo_de.ftl".)
> A tricky corner case is when LookupIndependentTemplate itself stores a
> non-null Locale (it can, as a TemplateCofiguration can contain all
> runtime configuration settings), which differs from the Locale for
> which the template was successfully looked up. I guess then that
> should take precedence over Template.locale. (A possible use case: you
> might don't use localized lookup, and instead the template itself
> dictates the locale. After all, the static text in the template uses
> some language.)
> Any thoughts?

Everything sounds good. Your judgement on the tricky corner case makes
sense, too.
One consideration might be naming. It sounds like Template 'contains'
LookupIndependentTemplate. But the names sound like 'inheritance' to
me. ;-) So I wonder if there could be a better / more intuitive



> --
> Thanks,
>  Daniel Dekany

View raw message