gflohr / libintl-perl

Official repository for libintl-perl
http://www.guido-flohr.net/en/projects/#libintl-perl
GNU General Public License v3.0
5 stars 4 forks source link

Locale::Messages::gettext stats non-existent *.mo files every time it is called #2

Closed GavinSmith0123 closed 6 years ago

GavinSmith0123 commented 6 years ago

I installed libintl-perl-1.29-1 using the cpan program.

If there is no translation file found for a particular language (which may often be the case with English), Locale::Messages::gettext will make stat calls looking for the file every time it is called, even if none were found the first time. I found this with the strace utility. For example, with the following Perl program as test.pl:


#!/usr/bin/perl

use strict; use warnings;
use Locale::Messages;
use POSIX;

POSIX::setlocale (LC_MESSAGES, '');

Locale::Messages::textdomain ("texinfo_document");
Locale::Messages::bindtextdomain ("texinfo_document" => "/usr/local/share/locale");

while (1) {
  print Locale::Messages::gettext ("Macro"), "\n";
}

running strace /usr/bin/perl test.pl leads to output like the following being repeated infinitely:

stat64("/usr/share/locale/en/LC_MESSAGES", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
stat64("/usr/share/locale/en/LC_MESSAGES/texinfo_document.mo", 0x8614180) = -1 ENOENT (No such file or directory)

If the translation file does exist, then stat64 is only called on the *.mo file once or twice, e.g. with LC_MESSAGES=de_DE strace /usr/bin/perl test.pl.

This is very likely inefficient, especially for programs that call gettext a lot. It should be enough to try to find the file once, and give up afterwards.

This does not appear to happen with glibc 2.19 with a C program such as the following:

#include <libintl.h>
#include <stdio.h>
#include <locale.h>

int main (void)
{
  char *cur_domain;
  char *cur_dir;

  setlocale (LC_ALL, "");

  cur_dir = bindtextdomain("texinfo_document", "/usr/local/share/locale");
  cur_domain = textdomain ("texinfo_document");

  while (1)
    {
      printf ("%s\n", gettext ("Macro"));
    }
}

With this program, stat64 was not called repeatedly, regardless of the messages locale.

GavinSmith0123 commented 6 years ago

I found that the code inside gettext_pp.pm was being used. I found the following change fixed this issue:

--- gettext_pp-old.pm   2018-08-10 13:12:42.000000000 +0100
+++ gettext_pp.pm       2018-08-10 13:09:53.000000000 +0100
@@ -579,12 +579,11 @@
                push @$domains, $domain;
        }
     }
+    $domains = [] unless defined $domains;
     $__gettext_pp_domain_cache->{$dir}
                               ->{$cache_key}
                               ->{$category_name}
                               ->{$domainname} = $domains;
-
-    $domains = [] unless defined $domains;

     return $domains;
 }
gflohr commented 6 years ago

The module should remember failed attempts to find an mo file and your fix looks reasonable.