← 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/Spool.pm
StatementsExecuted 132394 statements in 343ms
Subroutines
Calls P F Exclusive
Time
Inclusive
Time
Subroutine
230011105ms1.20sSympa::Spool::::unmarshal_metadataSympa::Spool::unmarshal_metadata
14942298.5ms34.5sSympa::Spool::::nextSympa::Spool::next (recurses: max depth 1, inclusive time 2.78s)
23001134.7ms45.4msSympa::Spool::::split_listnameSympa::Spool::split_listname
23001126.5ms1.22sSympa::Spool::::unmarshalSympa::Spool::unmarshal
2302124.9ms62.5msSympa::Spool::::_loadSympa::Spool::_load
78213121.5ms21.5msSympa::Spool::::CORE:matchSympa::Spool::CORE:match (opcode)
11501118.6ms18.6msSympa::Spool::::CORE:openSympa::Spool::CORE:open (opcode)
23001114.5ms14.5msSympa::Spool::::CORE:ftfileSympa::Spool::CORE:ftfile (opcode)
1150119.55ms9.55msSympa::Spool::::CORE:readlineSympa::Spool::CORE:readline (opcode)
1150114.48ms4.48msSympa::Spool::::CORE:closeSympa::Spool::CORE:close (opcode)
230113.96ms3.96msSympa::Spool::::CORE:readdirSympa::Spool::CORE:readdir (opcode)
230113.93ms3.93msSympa::Spool::::CORE:open_dirSympa::Spool::CORE:open_dir (opcode)
2300113.15ms3.15msSympa::Spool::::CORE:regcompSympa::Spool::CORE:regcomp (opcode)
2530312.25ms2.25msSympa::Spool::::_is_collectionSympa::Spool::_is_collection
23121680µs680µsSympa::Spool::::CORE:sortSympa::Spool::CORE:sort (opcode)
23011428µs428µsSympa::Spool::::CORE:closedirSympa::Spool::CORE:closedir (opcode)
23021253µs253µsSympa::Spool::::_initSympa::Spool::_init
111147µs351µsSympa::Spool::::newSympa::Spool::new
11166µs104µsSympa::Spool::::build_glob_patternSympa::Spool::build_glob_pattern
11161µs84µsSympa::Spool::::_createSympa::Spool::_create
22123µs23µsSympa::Spool::::CORE:substSympa::Spool::CORE:subst (opcode)
11118µs18µsSympa::Spool::::CORE:ftdirSympa::Spool::CORE:ftdir (opcode)
6118µs8µsSympa::Spool::::CORE:substcontSympa::Spool::CORE:substcont (opcode)
1113µs3µsSympa::Spool::::_filter_preSympa::Spool::_filter_pre
2212µs2µsSympa::Spool::::CORE:umaskSympa::Spool::CORE:umask (opcode)
1111µs1µsSympa::Spool::::_no_glob_patternSympa::Spool::_no_glob_pattern
0000s0sSympa::Spool::::BEGIN@187Sympa::Spool::BEGIN@187
0000s0sSympa::Spool::::BEGIN@30Sympa::Spool::BEGIN@30
0000s0sSympa::Spool::::BEGIN@31Sympa::Spool::BEGIN@31
0000s0sSympa::Spool::::BEGIN@32Sympa::Spool::BEGIN@32
0000s0sSympa::Spool::::BEGIN@33Sympa::Spool::BEGIN@33
0000s0sSympa::Spool::::BEGIN@34Sympa::Spool::BEGIN@34
0000s0sSympa::Spool::::BEGIN@35Sympa::Spool::BEGIN@35
0000s0sSympa::Spool::::BEGIN@36Sympa::Spool::BEGIN@36
0000s0sSympa::Spool::::BEGIN@37Sympa::Spool::BEGIN@37
0000s0sSympa::Spool::::BEGIN@39Sympa::Spool::BEGIN@39
0000s0sSympa::Spool::::BEGIN@40Sympa::Spool::BEGIN@40
0000s0sSympa::Spool::::BEGIN@41Sympa::Spool::BEGIN@41
0000s0sSympa::Spool::::BEGIN@42Sympa::Spool::BEGIN@42
0000s0sSympa::Spool::::BEGIN@43Sympa::Spool::BEGIN@43
0000s0sSympa::Spool::::BEGIN@44Sympa::Spool::BEGIN@44
0000s0sSympa::Spool::::BEGIN@45Sympa::Spool::BEGIN@45
0000s0sSympa::Spool::::BEGIN@46Sympa::Spool::BEGIN@46
0000s0sSympa::Spool::::__ANON__Sympa::Spool::__ANON__ (xsub)
0000s0sSympa::Spool::::__ANON__[:261]Sympa::Spool::__ANON__[:261]
0000s0sSympa::Spool::::_filterSympa::Spool::_filter
0000s0sSympa::Spool::::_store_keySympa::Spool::_store_key
0000s0sSympa::Spool::::marshalSympa::Spool::marshal
0000s0sSympa::Spool::::marshal_metadataSympa::Spool::marshal_metadata
0000s0sSympa::Spool::::quarantineSympa::Spool::quarantine
0000s0sSympa::Spool::::removeSympa::Spool::remove
0000s0sSympa::Spool::::sizeSympa::Spool::size
0000s0sSympa::Spool::::storeSympa::Spool::store
0000s0sSympa::Spool::::store_spoolSympa::Spool::store_spool
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::Spool;
29
30use strict;
31use warnings;
32use Cwd qw();
33use Digest::MD5;
34use English qw(-no_match_vars);
35use POSIX qw();
36use Sys::Hostname qw();
37use Time::HiRes qw();
38
39use Sympa;
40use Conf;
41use Sympa::Constants;
42use Sympa::Family;
43use Sympa::List;
44use Sympa::LockedFile;
45use Sympa::Log;
46use Sympa::Tools::File;
47
48my $log = Sympa::Log->instance;
49
50# Methods.
51
52
# spent 351µs (147+204) within Sympa::Spool::new which was called: # once (147µs+204µs) by Sympa::Spindle::new at line 42 of /usr/local/libexec/sympa/Sympa/Spindle.pm
sub new {
5316µs my $class = shift;
5411µs my %options = @_;
55
56156µs1500ns die $EVAL_ERROR unless eval sprintf 'require %s', $class->_generator;
# spent 500ns making 1 call to Sympa::Spool::Task::_generator
# spent 3µs executing statements in string eval
57
58 my $self = bless {
59 %options,
6018µs19µs %{$class->_directories(%options) || {}},
# spent 9µs making 1 call to Sympa::Spool::Task::_directories
61 _metadatas => undef,
62 _glob_pattern => undef,
63 } => $class;
64
6518µs184µs $self->_create;
# spent 84µs making 1 call to Sympa::Spool::_create
6614µs11µs $self->_init(0) or return undef;
# spent 1µs making 1 call to Sympa::Spool::_init
67
68 # Build glob pattern (using encoded attributes).
6914µs11µs unless ($self->_no_glob_pattern) {
# spent 1µs making 1 call to Sympa::Spool::_no_glob_pattern
701900ns my $opts = {%options};
7119µs13µs $self->_filter_pre($opts);
# spent 3µs making 1 call to Sympa::Spool::_filter_pre
72 $self->{_glob_pattern} =
73130µs3105µs Sympa::Spool::build_glob_pattern($self->_marshal_format,
# spent 104µs making 1 call to Sympa::Spool::build_glob_pattern # spent 500ns making 1 call to Sympa::Spool::Task::_marshal_format # spent 400ns making 1 call to Sympa::Spool::Task::_marshal_keys
74 $self->_marshal_keys, %$opts);
75 }
76
7714µs $self;
78}
79
80
# spent 84µs (61+23) within Sympa::Spool::_create which was called: # once (61µs+23µs) by Sympa::Spool::new at line 65
sub _create {
811600ns my $self = shift;
82
8319µs11µs my $umask = umask oct $Conf::Conf{'umask'};
# spent 1µs making 1 call to Sympa::Spool::CORE:umask
84125µs24µs foreach my $directory (sort values %{$self->_directories}) {
# spent 2µs making 1 call to Sympa::Spool::CORE:sort # spent 1µs making 1 call to Sympa::Spool::Task::_directories
85130µs118µs unless (-d $directory) {
# spent 18µs making 1 call to Sympa::Spool::CORE:ftdir
86 $log->syslog('info', 'Creating directory %s of %s',
87 $directory, $self);
88 unless (mkdir $directory, 0775 or -d $directory) {
89 die sprintf 'Cannot create %s: %s', $directory, $ERRNO;
90 }
91 unless (
92 Sympa::Tools::File::set_file_rights(
93 file => $directory,
94 user => Sympa::Constants::USER(),
95 group => Sympa::Constants::GROUP()
96 )
97 ) {
98 die sprintf 'Cannot create %s: %s', $directory, $ERRNO;
99 }
100 }
101 }
102110µs1500ns umask $umask;
# spent 500ns making 1 call to Sympa::Spool::CORE:umask
103}
104
105230526µs
# spent 253µs within Sympa::Spool::_init which was called 230 times, avg 1µs/call: # 229 times (252µs+0s) by Sympa::Spool::next at line 129, avg 1µs/call # once (1µs+0s) by Sympa::Spool::new at line 66
sub _init {1}
106
10718µs
# spent 1µs within Sympa::Spool::_no_glob_pattern which was called: # once (1µs+0s) by Sympa::Spool::new at line 69
sub _no_glob_pattern {0}
108
109sub marshal {
110 my $self = shift;
111 my $message = shift;
112 my %options = @_;
113
114 return Sympa::Spool::marshal_metadata($message, $self->_marshal_format,
115 $self->_marshal_keys, %options);
116}
117
118
# spent 34.5s (98.5ms+34.4) within Sympa::Spool::next which was called 1494 times, avg 23.1ms/call: # 1265 times (53.6ms+-53.6ms) by Sympa::Spool::Task::_existing_tasks at line 130 of /usr/local/libexec/sympa/Sympa/Spool/Task.pm, avg 0s/call # 229 times (44.9ms+34.4s) by Sympa::Spindle::spin at line 78 of /usr/local/libexec/sympa/Sympa/Spindle.pm, avg 150ms/call
sub next {
1191494363µs my $self = shift;
12014941.29ms my %options = @_;
121
1221494541µs return unless $self->{directory};
123
1241494723µs11533.3s unless ($self->{_metadatas}) {
# spent 33.3s making 115 calls to Sympa::Spool::Task::_load, avg 290ms/call
125 $self->{_metadatas} = $self->_load;
126 }
1271494859µs unless ($self->{_metadatas} and @{$self->{_metadatas}}) {
128229126µs undef $self->{_metadatas};
129229410µs229252µs $self->_init(1);
# spent 252µs making 229 calls to Sympa::Spool::_init, avg 1µs/call
130229302µs return;
131 }
132
13312652.25ms while (my $marshalled = shift @{$self->{_metadatas}}) {
1342300467µs my ($handle, $metadata, $message);
135
136 # Try locking message. Those locked or removed by other process will
137 # be skipped.
1382300943µs if ($options{no_lock}) {
139 next
140 unless open $handle, '<',
141115023.2ms115018.6ms $self->{directory} . '/' . $marshalled;
# spent 18.6ms making 1150 calls to Sympa::Spool::CORE:open, avg 16µs/call
142 } else {
143 $handle =
14411506.27ms2300406ms Sympa::LockedFile->new($self->{directory} . '/' . $marshalled,
# spent 405ms making 1150 calls to IO::File::new, avg 352µs/call # spent 1.11ms making 1150 calls to Sympa::Spool::_is_collection, avg 962ns/call
145 -1, $self->_is_collection ? '+' : '+<');
1461150345µs next unless $handle;
147 }
148
14923003.81ms23001.22s $metadata = $self->unmarshal($marshalled);
# spent 1.22s making 2300 calls to Sympa::Spool::unmarshal, avg 532µs/call
150
15123001.35ms if ($metadata) {
15223002.31ms11503.42ms if ($options{no_filter}) {
# spent 3.42ms making 1150 calls to Sympa::Spool::Task::_filter, avg 3µs/call
153 $self->_filter($metadata);
154 } else {
155115017.0ms2300109ms next unless $self->_filter($metadata);
# spent 105ms making 1150 calls to Sympa::LockedFile::DESTROY, avg 91µs/call # spent 3.85ms making 1150 calls to Sympa::Spool::Task::_filter, avg 3µs/call
156 }
157
15811501.83ms1150906µs if ($self->_is_collection) {
# spent 906µs making 1150 calls to Sympa::Spool::_is_collection, avg 788ns/call
159 $message = $self->_generator->new(%$metadata);
160 } else {
161345023.8ms11509.55ms my $msg_string = do { local $RS; <$handle> };
# spent 9.55ms making 1150 calls to Sympa::Spool::CORE:readline, avg 8µs/call
16211508.04ms23002.07s $message = $self->_generator->new($msg_string, %$metadata);
# spent 2.07s making 1150 calls to Sympa::Task::new, avg 1.80ms/call # spent 638µs making 1150 calls to Sympa::Spool::Task::_generator, avg 555ns/call
163 }
164 }
165
166 # Though message might not be deserialized, anyway return the result.
1671150578µs if ($options{no_lock}) {
16811506.48ms11504.48ms close $handle;
# spent 4.48ms making 1150 calls to Sympa::Spool::CORE:close, avg 4µs/call
16911506.50ms return ($message, 1);
170 } else {
171 return ($message, $handle);
172 }
173 }
174115339µs return;
175}
176
177sub _filter {1}
178
179
# spent 62.5ms (24.9+37.6) within Sympa::Spool::_load which was called 230 times, avg 272µs/call: # 115 times (17.2ms+17.1ms) by Sympa::Spool::Task::_existing_tasks at line 127 of /usr/local/libexec/sympa/Sympa/Spool/Task.pm, avg 298µs/call # 115 times (7.73ms+20.5ms) by Sympa::Spool::Task::_load at line 60 of /usr/local/libexec/sympa/Sympa/Spool/Task.pm, avg 246µs/call
sub _load {
18023086µs my $self = shift;
181
18223081µs my @entries;
183230247µs if ($self->{_glob_pattern}) {
184 my $cwd = Cwd::getcwd();
185 die sprintf 'Cannot chdir to %s: %s', $self->{directory}, $ERRNO
186 unless chdir $self->{directory};
187 @entries = glob $self->{_glob_pattern};
188 chdir $cwd;
189 } else {
19023086µs my $dh;
191 die sprintf 'Cannot open dir %s: %s', $self->{directory}, $ERRNO
1922305.12ms2303.93ms unless opendir $dh, $self->{directory};
# spent 3.93ms making 230 calls to Sympa::Spool::CORE:open_dir, avg 17µs/call
1932304.71ms2303.96ms @entries = readdir $dh;
# spent 3.96ms making 230 calls to Sympa::Spool::CORE:readdir, avg 17µs/call
1942301.23ms230428µs closedir $dh;
# spent 428µs making 230 calls to Sympa::Spool::CORE:closedir, avg 2µs/call
195 }
196
197230472µs230238µs my $iscol = $self->_is_collection;
# spent 238µs making 230 calls to Sympa::Spool::_is_collection, avg 1µs/call
198 my $metadatas = [
199 sort grep {
2002302.49ms230678µs !/,lock/
# spent 678µs making 230 calls to Sympa::Spool::CORE:sort, avg 3µs/call
201 and !m{(?:\A|/)(?:\.|T\.|BAD-)}
202 and ((not $iscol and -f ($self->{directory} . '/' . $_))
203276046.9ms782028.3ms or ($iscol and -d ($self->{directory} . '/' . $_)))
# spent 14.5ms making 2300 calls to Sympa::Spool::CORE:ftfile, avg 6µs/call # spent 13.9ms making 5520 calls to Sympa::Spool::CORE:match, avg 3µs/call
204 } @entries
205 ];
206
2072305.67ms return $metadatas;
208}
209
21025308.86ms
# spent 2.25ms within Sympa::Spool::_is_collection which was called 2530 times, avg 889ns/call: # 1150 times (1.11ms+0s) by Sympa::Spool::next at line 144, avg 962ns/call # 1150 times (906µs+0s) by Sympa::Spool::next at line 158, avg 788ns/call # 230 times (238µs+0s) by Sympa::Spool::_load at line 197, avg 1µs/call
sub _is_collection {0}
211
212sub quarantine {
213 my $self = shift;
214 my $handle = shift;
215
216 return undef unless $self->{bad_directory};
217 die 'bug in logic. Ask developer' unless ref $handle;
218
219 my $bad_file;
220
221 $bad_file = $self->{bad_directory} . '/' . $handle->basename;
222 unless (-d $self->{bad_directory} and $handle->rename($bad_file)) {
223 $bad_file = $self->{directory} . '/BAD-' . $handle->basename;
224 return undef unless $handle->rename($bad_file);
225 }
226
227 return 1;
228}
229
230sub remove {
231 my $self = shift;
232 my $handle = shift;
233
234 die 'bug in logic. Ask developer' unless ref $handle;
235
236 if ($self->_is_collection) {
237 return undef
238 unless rmdir($self->{directory} . '/' . $handle->basename);
239 return $handle->close;
240 } else {
241 return $handle->unlink;
242 }
243}
244
245sub size {
246 scalar @{shift->_load || []};
247}
248
249sub store {
250 my $self = shift;
251 my $message = shift->dup;
252 my %options = @_;
253
254 return if $self->_is_collection;
255
256 $message->{date} = time unless defined $message->{date};
257
258 my $marshalled =
259 Sympa::Spool::store_spool($self->{directory}, $message,
260 $self->_marshal_format, $self->_marshal_keys, %options,
261 _filter_pre => sub { $self->_filter_pre(shift) },);
262 return unless $marshalled;
263
264 $log->syslog('notice', '%s is stored into %s as <%s>',
265 $message, $self, $marshalled);
266
267 if ($self->_store_key) {
268 my $metadata = $self->unmarshal($marshalled);
269 return $metadata ? $metadata->{$self->_store_key} : undef;
270 }
271 return $marshalled;
272}
273
27414µs
# spent 3µs within Sympa::Spool::_filter_pre which was called: # once (3µs+0s) by Sympa::Spool::new at line 71
sub _filter_pre {1}
275
276sub _store_key {undef}
277
278
# spent 1.22s (26.5ms+1.20) within Sympa::Spool::unmarshal which was called 2300 times, avg 532µs/call: # 2300 times (26.5ms+1.20s) by Sympa::Spool::next at line 149, avg 532µs/call
sub unmarshal {
2792300550µs my $self = shift;
2802300557µs my $marshalled = shift;
281
282 return Sympa::Spool::unmarshal_metadata(
283230027.8ms69001.20s $self->{directory}, $marshalled,
# spent 1.20s making 2300 calls to Sympa::Spool::unmarshal_metadata, avg 520µs/call # spent 1.48ms making 2300 calls to Sympa::Spool::Task::_marshal_regexp, avg 643ns/call # spent 896µs making 2300 calls to Sympa::Spool::Task::_marshal_keys, avg 389ns/call
284 $self->_marshal_regexp, $self->_marshal_keys
285 );
286}
287
288# Low-level functions.
289
290
# spent 104µs (66+38) within Sympa::Spool::build_glob_pattern which was called: # once (66µs+38µs) by Sympa::Spool::new at line 73
sub build_glob_pattern {
29111µs my $format = shift;
2921600ns my $keys = shift;
29311µs my %options = @_;
294
29512µs if (exists $options{context}) {
296 my $context = $options{context};
297 if (ref $context eq 'Sympa::List') {
298 @options{qw(localpart domainpart)} =
299 split /\@/, Sympa::get_address($context);
300 } else {
301 $options{domainpart} = $context;
302 }
303 }
304
305146µs727µs $format =~ s/(%%|%[-#+.\d ]*[l]*\w)/$1 eq '%%' ? '%%' : '%s'/eg;
# spent 18µs making 1 call to Sympa::Spool::CORE:subst # spent 8µs making 6 calls to Sympa::Spool::CORE:substcont, avg 1µs/call
306 my @args =
307 map {
30852µs if (exists $options{$_} and defined $options{$_}) {
309 my $val = $options{$_};
310 $val =~ s/([^0-9A-Za-z\x80-\xFF])/\\$1/g;
311 $val;
312 } else {
31355µs '*';
314 }
315 } map {
316 lc $_
31719µs } @{$keys || []};
31812µs my $pattern = sprintf $format, @args;
31917µs15µs $pattern =~ s/[*][*]+/*/g;
# spent 5µs making 1 call to Sympa::Spool::CORE:subst
320
321 # Eliminate patterns contains only punctuations:
322 # ',', '.', '_', wildcard etc.
323129µs17µs return ($pattern =~ /[0-9A-Za-z\x80-\xFF]|\\[^0-9A-Za-z\x80-\xFF]/)
# spent 7µs making 1 call to Sympa::Spool::CORE:match
324 ? $pattern
325 : undef;
326}
327
328
# spent 45.4ms (34.7+10.7) within Sympa::Spool::split_listname which was called 2300 times, avg 20µs/call: # 2300 times (34.7ms+10.7ms) by Sympa::Spool::unmarshal_metadata at line 423, avg 20µs/call
sub split_listname {
3292300708µs my $robot_id = shift || '*';
3302300551µs my $mailbox = shift;
3312300549µs return unless defined $mailbox and length $mailbox;
332
33323002.89ms23007.22ms my $return_path_suffix =
# spent 7.22ms making 2300 calls to Conf::get_robot_conf, avg 3µs/call
334 Conf::get_robot_conf($robot_id, 'return_path_suffix');
335 my $regexp = join(
336 '|',
337 map { quotemeta $_ }
338230017.2ms23003.43ms grep { $_ and length $_ }
# spent 3.43ms making 2300 calls to Conf::get_robot_conf, avg 1µs/call
339 split(
340 /[\s,]+/, Conf::get_robot_conf($robot_id, 'list_check_suffixes')
341 )
342 );
343
344230011.5ms if ( $mailbox eq 'sympa'
345 and $robot_id eq $Conf::Conf{'domain'}) { # compat.
346 return (undef, 'sympa');
347 } elsif ($mailbox eq Conf::get_robot_conf($robot_id, 'email')
348 or $robot_id eq $Conf::Conf{'domain'}
349 and $mailbox eq $Conf::Conf{'email'}) {
350 return (undef, 'sympa');
351 } elsif ($mailbox eq Conf::get_robot_conf($robot_id, 'listmaster_email')
352 or $robot_id eq $Conf::Conf{'domain'}
353 and $mailbox eq $Conf::Conf{'listmaster_email'}) {
354 return (undef, 'listmaster');
355 } elsif ($mailbox =~ /^(\S+)$return_path_suffix$/) { # -owner
356 return ($1, 'return_path');
357 } elsif (!$regexp) {
358 return ($mailbox);
359 } elsif ($mailbox =~ /^(\S+)-($regexp)$/) {
360 my ($name, $suffix) = ($1, $2);
361 my $type;
362
363 if ($suffix eq 'request') { # -request
364 if ( $name eq Conf::get_robot_conf($robot_id, 'email')
365 or $robot_id eq $Conf::Conf{'domain'}
366 and $name eq $Conf::Conf{'email'}) { # sympa-request
367 ($name, $type) = (undef, 'sympaowner');
368 } else {
369 $type = 'owner';
370 }
371 } elsif ($suffix eq 'editor') {
372 $type = 'editor';
373 } elsif ($suffix eq 'subscribe') {
374 $type = 'subscribe';
375 } elsif ($suffix eq 'unsubscribe') {
376 $type = 'unsubscribe';
377 } else {
378 $name = $mailbox;
379 $type = 'UNKNOWN';
380 }
381 return ($name, $type);
382 } else {
383 return ($mailbox);
384 }
385}
386
387# Old name: SympaspoolClassic::analyze_file_name().
388
# spent 1.20s (105ms+1.09) within Sympa::Spool::unmarshal_metadata which was called 2300 times, avg 520µs/call: # 2300 times (105ms+1.09s) by Sympa::Spool::unmarshal at line 283, avg 520µs/call
sub unmarshal_metadata {
38923003.35ms2300589ms $log->syslog('debug3', '(%s, %s, %s)', @_);
# spent 589ms making 2300 calls to Sympa::Log::syslog, avg 256µs/call
3902300894µs my $spool_dir = shift;
3912300428µs my $marshalled = shift;
3922300521µs my $marshal_regexp = shift;
3932300442µs my $marshal_keys = shift;
394
3952300410µs my $data;
396 my @matches;
397230033.0ms460010.7ms unless (@matches = ($marshalled =~ /$marshal_regexp/)) {
# spent 7.59ms making 2300 calls to Sympa::Spool::CORE:match, avg 3µs/call # spent 3.15ms making 2300 calls to Sympa::Spool::CORE:regcomp, avg 1µs/call
398 $log->syslog('debug',
399 'File name %s does not have the proper format: %s',
400 $marshalled, $marshal_regexp);
401 return undef;
402 }
403 $data = {
404 messagekey => $marshalled,
405 map {
406115002.46ms my $value = shift @matches;
407115005.01ms (defined $value and length $value) ? (lc($_) => $value) : ();
408230012.5ms } @{$marshal_keys}
409 };
410
4112300512µs my ($robot_id, $family, $listname, $type, $list, $priority);
412
413 $robot_id = lc($data->{'domainpart'})
414 if defined $data->{'domainpart'}
415 and length $data->{'domainpart'}
41623008.46ms23005.43ms and Conf::valid_robot($data->{'domainpart'}, {just_try => 1});
# spent 5.43ms making 2300 calls to Conf::valid_robot, avg 2µs/call
417
41823002.15ms if ($data->{localpart} and 0 == index $data->{localpart}, '@') {
419 my $familyname = substr $data->{localpart}, 1;
420 $family = Sympa::Family->new($familyname, $robot_id || '*');
421 } else {
422 ($listname, $type) = Sympa::Spool::split_listname($robot_id || '*',
42323003.75ms230045.4ms $data->{'localpart'});
# spent 45.4ms making 2300 calls to Sympa::Spool::split_listname, avg 20µs/call
4242300759µs $list =
425 Sympa::List->new($listname, $robot_id || '*', {'just_try' => 1})
426 if defined $listname;
427 }
428
429 ## Get priority
430 #FIXME: is this always needed?
43123004.87ms23004.14ms if (exists $data->{'priority'}) {
# spent 4.14ms making 2300 calls to Conf::get_robot_conf, avg 2µs/call
432 # Priority was given by metadata.
433 ;
434 } elsif ($type and $type eq 'sympaowner') { # sympa-request
435 $priority = 0;
436 } elsif ($type and $type eq 'listmaster') {
437 ## highest priority
438 $priority = 0;
439 } elsif ($type and $type eq 'owner') { # -request
440 $priority = Conf::get_robot_conf($robot_id, 'request_priority');
441 } elsif ($type and $type eq 'return_path') { # -owner
442 $priority = Conf::get_robot_conf($robot_id, 'owner_priority');
443 } elsif ($type and $type eq 'sympa') {
444 $priority = Conf::get_robot_conf($robot_id, 'sympa_priority');
445 } elsif (ref $list eq 'Sympa::List') {
446 $priority = $list->{'admin'}{'priority'};
447 } else {
448 $priority = Conf::get_robot_conf($robot_id, 'default_list_priority');
449 }
450
45123003.07ms $data->{context} = $list || $family || $robot_id || '*';
4522300339µs $data->{'listname'} = $listname if $listname;
45323001.13ms $data->{'listtype'} = $type if defined $type;
45423001.09ms $data->{'priority'} = $priority if defined $priority;
455
456 $log->syslog('debug3', 'messagekey=%s, context=%s, priority=%s',
45723003.27ms2300436ms $marshalled, $data->{context}, $data->{'priority'});
# spent 436ms making 2300 calls to Sympa::Log::syslog, avg 189µs/call
458
45923005.08ms return $data;
460}
461
462sub marshal_metadata {
463 my $message = shift;
464 my $marshal_format = shift;
465 my $marshal_keys = shift;
466 my %options = @_;
467
468 # "sympa@DOMAIN", "@FAMILYNAME@DOMAIN" and "LISTNAME(-TYPE)@DOMAIN" are
469 # supported.
470 my ($localpart, $domainpart);
471 my $that = $message->{context};
472 if (ref $that eq 'Sympa::List') {
473 ($localpart, $domainpart) = split /\@/,
474 Sympa::get_address($that, $message->{listtype});
475 } elsif (ref $that eq 'Sympa::Family') {
476 my $familyname;
477 ($familyname, $domainpart) = split /\@/, $that->get_id;
478 $localpart = sprintf '@%s', $familyname;
479 } else {
480 my $robot_id = $that || '*';
481 $localpart = Conf::get_robot_conf($robot_id, 'email');
482 $domainpart = Conf::get_robot_conf($robot_id, 'domain');
483 }
484
485 my @args = map {
486 if ($_ eq 'localpart') {
487 $localpart;
488 } elsif ($_ eq 'domainpart') {
489 $domainpart;
490 } elsif (lc $_ ne $_
491 and $options{keep_keys}
492 and exists $message->{lc $_}
493 and defined $message->{lc $_}
494 and !ref($message->{lc $_})) {
495 # If keep_keys is set, use metadata instead of auto-generated
496 # values.
497 $message->{lc $_};
498 } elsif ($_ eq 'AUTHKEY') {
499 Digest::MD5::md5_hex(time . (int rand 46656) . $domainpart);
500 } elsif ($_ eq 'KEYAUTH') {
501 substr
502 Digest::MD5::md5_hex(time . (int rand 46656) . $domainpart),
503 0, 16;
504 } elsif ($_ eq 'PID') {
505 $PID;
506 } elsif ($_ eq 'RAND') {
507 int rand 10000;
508 } elsif ($_ eq 'TIME') {
509 Time::HiRes::time();
510 } elsif (exists $message->{$_}
511 and defined $message->{$_}
512 and !ref($message->{$_})) {
513 $message->{$_};
514 } else {
515 '';
516 }
517 } @{$marshal_keys};
518
519 # Set "C" locale so that decimal point for "%f" will be ".".
520 my $locale_numeric = POSIX::setlocale(POSIX::LC_NUMERIC());
521 POSIX::setlocale(POSIX::LC_NUMERIC(), 'C');
522 my $marshalled = sprintf $marshal_format, @args;
523 POSIX::setlocale(POSIX::LC_NUMERIC(), $locale_numeric);
524 return $marshalled;
525}
526
527sub store_spool {
528 my $spool_dir = shift;
529 my $message = shift;
530 my $marshal_format = shift;
531 my $marshal_keys = shift;
532 my %options = @_;
533
534 # At first content is stored into temporary file that has unique name and
535 # is referred only by this function.
536 my $tmppath = sprintf '%s/T.sympa@_tempfile.%s.%ld.%ld',
537 $spool_dir, Sys::Hostname::hostname(), time, $PID;
538 my $fh;
539 unless (open $fh, '>', $tmppath) {
540 die sprintf 'Cannot create %s: %s', $tmppath, $ERRNO;
541 }
542 print $fh $message->to_string(original => $options{original});
543 close $fh;
544
545 # Rename temporary path to the file name including metadata.
546 # Will retry up to five times.
547 my $tries;
548 for ($tries = 0; $tries < 5; $tries++) {
549 my $metadata = {%$message};
550 if (ref $options{_filter_pre} eq 'CODE') {
551 next unless $options{_filter_pre}->($metadata);
552 }
553
554 my $marshalled =
555 Sympa::Spool::marshal_metadata($metadata, $marshal_format,
556 $marshal_keys);
557 next unless defined $marshalled and length $marshalled;
558 my $path = $spool_dir . '/' . $marshalled;
559
560 my $lock;
561 unless ($lock = Sympa::LockedFile->new($path, -1, '+')) {
562 next;
563 }
564 if (-e $path) {
565 $lock->close;
566 next;
567 }
568
569 unless (rename $tmppath, $path) {
570 die sprintf 'Cannot create %s: %s', $path, $ERRNO;
571 }
572 $lock->close;
573
574 # Set mtime to be {date} in metadata of the message.
575 my $mtime =
576 defined $message->{date} ? $message->{date}
577 : defined $message->{time} ? $message->{time}
578 : time;
579 utime $mtime, $mtime, $path;
580
581 return $marshalled;
582 }
583
584 unlink $tmppath;
585 return undef;
586}
587
5881;
589__END__
 
# spent 4.48ms within Sympa::Spool::CORE:close which was called 1150 times, avg 4µs/call: # 1150 times (4.48ms+0s) by Sympa::Spool::next at line 168, avg 4µs/call
sub Sympa::Spool::CORE:close; # opcode
# spent 428µs within Sympa::Spool::CORE:closedir which was called 230 times, avg 2µs/call: # 230 times (428µs+0s) by Sympa::Spool::_load at line 194, avg 2µs/call
sub Sympa::Spool::CORE:closedir; # opcode
# spent 18µs within Sympa::Spool::CORE:ftdir which was called: # once (18µs+0s) by Sympa::Spool::_create at line 85
sub Sympa::Spool::CORE:ftdir; # opcode
# spent 14.5ms within Sympa::Spool::CORE:ftfile which was called 2300 times, avg 6µs/call: # 2300 times (14.5ms+0s) by Sympa::Spool::_load at line 203, avg 6µs/call
sub Sympa::Spool::CORE:ftfile; # opcode
# spent 21.5ms within Sympa::Spool::CORE:match which was called 7821 times, avg 3µs/call: # 5520 times (13.9ms+0s) by Sympa::Spool::_load at line 203, avg 3µs/call # 2300 times (7.59ms+0s) by Sympa::Spool::unmarshal_metadata at line 397, avg 3µs/call # once (7µs+0s) by Sympa::Spool::build_glob_pattern at line 323
sub Sympa::Spool::CORE:match; # opcode
# spent 18.6ms within Sympa::Spool::CORE:open which was called 1150 times, avg 16µs/call: # 1150 times (18.6ms+0s) by Sympa::Spool::next at line 141, avg 16µs/call
sub Sympa::Spool::CORE:open; # opcode
# spent 3.93ms within Sympa::Spool::CORE:open_dir which was called 230 times, avg 17µs/call: # 230 times (3.93ms+0s) by Sympa::Spool::_load at line 192, avg 17µs/call
sub Sympa::Spool::CORE:open_dir; # opcode
# spent 3.96ms within Sympa::Spool::CORE:readdir which was called 230 times, avg 17µs/call: # 230 times (3.96ms+0s) by Sympa::Spool::_load at line 193, avg 17µs/call
sub Sympa::Spool::CORE:readdir; # opcode
# spent 9.55ms within Sympa::Spool::CORE:readline which was called 1150 times, avg 8µs/call: # 1150 times (9.55ms+0s) by Sympa::Spool::next at line 161, avg 8µs/call
sub Sympa::Spool::CORE:readline; # opcode
# spent 3.15ms within Sympa::Spool::CORE:regcomp which was called 2300 times, avg 1µs/call: # 2300 times (3.15ms+0s) by Sympa::Spool::unmarshal_metadata at line 397, avg 1µs/call
sub Sympa::Spool::CORE:regcomp; # opcode
# spent 680µs within Sympa::Spool::CORE:sort which was called 231 times, avg 3µs/call: # 230 times (678µs+0s) by Sympa::Spool::_load at line 200, avg 3µs/call # once (2µs+0s) by Sympa::Spool::_create at line 84
sub Sympa::Spool::CORE:sort; # opcode
# spent 23µs within Sympa::Spool::CORE:subst which was called 2 times, avg 12µs/call: # once (18µs+0s) by Sympa::Spool::build_glob_pattern at line 305 # once (5µs+0s) by Sympa::Spool::build_glob_pattern at line 319
sub Sympa::Spool::CORE:subst; # opcode
# spent 8µs within Sympa::Spool::CORE:substcont which was called 6 times, avg 1µs/call: # 6 times (8µs+0s) by Sympa::Spool::build_glob_pattern at line 305, avg 1µs/call
sub Sympa::Spool::CORE:substcont; # opcode
# spent 2µs within Sympa::Spool::CORE:umask which was called 2 times, avg 800ns/call: # once (1µs+0s) by Sympa::Spool::_create at line 83 # once (500ns+0s) by Sympa::Spool::_create at line 102
sub Sympa::Spool::CORE:umask; # opcode