← Index
NYTProf Performance Profile   « line view »
For ./view
  Run on Fri Jul 31 19:05:14 2015
Reported on Fri Jul 31 19:08:10 2015

Filename/var/www/foswiki11/lib/Foswiki/Search/InfoCache.pm
StatementsExecuted 351710 statements in 1.03s
Subroutines
Calls P F Exclusive
Time
Inclusive
Time
Subroutine
5248311636ms3.89sFoswiki::Search::InfoCache::::__ANON__[:579]Foswiki::Search::InfoCache::__ANON__[:579]
876011320ms701msFoswiki::Search::InfoCache::::addTopicFoswiki::Search::InfoCache::addTopic
8111179ms180msFoswiki::Search::InfoCache::::sortTopicsFoswiki::Search::InfoCache::sortTopics
1252283.8ms350msFoswiki::Search::InfoCache::::addTopicsFoswiki::Search::InfoCache::addTopics
81223.27ms353msFoswiki::Search::InfoCache::::newFoswiki::Search::InfoCache::new
121222.52ms183msFoswiki::Search::InfoCache::::sortResultsFoswiki::Search::InfoCache::sortResults
81221.93ms4.74msFoswiki::Search::InfoCache::::_getListOfWebsFoswiki::Search::InfoCache::_getListOfWebs
41111.39ms333msFoswiki::Search::InfoCache::::getTopicListIteratorFoswiki::Search::InfoCache::getTopicListIterator
4111713µs713µsFoswiki::Search::InfoCache::::convertTopicPatternToRegexFoswiki::Search::InfoCache::convertTopicPatternToRegex
111407µs472µsFoswiki::Search::InfoCache::::BEGIN@26Foswiki::Search::InfoCache::BEGIN@26
11112µs25µsFoswiki::Search::InfoCache::::BEGIN@3Foswiki::Search::InfoCache::BEGIN@3
1119µs14µsFoswiki::Search::InfoCache::::BEGIN@4Foswiki::Search::InfoCache::BEGIN@4
1118µs21µsFoswiki::Search::InfoCache::::BEGIN@23Foswiki::Search::InfoCache::BEGIN@23
1114µs4µsFoswiki::Search::InfoCache::::BEGIN@6Foswiki::Search::InfoCache::BEGIN@6
1114µs4µsFoswiki::Search::InfoCache::::BEGIN@24Foswiki::Search::InfoCache::BEGIN@24
1113µs3µsFoswiki::Search::InfoCache::::BEGIN@25Foswiki::Search::InfoCache::BEGIN@25
0000s0sFoswiki::Search::InfoCache::::_compareFoswiki::Search::InfoCache::_compare
0000s0sFoswiki::Search::InfoCache::::filterByDateFoswiki::Search::InfoCache::filterByDate
0000s0sFoswiki::Search::InfoCache::::getRev1InfoFoswiki::Search::InfoCache::getRev1Info
0000s0sFoswiki::Search::InfoCache::::isImmutableFoswiki::Search::InfoCache::isImmutable
0000s0sFoswiki::Search::InfoCache::::numberOfTopicsFoswiki::Search::InfoCache::numberOfTopics
Call graph for these subroutines as a Graphviz dot language file.
Line State
ments
Time
on line
Calls Time
in subs
Code
1# See bottom of file for license and copyright information
2package Foswiki::Search::InfoCache;
3228µs238µs
# spent 25µs (12+13) within Foswiki::Search::InfoCache::BEGIN@3 which was called: # once (12µs+13µs) by Foswiki::Search::BEGIN@19 at line 3
use strict;
# spent 25µs making 1 call to Foswiki::Search::InfoCache::BEGIN@3 # spent 13µs making 1 call to strict::import
4226µs219µs
# spent 14µs (9+5) within Foswiki::Search::InfoCache::BEGIN@4 which was called: # once (9µs+5µs) by Foswiki::Search::BEGIN@19 at line 4
use warnings;
# spent 14µs making 1 call to Foswiki::Search::InfoCache::BEGIN@4 # spent 5µs making 1 call to warnings::import
5
6239µs14µs
# spent 4µs within Foswiki::Search::InfoCache::BEGIN@6 which was called: # once (4µs+0s) by Foswiki::Search::BEGIN@19 at line 6
use Foswiki::ListIterator ();
# spent 4µs making 1 call to Foswiki::Search::InfoCache::BEGIN@6
719µsour @ISA = ('Foswiki::ListIterator');
8
9=begin TML
10
11---+ package Foswiki::Search::InfoCache
12
13Support package; cache of topic info. When information about search hits is
14compiled for output, this cache is used to avoid recovering the same info
15about the same topic more than once.
16
17TODO: this is going to transform from an ugly duckling into the ResultSet Iterator
18
19I have the feeling that we should make result sets immutable
20
21=cut
22
23225µs234µs
# spent 21µs (8+13) within Foswiki::Search::InfoCache::BEGIN@23 which was called: # once (8µs+13µs) by Foswiki::Search::BEGIN@19 at line 23
use Assert;
# spent 21µs making 1 call to Foswiki::Search::InfoCache::BEGIN@23 # spent 13µs making 1 call to Assert::import
24218µs14µs
# spent 4µs within Foswiki::Search::InfoCache::BEGIN@24 which was called: # once (4µs+0s) by Foswiki::Search::BEGIN@19 at line 24
use Foswiki::Func ();
# spent 4µs making 1 call to Foswiki::Search::InfoCache::BEGIN@24
25218µs13µs
# spent 3µs within Foswiki::Search::InfoCache::BEGIN@25 which was called: # once (3µs+0s) by Foswiki::Search::BEGIN@19 at line 25
use Foswiki::Meta ();
# spent 3µs making 1 call to Foswiki::Search::InfoCache::BEGIN@25
2622.42ms1472µs
# spent 472µs (407+64) within Foswiki::Search::InfoCache::BEGIN@26 which was called: # once (407µs+64µs) by Foswiki::Search::BEGIN@19 at line 26
use Foswiki::Iterator::FilterIterator ();
# spent 472µs making 1 call to Foswiki::Search::InfoCache::BEGIN@26
27
28#use Monitor ();
29#Monitor::MonitorMethod('Foswiki::Search::InfoCache', 'getTopicListIterator');
30
31=begin TML
32
33---++ ClassMethod new($session, $defaultWeb, \@topicList)
34initialise a new list of topics, allowing their data to be lazy loaded if and when needed.
35
36$defaultWeb is used to qualify topics that do not have a web specifier - should expect it to be the same as BASEWEB in most cases.
37
38because this 'Iterator can be created and filled dynamically, once the Iterator hasNext() and next() methods are called, it is immutable.
39
40TODO: duplicates??, what about topicExists?
41TODO: remove the iterator code from this __container__ and make a $this->getIterator() which can then be used.
42TODO: replace the Iterator->reset() function with a lightweight Iterator->copyConstructor?
43TODO: or..... make reset() make the object muttable again, so we can change the elements in the list, but re-use the meta cache??
44CONSIDER: convert the internals to a hash[tomAddress] = {matches->[list of resultint text bits], othermeta...} - except this does not give us order :/
45
46=cut
47
48
# spent 353ms (3.27+350) within Foswiki::Search::InfoCache::new which was called 81 times, avg 4.36ms/call: # 41 times (561µs+363µs) by Foswiki::Store::QueryAlgorithms::BruteForce::_webQuery at line 101 of /var/www/foswiki11/lib/Foswiki/Store/QueryAlgorithms/BruteForce.pm, avg 23µs/call # 40 times (2.71ms+350ms) by Foswiki::Store::SearchAlgorithms::Forking::_webQuery at line 298 of /var/www/foswiki11/lib/Foswiki/Store/SearchAlgorithms/Forking.pm, avg 8.81ms/call
sub new {
4981328µs my ( $class, $session, $defaultWeb, $topicList ) = @_;
50
51811.29ms812.22ms my $this = $class->SUPER::new( [] );
# spent 2.22ms making 81 calls to Foswiki::ListIterator::new, avg 27µs/call
5281192µs $this->{_session} = $session;
5381172µs $this->{_defaultWeb} = $defaultWeb;
5481227µs $this->{count} = 0;
5581452µs40348ms if ( defined($topicList) ) {
# spent 348ms making 40 calls to Foswiki::Search::InfoCache::addTopics, avg 8.70ms/call
56 $this->addTopics( $defaultWeb, @$topicList );
57 }
58
5981338µs return $this;
60}
61
62sub isImmutable {
63 my $this = shift;
64
65 return ( $this->{index} != 0 );
66}
67
68
# spent 350ms (83.8+266) within Foswiki::Search::InfoCache::addTopics which was called 125 times, avg 2.80ms/call: # 85 times (956µs+1.05ms) by Foswiki::Store::QueryAlgorithms::BruteForce::_webQuery at line 227 of /var/www/foswiki11/lib/Foswiki/Store/QueryAlgorithms/BruteForce.pm, avg 24µs/call # 40 times (82.9ms+265ms) by Foswiki::Search::InfoCache::new at line 55, avg 8.70ms/call
sub addTopics {
691251.35ms my ( $this, $defaultWeb, @list ) = @_;
70
71125187µs125140µs ASSERT( !$this->isImmutable() )
# spent 140µs making 125 calls to Assert::ASSERTS_OFF, avg 1µs/call
72 if DEBUG; #cannot modify list once its being used as an iterator.
73125149µs125109µs ASSERT( defined($defaultWeb) ) if DEBUG;
# spent 109µs making 125 calls to Assert::ASSERTS_OFF, avg 872ns/call
74
75125293µs foreach my $t (@list) {
76884533.7ms8845266ms my ( $web, $topic ) =
# spent 266ms making 8845 calls to Foswiki::Func::normalizeWebTopicName, avg 30µs/call
77 Foswiki::Func::normalizeWebTopicName( $defaultWeb, $t );
78884513.9ms push( @{ $this->{list} }, "$web.$topic" );
79884512.1ms $this->{count}++;
80 }
811251.37ms undef $this->{sorted};
82}
83
84#TODO: what if it isa Meta obj
85#TODO: or an infoCache obj..
86
# spent 701ms (320+381) within Foswiki::Search::InfoCache::addTopic which was called 8760 times, avg 80µs/call: # 8760 times (320ms+381ms) by Foswiki::Store::QueryAlgorithms::BruteForce::_webQuery at line 243 of /var/www/foswiki11/lib/Foswiki/Store/QueryAlgorithms/BruteForce.pm, avg 80µs/call
sub addTopic {
8787605.52ms my ( $this, $meta ) = @_;
88
8987608.62ms87607.02ms ASSERT( !$this->isImmutable() )
# spent 7.02ms making 8760 calls to Assert::ASSERTS_OFF, avg 802ns/call
90 if DEBUG; #cannot modify list once its being used as an iterator.
91
92876014.6ms876023.7ms my $web = $meta->web();
# spent 23.7ms making 8760 calls to Foswiki::Meta::web, avg 3µs/call
93876013.0ms876016.7ms my $topic = $meta->topic();
# spent 16.7ms making 8760 calls to Foswiki::Meta::topic, avg 2µs/call
94
95876016.9ms8760187ms my ( $w, $t ) = Foswiki::Func::normalizeWebTopicName( $web, $topic );
# spent 187ms making 8760 calls to Foswiki::Func::normalizeWebTopicName, avg 21µs/call
9687607.06ms my $webtopic = "$w.$t";
9787608.81ms push( @{ $this->{list} }, $webtopic );
9887603.05ms $this->{count}++;
99876040.2ms26280147ms if ( defined($meta) ) {
# spent 110ms making 8760 calls to Foswiki::MetaCache::get, avg 13µs/call # spent 19.6ms making 8760 calls to Foswiki::search, avg 2µs/call # spent 17.6ms making 8760 calls to Foswiki::Search::metacache, avg 2µs/call
100 $this->{_session}->search->metacache->get( $web, $topic, $meta );
101 }
102876052.0ms undef $this->{sorted};
103}
104
105sub numberOfTopics {
106 my $this = shift;
107
108 # can't use this, as it lies once its gone through the 'sortResults' hack
109 #return scalar(@{ $this->{list} });
110 # when fixed, the count update in filterByDate should be removed
111
112 return $this->{count};
113}
114
115=begin TML
116
117---++ ObjectMethod sortResults($params)
118
119the implementation of %SORT{"" limit="" order="" reverse="" date=""}%
120
121it should be possible for the search engine to pre-sort, making this a nop, or to
122delay evaluated, partially evaluated, or even delegated to the DB/SQL
123
124can call repeatedly, the list will only be re-sorted if new elements are added.
125
126=cut
127
128
# spent 183ms (2.52+180) within Foswiki::Search::InfoCache::sortResults which was called 121 times, avg 1.51ms/call: # 81 times (587µs+53.3ms) by Foswiki::Search::ResultSet::sortResults at line 194 of /var/www/foswiki11/lib/Foswiki/Search/ResultSet.pm, avg 665µs/call # 40 times (1.93ms+127ms) by Foswiki::Store::SearchAlgorithms::Forking::query at line 184 of /var/www/foswiki11/lib/Foswiki/Store/SearchAlgorithms/Forking.pm, avg 3.22ms/call
sub sortResults {
129121110µs my ( $this, $params ) = @_;
130
131 #TODO: for now assume we do not change the sort order later
132121364µs return if ( defined( $this->{sorted} ) );
1338162µs $this->{sorted} = 1;
134
13581102µs my $session = $this->{_session};
136
13781122µs my $sortOrder = $params->{order} || '';
13881596µs81598µs my $revSort = Foswiki::isTrue( $params->{reverse} );
# spent 598µs making 81 calls to Foswiki::isTrue, avg 7µs/call
13981164µs my $limit = $params->{limit} || '';
140
141 #SMELL: duplicated code - removeme
142 # Limit search results
14381121µs if ( $limit =~ /(^\d+$)/o ) {
144
145 # only digits, all else is the same as
146 # an empty string. "+10" won't work.
147 $limit = $1;
148 }
149 else {
150
151 # change 'all' to 0, then to big number
1528140µs $limit = 0;
153 }
1548134µs $limit = 32000 unless ($limit);
155
156#TODO: this is really an ugly hack to get around the rather horrible limit 'performance' hack
1578150µs if ( defined( $params->{pager_show_results_to} )
158 and $params->{pager_show_results_to} > 0 )
159 {
160 $limit =
161 $params->{pager_skip_results_from} + $params->{pager_show_results_to};
162 }
163
164 # sort the topic list by date, author or topic name, and cache the
165 # info extracted to do the sorting
16681191µs if ( $sortOrder eq 'modified' ) {
167
168 # For performance:
169 # * sort by approx time (to get a rough list)
170 # * shorten list to the limit + some slack
171 # * sort by rev date on shortened list to get the accurate list
172 # SMELL: Cairo had efficient two stage handling of modified sort.
173 # SMELL: In Dakar this seems to be pointless since latest rev
174 # time is taken from topic instead of dir list.
175 my $slack = 10;
176 if ( $limit + 2 * $slack < scalar( @{ $this->{list} } ) ) {
177
178 # sort by approx latest rev time
179 my @tmpList =
180 map { $_->[1] }
181 sort { $a->[0] <=> $b->[0] }
182 map {
183 my ( $web, $topic ) =
184 Foswiki::Func::normalizeWebTopicName( $this->{_defaultWeb},
185 $_ );
186 [ $session->getApproxRevTime( $web, $topic ), $_ ]
187 } @{ $this->{list} };
188 @tmpList = reverse(@tmpList) if ($revSort);
189
190 # then shorten list and build the hashes for date and author
191 my $idx = $limit + $slack;
192 @{ $this->{list} } = ();
193 foreach (@tmpList) {
194 push( @{ $this->{list} }, $_ );
195 $idx -= 1;
196 last if $idx <= 0;
197 }
198 }
199
200 }
201 elsif (
202 $sortOrder =~ /^creat/ || # topic creation time
203 $sortOrder eq 'editby' || # author
204 $sortOrder =~ s/^formfield\(([^\)]+)\)$/$1/ # form field
205 )
206 {
207 }
208 else {
209
210 #default to topic sorting
2118139µs $sortOrder = 'topic';
212 }
21381686µs81180ms sortTopics( $this->{list}, $sortOrder, !$revSort );
# spent 180ms making 81 calls to Foswiki::Search::InfoCache::sortTopics, avg 2.22ms/call
214}
215
216=begin TML
217
218---++ filterByDate( $date )
219
220Filter the list by date interval; see System.TimeSpecifications.
221
222<verbatim>
223$infoCache->filterByDate( $date );
224</verbatim>
225
226=cut
227
228sub filterByDate {
229 my ( $this, $date ) = @_;
230
231 my $session = $Foswiki::Plugins::SESSION;
232
233 require Foswiki::Time;
234 my @ends = Foswiki::Time::parseInterval($date);
235 my @resultList = ();
236 foreach my $webtopic ( @{ $this->{list} } ) {
237
238 # if date falls out of interval: exclude topic from result
239 my ( $web, $topic ) =
240 Foswiki::Func::normalizeWebTopicName( $this->{_defaultWeb},
241 $webtopic );
242 my $topicdate = $session->getApproxRevTime( $web, $topic );
243 push( @resultList, $webtopic )
244 unless ( $topicdate < $ends[0] || $topicdate > $ends[1] );
245 }
246 $this->{list} = \@resultList;
247
248 # use this hack until numberOfTopics reads the length of list
249 $this->{count} = scalar @{ $this->{list} };
250}
251
252######OLD methods
253
254# Determins, and caches, the topic revision info of the base version,
255sub getRev1Info {
256 my ( $webtopic, $attr ) = @_;
257
258 my $session = $Foswiki::Plugins::SESSION;
259 my $metacache = $session->search->metacache;
260
261 my ( $web, $topic ) =
262 Foswiki::Func::normalizeWebTopicName( $Foswiki::cfg{UsersWebName},
263 $webtopic );
264
265 my $info = $metacache->get( $web, $topic );
266 unless ( defined $info->{$attr} ) {
267 my $ri = $info->{rev1info};
268 unless ($ri) {
269 my $tmp = Foswiki::Meta->load( $session, $web, $topic, 1 );
270 $info->{rev1info} = $ri = $tmp->getRevisionInfo();
271 }
272
273 if ( $attr eq 'createusername' ) {
274 $info->{createusername} =
275 $session->{users}->getLoginName( $ri->{author} );
276 }
277 elsif ( $attr eq 'createwikiname' ) {
278 $info->{createwikiname} =
279 $session->{users}->getWikiName( $ri->{author} );
280 }
281 elsif ( $attr eq 'createwikiusername' ) {
282 $info->{createwikiusername} =
283 $session->{users}->webDotWikiName( $ri->{author} );
284 }
285 elsif ($attr eq 'createdate'
286 or $attr eq 'createlongdate'
287 or $attr eq 'created' )
288 {
289 $info->{created} = $ri->{date};
290 require Foswiki::Time;
291 $info->{createdate} = Foswiki::Time::formatTime( $ri->{date} );
292
293 #TODO: wow thats disgusting.
294 $info->{created} = $info->{createlongdate} = $info->{createdate};
295 }
296 }
297 return $info->{$attr};
298}
299
300# Sort a topic list using cached info
301
# spent 180ms (179+521µs) within Foswiki::Search::InfoCache::sortTopics which was called 81 times, avg 2.22ms/call: # 81 times (179ms+521µs) by Foswiki::Search::InfoCache::sortResults at line 213, avg 2.22ms/call
sub sortTopics {
30281229µs my ( $listRef, $sortfield, $revSort ) = @_;
30381306µs81289µs ASSERT($sortfield);
# spent 289µs making 81 calls to Assert::dummyASSERT, avg 4µs/call
304
305 #seriously, don't spend time doing stuff to an empty list (or a list of one!)
3068162µs return if ( scalar(@$listRef) <= 0 );
307
3088164µs if ( $sortfield eq 'topic' ) {
309
310# simple sort, see Codev.SchwartzianTransformMisused
311# note no extraction of topic info here, as not needed
312# for the sort. Instead it will be read lazily, later on.
313#TODO: need to remove the web portion
314#mmm, need to profile if there is even a point to this - as all topics still need to be parsed to find permissions
315815.19ms if ($revSort) {
316 @{$listRef} = map { $_->[1] }
31717605111ms sort { $a->[0] cmp $b->[0] }
3181760517.8ms map { $_ =~ /^(.*?)([^.]+)$/; [ $2, $_ ] } #quickhack to remove web
3198143.4ms @{$listRef};
320 }
321 else {
322 @{$listRef} = map { $_->[1] }
323 sort { $b->[0] cmp $a->[0] }
324 map { $_ =~ /^(.*?)([^.]+)$/; [ $2, $_ ] } #quickhack to remove web
325 @{$listRef};
326 }
32781263µs81232µs ASSERT( $listRef->[0] ) if DEBUG;
# spent 232µs making 81 calls to Assert::ASSERTS_OFF, avg 3µs/call
32881355µs return;
329 }
330
331 my $metacache = $Foswiki::Plugins::SESSION->search->metacache;
332
333 # populate the cache for each topic
334 foreach my $webtopic ( @{$listRef} ) {
335 if ( $sortfield =~ /^creat/ ) {
336
337 # The act of getting the info will cache it
338 getRev1Info( $webtopic, $sortfield );
339 }
340 else {
341
342 #duplicated from above - I'd rather do it only here, but i'm not sure if i can.
343 $sortfield =~ s/^formfield\((.*)\)$/$1/; # form field
344
345 my $info = $metacache->get($webtopic);
346 if ( !defined( $info->{$sortfield} ) ) {
347
348#under normal circumstances this code is not called, because the metacach has already filled it.
349 if ( $sortfield eq 'modified' ) {
350 my $ri = $info->{tom}->getRevisionInfo();
351 $info->{$sortfield} = $ri->{date};
352 }
353 else {
354 $info->{$sortfield} =
355 Foswiki::Search::displayFormField( $info->{tom},
356 $sortfield );
357 }
358 }
359 }
360
361 # SMELL: CDot isn't clear why this is needed, but it is otherwise
362 # we end up with the users all being identified as "undef"
363 my $info = $metacache->get($webtopic);
364 $info->{editby} =
365 $info->{tom}->session->{users}->getWikiName( $info->{editby} );
366 }
367 if ($revSort) {
368 @{$listRef} = map { $_->[1] }
369 sort { _compare( $b->[0], $a->[0] ) }
370 map { [ $metacache->get($_)->{$sortfield}, $_ ] } @{$listRef};
371 }
372 else {
373 @{$listRef} = map { $_->[1] }
374 sort { _compare( $a->[0], $b->[0] ) }
375 map { [ $metacache->get($_)->{$sortfield}, $_ ] } @{$listRef};
376 }
377}
378
379# RE for a full-spec floating-point number
3801100nsour ($NUMBER);
38112µs$NUMBER = qr/^[-+]?[0-9]+(\.[0-9]*)?([Ee][-+]?[0-9]+)?$/s;
382
383sub _compare {
384 my $x = shift;
385 my $y = shift;
386
387 ASSERT( defined($x) ) if DEBUG;
388 ASSERT( defined($y) ) if DEBUG;
389
390 if ( $x =~ /$NUMBER/o && $y =~ /$NUMBER/o ) {
391
392 # when sorting numbers do it largest first; this is just because
393 # this is what date comparisons need.
394 return $y <=> $x;
395 }
396
397 my $datex = undef;
398 my $datey = undef;
399
400 # parseTime can error if you give it a date out of range so we skip
401 # testing if pure number
402 # We skip testing for dates the first character is not a digit
403 # as all formats we recognise as dates are
404 if ( $x =~ /^\d/
405 && $x !~ /$NUMBER/o
406 && $y =~ /^\d/
407 && $y !~ /$NUMBER/o )
408 {
409 $datex = Foswiki::Time::parseTime($x);
410 $datey = Foswiki::Time::parseTime($y) if $datex;
411 }
412
413 if ( $datex && $datey ) {
414 return $datey <=> $datex;
415 }
416 else {
417 return $y cmp $x;
418 }
419}
420
421#convert a comma separated list of webs into the list we'll process
422#TODO: this is part of the Store now, and so should not need to reference Meta - it rather uses the store..
423
# spent 4.74ms (1.93+2.81) within Foswiki::Search::InfoCache::_getListOfWebs which was called 81 times, avg 59µs/call: # 41 times (974µs+1.80ms) by Foswiki::Store::QueryAlgorithms::BruteForce::query at line 56 of /var/www/foswiki11/lib/Foswiki/Store/QueryAlgorithms/BruteForce.pm, avg 68µs/call # 40 times (953µs+1.02ms) by Foswiki::Store::SearchAlgorithms::Forking::query at line 161 of /var/www/foswiki11/lib/Foswiki/Store/SearchAlgorithms/Forking.pm, avg 49µs/call
sub _getListOfWebs {
4248165µs my ( $webName, $recurse, $searchAllFlag ) = @_;
4258130µs my $session = $Foswiki::Plugins::SESSION;
426
4278114µs my %excludeWeb;
4288119µs my @tmpWebs;
429
430 #$web = Foswiki::Sandbox::untaint( $web,\&Foswiki::Sandbox::validateWebName );
431
4328146µs if ($webName) {
4334195µs foreach my $web ( split( /[\,\s]+/, $webName ) ) {
4344159µs $web =~ s#\.#/#go;
435
436 # the web processing loop filters for valid web names,
437 # so don't do it here.
4384179µs if ( $web =~ s/^-// ) {
439 $excludeWeb{$web} = 1;
440 }
441 else {
44241195µs41339µs if ( $web =~ /^(all|on)$/i
# spent 339µs making 41 calls to Foswiki::isTrue, avg 8µs/call
443 || $Foswiki::cfg{EnableHierarchicalWebs}
444 && Foswiki::isTrue($recurse) )
445 {
446 require Foswiki::WebFilter;
447 my $webObject;
448 my $prefix = "$web/";
449 if ( $web =~ /^(all|on)$/i ) {
450 $webObject = Foswiki::Meta->new($session);
451 $prefix = '';
452 }
453 else {
454 $web = Foswiki::Sandbox::untaint( $web,
455 \&Foswiki::Sandbox::validateWebName );
456 ASSERT($web);
457 push( @tmpWebs, $web );
458 $webObject = Foswiki::Meta->new( $session, $web );
459 }
460 my $it = $webObject->eachWeb(1);
461 while ( $it->hasNext() ) {
462 my $w = $prefix . $it->next();
463 next
464 unless $Foswiki::WebFilter::user_allowed->ok(
465 $session, $w );
466 $w = Foswiki::Sandbox::untaint( $w,
467 \&Foswiki::Sandbox::validateWebName );
468 ASSERT($web);
469 push( @tmpWebs, $w );
470 }
471 }
472 else {
47341109µs41730µs $web = Foswiki::Sandbox::untaint( $web,
# spent 730µs making 41 calls to Foswiki::Sandbox::untaint, avg 18µs/call
474 \&Foswiki::Sandbox::validateWebName );
4754132µs push( @tmpWebs, $web );
476 }
477 }
478 }
479
480 }
481 else {
482
483 # default to current web
48440214µs401.47ms my $web =
# spent 1.47ms making 40 calls to Foswiki::Sandbox::untaint, avg 37µs/call
485 Foswiki::Sandbox::untaint( $session->{webName},
486 \&Foswiki::Sandbox::validateWebName );
4874029µs push( @tmpWebs, $web );
4884065µs40278µs if ( Foswiki::isTrue($recurse) ) {
# spent 278µs making 40 calls to Foswiki::isTrue, avg 7µs/call
489 my $webObject = Foswiki::Meta->new( $session, $session->{webName} );
490 my $it =
491 $webObject->eachWeb( $Foswiki::cfg{EnableHierarchicalWebs} );
492 while ( $it->hasNext() ) {
493 my $w = $session->{webName} . '/' . $it->next();
494 next
495 unless $Foswiki::WebFilter::user_allowed->ok( $session, $w );
496 $w = Foswiki::Sandbox::untaint( $w,
497 \&Foswiki::Sandbox::validateWebName );
498 push( @tmpWebs, $w );
499 }
500 }
501 }
502
5038120µs my @webs;
50481106µs foreach my $web (@tmpWebs) {
5058118µs next unless defined $web;
5068191µs push( @webs, $web ) unless $excludeWeb{$web};
50781134µs $excludeWeb{$web} = 1; # eliminate duplicates
508 }
509
51081322µs return @webs;
511}
512#########################################
513#TODO: this is _now_ a default utility method that can be used by search&query algo's to brute force file a list of topics to search.
514#if you can avoid it, you should - as it needs to do an opendir on the web, and if you have alot of topics, life gets slow
515# get a list of topics to search in the web, filtered by the $topic
516# spec
517
# spent 333ms (1.39+331) within Foswiki::Search::InfoCache::getTopicListIterator which was called 41 times, avg 8.11ms/call: # 41 times (1.39ms+331ms) by Foswiki::Store::QueryAlgorithms::BruteForce::_webQuery at line 168 of /var/www/foswiki11/lib/Foswiki/Store/QueryAlgorithms/BruteForce.pm, avg 8.11ms/call
sub getTopicListIterator {
5184142µs my ( $webObject, $options ) = @_;
5194172µs my $casesensitive =
520 defined( $options->{casesensitive} ) ? $options->{casesensitive} : 1;
521
522 # E.g. "Web*, FooBar" ==> "^(Web.*|FooBar)$"
5234120µs $options->{excludeTopics} =
524 convertTopicPatternToRegex( $options->{excludeTopics} )
525 if ( $options->{excludeTopics} );
526
5274112µs my $topicFilter;
528417µs my $it;
5294138µs if ( $options->{includeTopics} ) {
530
531 # E.g. "Bug*, *Patch" ==> "^(Bug.*|.*Patch)$"
53241105µs41713µs $options->{includeTopics} =
# spent 713µs making 41 calls to Foswiki::Search::InfoCache::convertTopicPatternToRegex, avg 17µs/call
533 convertTopicPatternToRegex( $options->{includeTopics} );
534
535 # limit search to topic list
5364154µs if ( $casesensitive
537 and $options->{includeTopics} =~
538 /^\^\([\_\-\+$Foswiki::regex{mixedAlphaNum}\|]+\)\$$/ )
539 {
540
541 # topic list without wildcards
542 # for speed, do not get all topics in web
543 # but convert topic pattern into topic list
544 my $topics = $options->{includeTopics};
545 $topics =~ s/^\^\(//o;
546 $topics =~ s/\)\$//o;
547
548 # build list from topic pattern
549 my @list = split( /\|/, $topics );
550 $it = new Foswiki::ListIterator( \@list );
551 }
552 elsif ( !$casesensitive ) {
55341216µs $topicFilter = qr/$options->{includeTopics}/i;
554 }
555 else {
556 $topicFilter = qr/$options->{includeTopics}/;
557 }
558 }
559
56041156µs41330ms $it = $webObject->eachTopic() unless ( defined($it) );
# spent 330ms making 41 calls to Foswiki::Meta::eachTopic, avg 8.05ms/call
561
562 my $filterIter = new Foswiki::Iterator::FilterIterator(
563 $it,
564
# spent 3.89s (636ms+3.25) within Foswiki::Search::InfoCache::__ANON__[/var/www/foswiki11/lib/Foswiki/Search/InfoCache.pm:579] which was called 52483 times, avg 74µs/call: # 52483 times (636ms+3.25s) by Foswiki::Iterator::FilterIterator::hasNext at line 50 of /var/www/foswiki11/lib/Foswiki/Iterator/FilterIterator.pm, avg 74µs/call
sub {
5655248314.9ms my $item = shift;
566
567 #my $data = shift;
56852483208ms return unless !$topicFilter || $item =~ /$topicFilter/;
569
570 # exclude topics, Codev.ExcludeWebTopicsFromSearch
5714612530.0ms if ( !$casesensitive && $options->{excludeTopics} ) {
572 return if $item =~ /$options->{excludeTopics}/i;
573 }
574 elsif ( $options->{excludeTopics} ) {
575 return if $item =~ /$options->{excludeTopics}/;
576 }
57746125357ms922503.25s return $Foswiki::Plugins::SESSION->topicExists( $webObject->web,
# spent 3.14s making 46125 calls to Foswiki::topicExists, avg 68µs/call # spent 116ms making 46125 calls to Foswiki::Meta::web, avg 3µs/call
578 $item );
579 }
58041465µs41671µs );
# spent 671µs making 41 calls to Foswiki::Iterator::FilterIterator::new, avg 16µs/call
58141126µs return $filterIter;
582}
583
584
# spent 713µs within Foswiki::Search::InfoCache::convertTopicPatternToRegex which was called 41 times, avg 17µs/call: # 41 times (713µs+0s) by Foswiki::Search::InfoCache::getTopicListIterator at line 532, avg 17µs/call
sub convertTopicPatternToRegex {
5854134µs my ($topic) = @_;
5864113µs return '' unless ($topic);
587
588 # 'Web*, FooBar' ==> ( 'Web*', 'FooBar' ) ==> ( 'Web.*', "FooBar" )
5894196µs my @arr =
590123417µs map { s/[^\*\_\-\+$Foswiki::regex{mixedAlphaNum}]//go; s/\*/\.\*/go; $_ }
591 split( /(?:,\s*|\|)/, $topic );
5924118µs return '' unless (@arr);
593
594 # ( 'Web.*', 'FooBar' ) ==> "^(Web.*|FooBar)$"
59541185µs return '^(' . join( '|', @arr ) . ')$';
596}
597
59814µs1;
599__END__