← Index
NYTProf Performance Profile   « line view »
For /usr/local/libexec/sympa/task_manager-debug.pl
  Run on Tue Jun 1 22:32:51 2021
Reported on Tue Jun 1 22:35:10 2021

Filename/usr/local/libexec/sympa/Sympa/Robot.pm
StatementsExecuted 214766 statements in 555ms
Subroutines
Calls P F Exclusive
Time
Inclusive
Time
Subroutine
207021240ms377msSympa::Robot::::_load_topics_get_titleSympa::Robot::_load_topics_get_title
150711227ms2.30sSympa::Robot::::load_topicsSympa::Robot::load_topics
15071147.7ms2.35sSympa::Robot::::topic_keysSympa::Robot::topic_keys
1300652142.2ms42.2msSympa::Robot::::CORE:matchSympa::Robot::CORE:match (opcode)
15072126.6ms24.9sSympa::Robot::::list_paramsSympa::Robot::list_params
7535213.58ms3.58msSympa::Robot::::CORE:sortSympa::Robot::CORE:sort (opcode)
345113.04ms3.04msSympa::Robot::::CORE:ftereadSympa::Robot::CORE:fteread (opcode)
690112.68ms2.68msSympa::Robot::::_add_topicSympa::Robot::_add_topic
0000s0sSympa::Robot::::BEGIN@30Sympa::Robot::BEGIN@30
0000s0sSympa::Robot::::BEGIN@31Sympa::Robot::BEGIN@31
0000s0sSympa::Robot::::BEGIN@32Sympa::Robot::BEGIN@32
0000s0sSympa::Robot::::BEGIN@34Sympa::Robot::BEGIN@34
0000s0sSympa::Robot::::BEGIN@35Sympa::Robot::BEGIN@35
0000s0sSympa::Robot::::BEGIN@36Sympa::Robot::BEGIN@36
0000s0sSympa::Robot::::BEGIN@37Sympa::Robot::BEGIN@37
0000s0sSympa::Robot::::BEGIN@38Sympa::Robot::BEGIN@38
0000s0sSympa::Robot::::BEGIN@39Sympa::Robot::BEGIN@39
0000s0sSympa::Robot::::BEGIN@40Sympa::Robot::BEGIN@40
0000s0sSympa::Robot::::BEGIN@41Sympa::Robot::BEGIN@41
0000s0sSympa::Robot::::__ANON__Sympa::Robot::__ANON__ (xsub)
0000s0sSympa::Robot::::_topic_get_titleSympa::Robot::_topic_get_title
0000s0sSympa::Robot::::get_netidtoemail_dbSympa::Robot::get_netidtoemail_db
0000s0sSympa::Robot::::set_netidtoemail_dbSympa::Robot::set_netidtoemail_db
0000s0sSympa::Robot::::topic_get_titleSympa::Robot::topic_get_title
0000s0sSympa::Robot::::update_email_netidmap_dbSympa::Robot::update_email_netidmap_db
Call graph for these subroutines as a Graphviz dot language file.
Line State
ments
Time
on line
Calls Time
in subs
Code
1# -*- indent-tabs-mode: nil; -*-
2# vim:ft=perl:et:sw=4
3# $Id$
4
5# Sympa - SYsteme de Multi-Postage Automatique
6#
7# Copyright (c) 1997, 1998, 1999 Institut Pasteur & Christophe Wolfhugel
8# Copyright (c) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
9# 2006, 2007, 2008, 2009, 2010, 2011 Comite Reseau des Universites
10# Copyright (c) 2011, 2012, 2013, 2014, 2015, 2016, 2017 GIP RENATER
11# Copyright 2017, 2020 The Sympa Community. See the AUTHORS.md
12# file at the top-level directory of this distribution and at
13# <https://github.com/sympa-community/sympa.git>.
14#
15# This program is free software; you can redistribute it and/or modify
16# it under the terms of the GNU General Public License as published by
17# the Free Software Foundation; either version 2 of the License, or
18# (at your option) any later version.
19#
20# This program is distributed in the hope that it will be useful,
21# but WITHOUT ANY WARRANTY; without even the implied warranty of
22# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23# GNU General Public License for more details.
24#
25# You should have received a copy of the GNU General Public License
26# along with this program. If not, see <http://www.gnu.org/licenses/>.
27
28package Sympa::Robot;
29
30use strict;
31use warnings;
32use Encode qw();
33
34use Sympa;
35use Conf;
36use Sympa::DatabaseManager;
37use Sympa::Language;
38use Sympa::ListDef;
39use Sympa::Log;
40use Sympa::Tools::Data;
41use Sympa::Tools::File;
42
43my $language = Sympa::Language->instance;
44my $log = Sympa::Log->instance;
45
46## Database and SQL statement handlers
47my ($sth, @sth_stack);
48
49our %list_of_topics = ();
50## Last modification times
51our %mtime;
52
53our %listmaster_messages_stack;
54
55# MOVED: Use Sympa::send_file(), or Sympa::Message::Template::new() with
56# Sympa::Mailer::send_message().
57# sub send_global_file($tpl, $who, $robot, $context, $options);
58
59# MOVED: Use Sympa::send_notify_to_listmaster() or
60# Sympa::Spool::Listmaster::flush().
61# sub send_notify_to_listmaster($operation, $robot, $data, $checkstack, $purge);
62
63## Is the user listmaster
64# MOVED: Use Sympa::is_listmaster().
65#sub is_listmaster;
66
67## get idp xref to locally validated email address
68sub get_netidtoemail_db {
69 my $robot = shift;
70 my $netid = shift;
71 my $idpname = shift;
72 $log->syslog('debug', '(%s, %s)', $netid, $idpname);
73
74 my ($l, %which, $email);
75
76 push @sth_stack, $sth;
77
78 my $sdm = Sympa::DatabaseManager->instance;
79 unless (
80 $sdm
81 and $sth = $sdm->do_prepared_query(
82 q{SELECT email_netidmap
83 FROM netidmap_table
84 WHERE netid_netidmap = ? and serviceid_netidmap = ? and
85 robot_netidmap = ?},
86 $netid, $idpname,
87 $robot
88 )
89 ) {
90 $log->syslog(
91 'err',
92 'Unable to get email address from netidmap_table for id %s, service %s, robot %s',
93 $netid,
94 $idpname,
95 $robot
96 );
97 return undef;
98 }
99
100 $email = $sth->fetchrow;
101
102 $sth->finish();
103
104 $sth = pop @sth_stack;
105
106 return $email;
107}
108
109## set idp xref to locally validated email address
110sub set_netidtoemail_db {
111 my $robot = shift;
112 my $netid = shift;
113 my $idpname = shift;
114 my $email = shift;
115 $log->syslog('debug', '(%s, %s, %s)', $netid, $idpname, $email);
116
117 my ($l, %which);
118
119 my $sdm = Sympa::DatabaseManager->instance;
120 unless (
121 $sdm
122 and $sdm->do_prepared_query(
123 q{INSERT INTO netidmap_table
124 (netid_netidmap, serviceid_netidmap, email_netidmap,
125 robot_netidmap)
126 VALUES (?, ?, ?, ?)},
127 $netid, $idpname, $email, $robot
128 )
129 ) {
130 $log->syslog(
131 'err',
132 'Unable to set email address %s in netidmap_table for id %s, service %s, robot %s',
133 $email,
134 $netid,
135 $idpname,
136 $robot
137 );
138 return undef;
139 }
140
141 return 1;
142}
143
144## Update netidmap table when user email address changes
145sub update_email_netidmap_db {
146 my ($robot, $old_email, $new_email) = @_;
147
148 unless (defined $robot
149 && defined $old_email
150 && defined $new_email) {
151 $log->syslog('err', 'Missing parameter');
152 return undef;
153 }
154
155 my $sdm = Sympa::DatabaseManager->instance;
156 unless (
157 $sdm
158 and $sdm->do_prepared_query(
159 q{UPDATE netidmap_table
160 SET email_netidmap = ?
161 WHERE email_netidmap = ? AND robot_netidmap = ?},
162 $new_email,
163 $old_email, $robot
164 )
165 ) {
166 $log->syslog(
167 'err',
168 'Unable to set new email address %s in netidmap_table to replace old address %s for robot %s',
169 $new_email,
170 $old_email,
171 $robot
172 );
173 return undef;
174 }
175
176 return 1;
177}
178
179my $default_topics_visibility = 'noconceal';
180
181# Loads the list of topics if updated.
182# The topic names "others" and "topicsless" are reserved words therefore
183# ignored. Note: "other" is not reserved and may be used.
184
# spent 2.30s (227ms+2.07) within Sympa::Robot::load_topics which was called 1507 times, avg 1.52ms/call: # 1507 times (227ms+2.07s) by Sympa::Robot::topic_keys at line 365, avg 1.52ms/call
sub load_topics {
1851507300µs my $robot = shift;
18615072.57ms1507356ms $log->syslog('debug2', '(%s)', $robot);
# spent 356ms making 1507 calls to Sympa::Log::syslog, avg 236µs/call
187
18815072.42ms1507964ms my $conf_file = Sympa::search_fullpath($robot, 'topics.conf');
# spent 964ms making 1507 calls to Sympa::search_fullpath, avg 640µs/call
189
1901507349µs unless ($conf_file) {
191 $log->syslog('err', 'No topics.conf defined');
192 return;
193 }
194
1951507941µs my $topics = {};
196
197 ## Load if not loaded or changed on disk
19815073.80ms116237.8ms if (!$list_of_topics{$robot}
# spent 37.8ms making 1162 calls to Sympa::Tools::File::get_mtime, avg 33µs/call
199 or Sympa::Tools::File::get_mtime($conf_file) >
200 $mtime{'topics'}{$robot}) {
201
202 ## delete previous list of topics
2033454.31ms %list_of_topics = ();
204
2053453.69ms3453.04ms unless (-r $conf_file) {
# spent 3.04ms making 345 calls to Sympa::Robot::CORE:fteread, avg 9µs/call
206 $log->syslog('err', 'Unable to read %s', $conf_file);
207 return;
208 }
209
210345849µs34553.4ms my $config_content = Sympa::Tools::Text::slurp($conf_file);
# spent 53.4ms making 345 calls to Sympa::Tools::Text::slurp, avg 155µs/call
211345130µs unless (defined $config_content) {
212 $log->syslog('err', 'Unable to open config file %s', $conf_file);
213 return;
214 }
215
216 ## Rough parsing
217345139µs my $index = 0;
218345110µs my (@rough_data, $topic);
21934526.3ms foreach my $line (split /(?<=\n)(?=\n|.)/, $config_content) {
22015180113ms4519525.2ms if ($line =~ /\A(others|topicsless)\s*\z/i) {
# spent 25.2ms making 45195 calls to Sympa::Robot::CORE:match, avg 557ns/call
221 # "others" and "topicsless" are reserved words. Ignore.
222 next;
223 } elsif ($line =~ /^([\-\w\/]+)\s*$/) {
2242070246µs $index++;
22520702.30ms $topic = {
226 'name' => lc($1),
227 'order' => $index
228 };
229 } elsif ($line =~ /^([\w\.]+)\s+(.+\S)\s*$/) {
230113852.07ms next unless defined $topic->{'name'};
231
232113856.75ms $topic->{$1} = $2;
233 } elsif ($line =~ /^\s*$/) {
2341725379µs next unless defined $topic->{'name'};
235
2361725380µs push @rough_data, $topic;
2371725405µs $topic = {};
238 }
239 }
240
241 ## Last topic
242345284µs if (defined $topic->{'name'}) {
24334578µs push @rough_data, $topic;
24434580µs $topic = {};
245 }
246
247345873µs3459.83ms $mtime{'topics'}{$robot} = Sympa::Tools::File::get_mtime($conf_file);
# spent 9.83ms making 345 calls to Sympa::Tools::File::get_mtime, avg 28µs/call
248
249345272µs unless ($#rough_data > -1) {
250 $log->syslog('notice', 'No topic defined in %s', $conf_file);
251 return;
252 }
253
254 ## Analysis
255345251µs foreach my $topic (@rough_data) {
25620701.39ms my @tree = split '/', $topic->{'name'};
257
25820701.47ms if ($#tree == 0) {
25913801.39ms1380260ms my $title = _load_topics_get_title($topic);
# spent 260ms making 1380 calls to Sympa::Robot::_load_topics_get_title, avg 189µs/call
26013801.26ms $list_of_topics{$robot}{$tree[0]}{'title'} = $title;
261 $list_of_topics{$robot}{$tree[0]}{'visibility'} =
26213801.02ms $topic->{'visibility'} || $default_topics_visibility;
263 $list_of_topics{$robot}{$tree[0]}{'order'} =
26413801.02ms $topic->{'order'};
265 } else {
266690842µs my $subtopic = join('/', @tree[1 .. $#tree]);
267690572µs690116ms my $title = _load_topics_get_title($topic);
# spent 116ms making 690 calls to Sympa::Robot::_load_topics_get_title, avg 168µs/call
268 my $visibility =
269690292µs $topic->{'visibility'} || $default_topics_visibility;
2706901.52ms6902.68ms $list_of_topics{$robot}{$tree[0]}{'sub'}{$subtopic} =
# spent 2.68ms making 690 calls to Sympa::Robot::_add_topic, avg 4µs/call
271 _add_topic($subtopic, $title, $visibility);
272 }
273 }
274
275 ## Set undefined Topic (defined via subtopic)
2763452.01ms foreach my $t (keys %{$list_of_topics{$robot}}) {
2771380621µs unless (defined $list_of_topics{$robot}{$t}{'title'}) {
278 $list_of_topics{$robot}{$t}{'title'} = {'default' => $t};
279 }
280 }
281 }
282
283 ## Set the title in the current language
28415072.29ms15072.15ms my $lang = $language->get_lang;
# spent 2.15ms making 1507 calls to Sympa::Language::get_lang, avg 1µs/call
28515072.82ms foreach my $top (keys %{$list_of_topics{$robot}}) {
28660282.18ms my $topic = $list_of_topics{$robot}{$top};
28760286.05ms6028169ms foreach my $l (Sympa::Language::implicated_langs($lang)) {
# spent 169ms making 6028 calls to Sympa::Language::implicated_langs, avg 28µs/call
28860283.22ms if (exists $topic->{'title'}{$l}) {
289 $topic->{'current_title'} = $topic->{'title'}{$l};
290 }
291 }
29260281.70ms unless (exists $topic->{'current_title'}) {
293 if (exists $topic->{'title'}{'gettext'}) {
294 $topic->{'current_title'} =
295 $language->gettext($topic->{'title'}{'gettext'});
296 } else {
2971380663µs $topic->{'current_title'} = $topic->{'title'}{'default'}
298 || $top;
299 }
300 }
301
30260286.39ms foreach my $subtop (keys %{$topic->{'sub'}}) {
30330142.77ms301471.2ms foreach my $l (Sympa::Language::implicated_langs($lang)) {
# spent 71.2ms making 3014 calls to Sympa::Language::implicated_langs, avg 24µs/call
30430142.04ms if (exists $topic->{'sub'}{$subtop}{'title'}{$l}) {
305 $topic->{'sub'}{$subtop}{'current_title'} =
306 $topic->{'sub'}{$subtop}{'title'}{$l};
307 }
308 }
30930141.73ms unless (exists $topic->{'sub'}{$subtop}{'current_title'}) {
310 if (exists $topic->{'sub'}{$subtop}{'title'}{'gettext'}) {
311 $topic->{'sub'}{$subtop}{'current_title'} =
312 $language->gettext(
313 $topic->{'sub'}{$subtop}{'title'}{'gettext'});
314 } else {
315 $topic->{'sub'}{$subtop}{'current_title'} =
316690476µs $topic->{'sub'}{$subtop}{'title'}{'default'}
317 || $subtop;
318 }
319 }
320 }
321 }
322
32315074.36ms return %{$list_of_topics{$robot}};
324}
325
326# Old name: _get_topic_titles().
327
# spent 377ms (240+137) within Sympa::Robot::_load_topics_get_title which was called 2070 times, avg 182µs/call: # 1380 times (167ms+93.2ms) by Sympa::Robot::load_topics at line 259, avg 189µs/call # 690 times (72.4ms+43.7ms) by Sympa::Robot::load_topics at line 267, avg 168µs/call
sub _load_topics_get_title {
3282070345µs my $topic = shift;
329
3302070265µs my $title;
33120702.93ms foreach my $key (%{$topic}) {
33231050230ms8487017.0ms if ($key =~ /^title\.gettext$/i) {
# spent 17.0ms making 84870 calls to Sympa::Robot::CORE:match, avg 201ns/call
333 $title->{'gettext'} = $topic->{$key};
334 } elsif ($key =~ /^title\.(\S+)$/i) {
33582802.27ms my $lang = $1;
336 # canonicalize lang if possible.
33782805.91ms8280120ms $lang = Sympa::Language::canonic_lang($lang) || $lang;
# spent 120ms making 8280 calls to Sympa::Language::canonic_lang, avg 14µs/call
33882804.15ms $title->{$lang} = $topic->{$key};
339 } elsif ($key =~ /^title$/i) {
340 $title->{'default'} = $topic->{$key};
341 }
342 }
343
34420702.50ms return $title;
345}
346
347## Inner sub used by load_topics()
348
# spent 2.68ms within Sympa::Robot::_add_topic which was called 690 times, avg 4µs/call: # 690 times (2.68ms+0s) by Sympa::Robot::load_topics at line 270, avg 4µs/call
sub _add_topic {
349690381µs my ($name, $title, $visibility) = @_;
350690262µs my $topic = {};
351
352690419µs my @tree = split '/', $name;
3536901.83ms if ($#tree == 0) {
354 return {'title' => $title, 'visibility' => $visibility};
355 } else {
356 $topic->{'sub'}{$name} =
357 _add_topic(join('/', @tree[1 .. $#tree]), $title, $visibility);
358 return $topic;
359 }
360}
361
362
# spent 2.35s (47.7ms+2.30) within Sympa::Robot::topic_keys which was called 1507 times, avg 1.56ms/call: # 1507 times (47.7ms+2.30s) by Sympa::Robot::list_params at line 446, avg 1.56ms/call
sub topic_keys {
3631507490µs my $robot_id = shift;
364
36515073.49ms15072.30s my %topics = Sympa::Robot::load_topics($robot_id);
# spent 2.30s making 1507 calls to Sympa::Robot::load_topics, avg 1.52ms/call
366 return map {
367753516.6ms15072.56ms my $topic = $_;
# spent 2.56ms making 1507 calls to Sympa::Robot::CORE:sort, avg 2µs/call
368602830.3ms60281.02ms if ($topics{$topic}->{sub}) {
# spent 1.02ms making 6028 calls to Sympa::Robot::CORE:sort, avg 170ns/call
369 ( $topic,
370 map { $topic . '/' . $_ } sort keys %{$topics{$topic}->{sub}}
371 );
372 } else {
373 ($topic);
374 }
375 } sort keys %topics;
376}
377
378sub topic_get_title {
379 my $robot_id = shift;
380 my $topic = shift;
381
382 my $tinfo = {Sympa::Robot::load_topics($robot_id)};
383 return unless %$tinfo;
384
385 my @ttitles;
386 my @tpaths = split '/', $topic;
387
388 while (1) {
389 my $t = shift @tpaths;
390 unless (exists $tinfo->{$t}) {
391 @ttitles = ();
392 last;
393 } elsif (not @tpaths) {
394 push @ttitles, (_topic_get_title($tinfo->{$t}) || $t);
395 last;
396 } elsif (not $tinfo->{$t}->{sub}) {
397 @ttitles = ();
398 last;
399 } else {
400 push @ttitles, (_topic_get_title($tinfo->{$t}) || $t);
401 $tinfo = $tinfo->{$t}->{sub};
402 }
403 }
404
405 return @ttitles if wantarray;
406 return join ' / ', @ttitles;
407}
408
409sub _topic_get_title {
410 my $titem = shift;
411
412 return undef unless $titem and exists $titem->{title};
413
414 foreach my $lang (Sympa::Language::implicated_langs($language->get_lang))
415 {
416 return $titem->{title}->{$lang}
417 if $titem->{title}->{$lang};
418 }
419 if ($titem->{title}->{gettext}) {
420 return $language->gettext($titem->{title}->{gettext});
421 } elsif ($titem->{title}->{default}) {
422 return $titem->{title}->{default};
423 } else {
424 return undef;
425 }
426}
427
428=over 4
429
430=item list_params
431
432I<Getter>.
433Returns hashref to list parameter information.
434
435=back
436
437=cut
438
439# Old name: tools::get_list_params().
440
# spent 24.9s (26.6ms+24.9) within Sympa::Robot::list_params which was called 1507 times, avg 16.6ms/call: # 1494 times (26.3ms+24.5s) by Sympa::List::_load_edit_list_conf at line 6158 of /usr/local/libexec/sympa/Sympa/List.pm, avg 16.4ms/call # 13 times (255µs+407ms) by Sympa::List::_load_list_config_file at line 4987 of /usr/local/libexec/sympa/Sympa/List.pm, avg 31.3ms/call
sub list_params {
4411507389µs my $robot_id = shift;
442
44315073.53ms15076.44s my $pinfo = Sympa::Tools::Data::clone_var(\%Sympa::ListDef::pinfo);
# spent 6.44s making 1507 calls to Sympa::Tools::Data::clone_var, avg 4.28ms/call
44415079.46ms150716.1s $pinfo->{lang}{format} = [Sympa::get_supported_languages($robot_id)];
# spent 16.1s making 1507 calls to Sympa::get_supported_languages, avg 10.7ms/call
445
44615072.78ms15072.35s my @topics = Sympa::Robot::topic_keys($robot_id);
# spent 2.35s making 1507 calls to Sympa::Robot::topic_keys, avg 1.56ms/call
44715072.50ms $pinfo->{topics}{format} = [@topics];
448 # Compat.
44915072.83ms $pinfo->{topics}{file_format} = sprintf '(%s)(,(%s))*',
450 join('|', @topics),
451 join('|', @topics);
452
45315078.09ms return $pinfo;
454}
455
4561;
 
# spent 3.04ms within Sympa::Robot::CORE:fteread which was called 345 times, avg 9µs/call: # 345 times (3.04ms+0s) by Sympa::Robot::load_topics at line 205, avg 9µs/call
sub Sympa::Robot::CORE:fteread; # opcode
# spent 42.2ms within Sympa::Robot::CORE:match which was called 130065 times, avg 324ns/call: # 84870 times (17.0ms+0s) by Sympa::Robot::_load_topics_get_title at line 332, avg 201ns/call # 45195 times (25.2ms+0s) by Sympa::Robot::load_topics at line 220, avg 557ns/call
sub Sympa::Robot::CORE:match; # opcode
# spent 3.58ms within Sympa::Robot::CORE:sort which was called 7535 times, avg 476ns/call: # 6028 times (1.02ms+0s) by Sympa::Robot::topic_keys at line 368, avg 170ns/call # 1507 times (2.56ms+0s) by Sympa::Robot::topic_keys at line 367, avg 2µs/call
sub Sympa::Robot::CORE:sort; # opcode