Sitecore Language Fallback caching issue

Language Fallback is a powerful feature in Sitecore. It’s been around for years as a module and since Sitecore 8.1 it is part of the core product. In short, it allow values to be inherited between item language versions. This allows you to show default content when translation is missing. You may have dialects of a languages, such as US English vs British English, and you can use Language Fallback to avoid translating content that is the same for the two dialects etc.

TL;DR
Increase Caching.SmallCacheSize to about 10MB if you’re using Language Fallback in Sitecore.

Figuring out what value to actually render in a field becomes a bit more complex, and Sitecore uses a few additional caches to speed this up. However, I’ve found that one of them being incorrect configured by default. If you’re finding one of the following warning messages in your Sitecore log looking like this, you’re probably affected by this:


... WARN master[isLanguageFallbackValid] cache is cleared by ...
... WARN web[isLanguageFallbackValid] cache is cleared by ...

Background
Sitecore has a set of default named cache sizes:

Settings Name Default size
Caching.TinyCacheSize 10KB
Caching.SmallCacheSize 100KB
Caching.MediumCacheSize 1MB
Caching.LargeCacheSize 10MB
Caching.HugeCacheSize 100KM

Those cache sizes are sometimes referenced when a cache doesn’t have a specific size setting. The Language Fallback has a cache containing the validity of a fallback field. Essentially it just stores a boolean, “1” or “0”, for each entry in this cache. There is a cache for each database, so the name of the caches is “dbname[isLanguageFallbackValid]”, and its size is hard coded to Small cache size in DatabaseCaches.Initialize().

The issue
One would think that this wouldn’t be a problem. If we’re caching just a true/false value, wouldn’t 100KB be enough? Well, it turns out that behind the scenes, this isn’t performed in a very efficient way. The cached value is dependent on multiple parameters, making the cache key quite complex and large in size. In the Sitecore implementation, it uses a specific IsLanguageFallbackValidCacheKey object to describe the key. It contains the Item ID, the Field ID, the Language and, for some strange reason, the Database. (The cache is per database anyway).

In addition, the Item ID and Field ID is converted into strings. A Guid is 16 bytes in size. A Sitecore ID.ToString() becomes 38 characters, and a character in Windows is two bytes, so this 16 byte Guid suddenly becomes almost 80 bytes. So there is a lot of room for cache key size reduction here. The cache itself also of a “Indexed” cache type, so that gives a lot of overhead as well. As lists, hash tables etc grows, they also pre-allocate space for future objects.

The sum of all this is that an entry in this IsLanguageFallbackValidCache is almost a kilobyte each. So essentially only about 100 entries or so will fit in the cache. You probably have something in the magnitude of 100,000 field values in your solution if you find Language Fallback useful.

I took a snapshot of a running instance with increased cache size and analyzed it with dotMemory. As you can see, just 29,250 cached booleans occupies 57MB:
Memory dump of cache key

Memory dump of cache allocation

The solution
At the time of writing this, the only workaround is to increase the SmallCacheSize to a size that suits your solution. I found that 50-100MB was a good size for mine. You set the parameter in a config file, like this:

<?xml version="1.0" encoding="utf-8" ?>
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/" xmlns:set="http://www.sitecore.net/xmlconfig/set/">
  <sitecore>
    <settings>
      <setting name="Caching.SmallCacheSize" set:value="100MB" />
    </settings>
  </sitecore>
</configuration>

Look at the size of the cache in /sitecore/admin/cache.aspx and look for cache clear warnings in your logs to find a good balance that suits your solution.

A potential downside is that all other caches that use the “SmallCacheSize” is also changed. I’ve filed a wish to Sitecore to have a unique cache size settings for each cache and just use the pre-defined small/medium/large cache sizes as fallback.

When writing this, I have an open ticket on this too, and I assume Sitecore will come to the same conclusion that the cache key objects needs to be rewritten to reduce its memory foot print and the default size should be set to something like “MediumCacheSize”.

Leave a Reply