The locale() function caches all available translations for a language on the first run.

If a string translation is not found, the negative result is only cached in the static variable $locale_t -- but not in the cache layer.

The attached patch caches the negative result in the cache layer, too.

Side effects: a new translation will only show up when the cache is invalidated -- but I hope that adding a new translation does that automatically.

CommentFileSizeAuthor
#2 locale-cache-1156452.patch1.1 KBteefax
locale.module.diff664 bytesteefax

Comments

damien tournoud’s picture

Status: Active » Postponed (maintainer needs more info)

This function caches two things in the DB: strings less then 75 characters and non-translated strings. I'm not completely sure what you are trying to fix here.

teefax’s picture

Version: 6.20 » 6.x-dev
StatusFileSize
new1.1 KB

OK, let me describe what I'm seeing here (I'm the server admin trying to make the site faster):

- Drupal 6.20 / 6.x
- Cacheing happens with memcache.module
- Site is set to 'de' language by default and there are quite some things which are not translated in the DB

On first page load:
- all existing translations are loaded, including the untranslated strings (locale.module line 360)

SQL: SELECT s.source, t.translation, t.language FROM locales_source s LEFT JOIN locales_target t ON s.lid = t.lid AND t.language = 'de' WHERE s.textgroup = 'default' AND s.version = '6.20' AND LENGTH(s.source) < 75

...
| Allows uploading, resizing and viewing of images.                          | Ermöglicht das Hochladen, Skalieren und Betrachten von Bildern.                                                         | de       | 
| Allows easy attaching of image nodes to other content types.               | NULL                                                                                                                     | NULL     | 
...

so untranslated strings come in with translation==NULL.

This whole result set is correctly cached (in memcache and $locale_t).

- then locale() is asked for a string which is not translated. the $locale_t static variable is checked, and since the DB returned NULL, the isset in locale.module line 371 evals to true, so the DB is queried again for the string.
- The translation is found(if ($translation) { == true in line 375) but the translation value is still NULL.
- TRUE is saved for the translation in the static $locale_t variable. But the change is not pushed through to the cache layer.
- the locale() function returns the untranslated string.

On the next page load, the $locale_t static variable is filled from the cache layer (no DB hit) -- but the cache layer does not contain the TRUE for the untranslated string.

When locale() is asked for the same untranslated string as above, it has to hit the database again. And again.

The patch stores the TRUE value in the cache layer, so that on the next page load, the locale() call for the untranslated string does not hit the DB.

This removes some 100 DB calls on some of our pages (which have quite a bit of untranslated strings, yes).

I have not found out if updating a translation will invalidate the cache automatically -- otherwise there might be some work needed there, too)

(attached newer patch is in better format and against 6.x-dev)

damien tournoud’s picture

"so untranslated strings come in with translation==NULL."

No, they are transformed into TRUE before being saved.

        $result = db_query("SELECT s.source, t.translation, t.language FROM {locales_source} s LEFT JOIN {locales_target} t ON s.lid = t.lid AND t.language = '%s' WHERE s.textgroup = 'default' AND s.version = '%s' AND LENGTH(s.source) < 75", $langcode, VERSION);
        while ($data = db_fetch_object($result)) {
          $locale_t[$langcode][$data->source] = (empty($data->translation) ? TRUE : $data->translation);
        }
        cache_set('locale:' . $langcode, $locale_t[$langcode]);
teefax’s picture

Hello,

you're right, I missed that transformation -- but: without my patch there were still many invocations of

    // We do not have this translation cached, so get it from the DB.
    $translation = db_fetch_object(db_query("SELECT s.lid, t.translation, s.version FROM {locales_source} s LEFT JOIN {locales_target} t ON s.lid = t.lid AND t.language = '%s' WHERE s.source = '%s' AND s.textgroup = 'default'", $langcode, $string));

on every page load (same page, multiple reloads).

I will take a deeper look on what is happening on monday and will get back to you with what I find.

teefax’s picture

Hello,

so, I had some time to look into why I'm seeing less queries with my patch applied -- the strings which were queried on each page load were all longer than 75 characters and so they were not loaded in the initial

 $result = db_query("SELECT s.source, t.translation, t.language FROM {locales_source} s LEFT JOIN {locales_target} t ON s.lid = t.lid AND t.language = '%s' WHERE s.textgroup = 'default' AND s.version = '%s' AND LENGTH(s.source) < 75", $langcode, VERSION);

.

So the translations for strings longer than 75 characters are loaded on each page load.

My patch caches the result of those queries, too -- so with my patch applied, the translations for those strings are cached when the DB is queried anyway.

Status: Postponed (maintainer needs more info) » Closed (outdated)

Automatically closed because Drupal 6 is no longer supported. If the issue verifiably applies to later versions, please reopen with details and update the version.