Filename | /var/www/foswikidev/core/lib/Foswiki/Store/Interfaces/QueryAlgorithm.pm |
Statements | Executed 258766 statements in 847ms |
Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
---|---|---|---|---|---|
17520 | 1 | 1 | 806ms | 53.9s | __ANON__[:194] | Foswiki::Store::Interfaces::QueryAlgorithm::
8760 | 1 | 1 | 109ms | 162ms | getField | Foswiki::Store::Interfaces::QueryAlgorithm::
80 | 1 | 1 | 8.89ms | 108s | query (recurses: max depth 1, inclusive time 49.2s) | Foswiki::Store::Interfaces::QueryAlgorithm::
80 | 1 | 1 | 2.40ms | 8.41ms | getWebIterator | Foswiki::Store::Interfaces::QueryAlgorithm::
80 | 1 | 1 | 2.19ms | 4.55ms | getListOfWebs | Foswiki::Store::Interfaces::QueryAlgorithm::
80 | 1 | 1 | 2.06ms | 3.12ms | addACLFilter | Foswiki::Store::Interfaces::QueryAlgorithm::
1 | 1 | 1 | 1.79ms | 1.90ms | BEGIN@17 | Foswiki::Store::Interfaces::QueryAlgorithm::
80 | 1 | 1 | 1.57ms | 15.0ms | __ANON__[:235] | Foswiki::Store::Interfaces::QueryAlgorithm::
80 | 1 | 1 | 925µs | 157s | __ANON__[:119] | Foswiki::Store::Interfaces::QueryAlgorithm::
80 | 1 | 1 | 503µs | 503µs | addPager | Foswiki::Store::Interfaces::QueryAlgorithm::
1 | 1 | 1 | 437µs | 522µs | BEGIN@20 | Foswiki::Store::Interfaces::QueryAlgorithm::
1 | 1 | 1 | 402µs | 606µs | BEGIN@9 | Foswiki::Store::Interfaces::QueryAlgorithm::
1 | 1 | 1 | 302µs | 400µs | BEGIN@8 | Foswiki::Store::Interfaces::QueryAlgorithm::
2 | 2 | 2 | 17µs | 17µs | new | Foswiki::Store::Interfaces::QueryAlgorithm::
1 | 1 | 1 | 15µs | 27µs | BEGIN@4 | Foswiki::Store::Interfaces::QueryAlgorithm::
1 | 1 | 1 | 14µs | 41µs | BEGIN@344 | Foswiki::Store::Interfaces::QueryAlgorithm::
1 | 1 | 1 | 11µs | 41µs | BEGIN@6 | Foswiki::Store::Interfaces::QueryAlgorithm::
1 | 1 | 1 | 9µs | 13µs | BEGIN@5 | Foswiki::Store::Interfaces::QueryAlgorithm::
1 | 1 | 1 | 9µs | 42µs | BEGIN@30 | Foswiki::Store::Interfaces::QueryAlgorithm::
1 | 1 | 1 | 6µs | 6µs | BEGIN@18 | Foswiki::Store::Interfaces::QueryAlgorithm::
1 | 1 | 1 | 5µs | 5µs | BEGIN@10 | Foswiki::Store::Interfaces::QueryAlgorithm::
1 | 1 | 1 | 5µs | 5µs | BEGIN@21 | Foswiki::Store::Interfaces::QueryAlgorithm::
1 | 1 | 1 | 5µs | 5µs | BEGIN@19 | Foswiki::Store::Interfaces::QueryAlgorithm::
1 | 1 | 1 | 5µs | 5µs | BEGIN@23 | Foswiki::Store::Interfaces::QueryAlgorithm::
1 | 1 | 1 | 4µs | 4µs | BEGIN@11 | Foswiki::Store::Interfaces::QueryAlgorithm::
1 | 1 | 1 | 4µs | 4µs | BEGIN@16 | Foswiki::Store::Interfaces::QueryAlgorithm::
1 | 1 | 1 | 4µs | 4µs | BEGIN@14 | Foswiki::Store::Interfaces::QueryAlgorithm::
1 | 1 | 1 | 3µs | 3µs | BEGIN@12 | Foswiki::Store::Interfaces::QueryAlgorithm::
1 | 1 | 1 | 3µs | 3µs | BEGIN@15 | Foswiki::Store::Interfaces::QueryAlgorithm::
1 | 1 | 1 | 3µs | 3µs | BEGIN@13 | Foswiki::Store::Interfaces::QueryAlgorithm::
0 | 0 | 0 | 0s | 0s | getForm | Foswiki::Store::Interfaces::QueryAlgorithm::
0 | 0 | 0 | 0s | 0s | getRefTopic | Foswiki::Store::Interfaces::QueryAlgorithm::
0 | 0 | 0 | 0s | 0s | getRev1Info | Foswiki::Store::Interfaces::QueryAlgorithm::
Line | State ments |
Time on line |
Calls | Time in subs |
Code |
---|---|---|---|---|---|
1 | # See bottom of file for license and copyright information | ||||
2 | package Foswiki::Store::Interfaces::QueryAlgorithm; | ||||
3 | |||||
4 | 2 | 28µs | 2 | 38µs | # spent 27µs (15+11) within Foswiki::Store::Interfaces::QueryAlgorithm::BEGIN@4 which was called:
# once (15µs+11µs) by Foswiki::Store::QueryAlgorithms::BruteForce::BEGIN@29 at line 4 # spent 27µs making 1 call to Foswiki::Store::Interfaces::QueryAlgorithm::BEGIN@4
# spent 11µs making 1 call to strict::import |
5 | 2 | 24µs | 2 | 17µs | # spent 13µs (9+4) within Foswiki::Store::Interfaces::QueryAlgorithm::BEGIN@5 which was called:
# once (9µs+4µs) by Foswiki::Store::QueryAlgorithms::BruteForce::BEGIN@29 at line 5 # spent 13µs making 1 call to Foswiki::Store::Interfaces::QueryAlgorithm::BEGIN@5
# spent 4µs making 1 call to warnings::import |
6 | 2 | 27µs | 2 | 72µs | # spent 41µs (11+31) within Foswiki::Store::Interfaces::QueryAlgorithm::BEGIN@6 which was called:
# once (11µs+31µs) by Foswiki::Store::QueryAlgorithms::BruteForce::BEGIN@29 at line 6 # spent 41µs making 1 call to Foswiki::Store::Interfaces::QueryAlgorithm::BEGIN@6
# spent 31µs making 1 call to Exporter::import |
7 | |||||
8 | 2 | 90µs | 1 | 400µs | # spent 400µs (302+98) within Foswiki::Store::Interfaces::QueryAlgorithm::BEGIN@8 which was called:
# once (302µs+98µs) by Foswiki::Store::QueryAlgorithms::BruteForce::BEGIN@29 at line 8 # spent 400µs making 1 call to Foswiki::Store::Interfaces::QueryAlgorithm::BEGIN@8 |
9 | 2 | 101µs | 1 | 606µs | # spent 606µs (402+204) within Foswiki::Store::Interfaces::QueryAlgorithm::BEGIN@9 which was called:
# once (402µs+204µs) by Foswiki::Store::QueryAlgorithms::BruteForce::BEGIN@29 at line 9 # spent 606µs making 1 call to Foswiki::Store::Interfaces::QueryAlgorithm::BEGIN@9 |
10 | 2 | 22µs | 1 | 5µs | # spent 5µs within Foswiki::Store::Interfaces::QueryAlgorithm::BEGIN@10 which was called:
# once (5µs+0s) by Foswiki::Store::QueryAlgorithms::BruteForce::BEGIN@29 at line 10 # spent 5µs making 1 call to Foswiki::Store::Interfaces::QueryAlgorithm::BEGIN@10 |
11 | 2 | 20µs | 1 | 4µs | # spent 4µs within Foswiki::Store::Interfaces::QueryAlgorithm::BEGIN@11 which was called:
# once (4µs+0s) by Foswiki::Store::QueryAlgorithms::BruteForce::BEGIN@29 at line 11 # spent 4µs making 1 call to Foswiki::Store::Interfaces::QueryAlgorithm::BEGIN@11 |
12 | 2 | 19µs | 1 | 3µs | # spent 3µs within Foswiki::Store::Interfaces::QueryAlgorithm::BEGIN@12 which was called:
# once (3µs+0s) by Foswiki::Store::QueryAlgorithms::BruteForce::BEGIN@29 at line 12 # spent 3µs making 1 call to Foswiki::Store::Interfaces::QueryAlgorithm::BEGIN@12 |
13 | 2 | 20µs | 1 | 3µs | # spent 3µs within Foswiki::Store::Interfaces::QueryAlgorithm::BEGIN@13 which was called:
# once (3µs+0s) by Foswiki::Store::QueryAlgorithms::BruteForce::BEGIN@29 at line 13 # spent 3µs making 1 call to Foswiki::Store::Interfaces::QueryAlgorithm::BEGIN@13 |
14 | 2 | 20µs | 1 | 4µs | # spent 4µs within Foswiki::Store::Interfaces::QueryAlgorithm::BEGIN@14 which was called:
# once (4µs+0s) by Foswiki::Store::QueryAlgorithms::BruteForce::BEGIN@29 at line 14 # spent 4µs making 1 call to Foswiki::Store::Interfaces::QueryAlgorithm::BEGIN@14 |
15 | 2 | 19µs | 1 | 3µs | # spent 3µs within Foswiki::Store::Interfaces::QueryAlgorithm::BEGIN@15 which was called:
# once (3µs+0s) by Foswiki::Store::QueryAlgorithms::BruteForce::BEGIN@29 at line 15 # spent 3µs making 1 call to Foswiki::Store::Interfaces::QueryAlgorithm::BEGIN@15 |
16 | 2 | 20µs | 1 | 4µs | # spent 4µs within Foswiki::Store::Interfaces::QueryAlgorithm::BEGIN@16 which was called:
# once (4µs+0s) by Foswiki::Store::QueryAlgorithms::BruteForce::BEGIN@29 at line 16 # spent 4µs making 1 call to Foswiki::Store::Interfaces::QueryAlgorithm::BEGIN@16 |
17 | 2 | 117µs | 1 | 1.90ms | # spent 1.90ms (1.79+101µs) within Foswiki::Store::Interfaces::QueryAlgorithm::BEGIN@17 which was called:
# once (1.79ms+101µs) by Foswiki::Store::QueryAlgorithms::BruteForce::BEGIN@29 at line 17 # spent 1.90ms making 1 call to Foswiki::Store::Interfaces::QueryAlgorithm::BEGIN@17 |
18 | 2 | 24µs | 1 | 6µs | # spent 6µs within Foswiki::Store::Interfaces::QueryAlgorithm::BEGIN@18 which was called:
# once (6µs+0s) by Foswiki::Store::QueryAlgorithms::BruteForce::BEGIN@29 at line 18 # spent 6µs making 1 call to Foswiki::Store::Interfaces::QueryAlgorithm::BEGIN@18 |
19 | 2 | 21µs | 1 | 5µs | # spent 5µs within Foswiki::Store::Interfaces::QueryAlgorithm::BEGIN@19 which was called:
# once (5µs+0s) by Foswiki::Store::QueryAlgorithms::BruteForce::BEGIN@29 at line 19 # spent 5µs making 1 call to Foswiki::Store::Interfaces::QueryAlgorithm::BEGIN@19 |
20 | 2 | 96µs | 1 | 522µs | # spent 522µs (437+85) within Foswiki::Store::Interfaces::QueryAlgorithm::BEGIN@20 which was called:
# once (437µs+85µs) by Foswiki::Store::QueryAlgorithms::BruteForce::BEGIN@29 at line 20 # spent 522µs making 1 call to Foswiki::Store::Interfaces::QueryAlgorithm::BEGIN@20 |
21 | 2 | 44µs | 1 | 5µs | # spent 5µs within Foswiki::Store::Interfaces::QueryAlgorithm::BEGIN@21 which was called:
# once (5µs+0s) by Foswiki::Store::QueryAlgorithms::BruteForce::BEGIN@29 at line 21 # spent 5µs making 1 call to Foswiki::Store::Interfaces::QueryAlgorithm::BEGIN@21 |
22 | |||||
23 | # spent 5µs within Foswiki::Store::Interfaces::QueryAlgorithm::BEGIN@23 which was called:
# once (5µs+0s) by Foswiki::Store::QueryAlgorithms::BruteForce::BEGIN@29 at line 28 | ||||
24 | 1 | 5µs | if ( $Foswiki::cfg{UseLocale} ) { | ||
25 | require locale; | ||||
26 | import locale(); | ||||
27 | } | ||||
28 | 1 | 23µs | 1 | 5µs | } # spent 5µs making 1 call to Foswiki::Store::Interfaces::QueryAlgorithm::BEGIN@23 |
29 | |||||
30 | 2 | 1.06ms | 2 | 75µs | # spent 42µs (9+33) within Foswiki::Store::Interfaces::QueryAlgorithm::BEGIN@30 which was called:
# once (9µs+33µs) by Foswiki::Store::QueryAlgorithms::BruteForce::BEGIN@29 at line 30 # spent 42µs making 1 call to Foswiki::Store::Interfaces::QueryAlgorithm::BEGIN@30
# spent 33µs making 1 call to constant::import |
31 | |||||
32 | =begin TML | ||||
33 | |||||
34 | ---+ package Foswiki::Store::Interfaces::QueryAlgorithm | ||||
35 | |||||
36 | Interface to query algorithms. | ||||
37 | Implementations of this interface are found in Foswiki/Store/*Algorithms. | ||||
38 | |||||
39 | The contract with query algorithms is specified by this interface description, | ||||
40 | plus the 'query' unit tests in Fn_SEARCH. | ||||
41 | The interface provides a default implementation of the 'getField' method, | ||||
42 | but all other methods are pure virtual and must be provided by subclasses. | ||||
43 | Note that if a subclass re-implements getField, then there is no direct | ||||
44 | need to inherit from this class (as long as all the methods are implemented). | ||||
45 | |||||
46 | =cut | ||||
47 | |||||
48 | =begin TML | ||||
49 | |||||
50 | ---++ ClassMethod new( $class, ) -> $cereal | ||||
51 | |||||
52 | =cut | ||||
53 | |||||
54 | # spent 17µs within Foswiki::Store::Interfaces::QueryAlgorithm::new which was called 2 times, avg 8µs/call:
# once (9µs+0s) by Foswiki::Store::QueryAlgorithms::BruteForce::new at line 62 of /var/www/foswikidev/core/lib/Foswiki/Store/QueryAlgorithms/BruteForce.pm
# once (8µs+0s) by Foswiki::Store::SearchAlgorithms::Forking::new at line 50 of /var/www/foswikidev/core/lib/Foswiki/Store/SearchAlgorithms/Forking.pm | ||||
55 | 2 | 1µs | my $class = shift; | ||
56 | 2 | 13µs | my $this = bless( {}, $class ); | ||
57 | 2 | 12µs | return $this; | ||
58 | } | ||||
59 | |||||
60 | =begin TML | ||||
61 | |||||
62 | ---++ ObjectMethod query( $query, $webs, $inputTopicSet, $session, $options ) -> $infoCache | ||||
63 | * =$query= - A Foswiki::Query::Node object | ||||
64 | * =$web= - name of the web being searched, or may be an array reference | ||||
65 | to a set of webs to search | ||||
66 | * =$inputTopicSet= - iterator over names of topics in that web to search | ||||
67 | * =$session= - reference to the store object | ||||
68 | * =$options= - hash of requested options | ||||
69 | This is the top-level interface to a query algorithm. A store module can call | ||||
70 | this method to start the 'hard work' query process. That process will call | ||||
71 | back to the =getField= method in this module to evaluate leaf data in the | ||||
72 | store. | ||||
73 | |||||
74 | To monitor the hoisting and evaluation processes, use the MONITOR_EVAL | ||||
75 | setting in Foswiki::Query::Node | ||||
76 | |||||
77 | this is a default implementation of the query() sub that uses the specific algorithms' _webQuery member function. | ||||
78 | |||||
79 | =cut | ||||
80 | |||||
81 | # spent 108s (8.89ms+108) within Foswiki::Store::Interfaces::QueryAlgorithm::query which was called 80 times, avg 1.35s/call:
# 80 times (8.89ms+108s) by Foswiki::Store::Rcs::Store::query at line 666 of /var/www/foswikidev/core/lib/Foswiki/Store/Rcs/Store.pm, avg 1.35s/call | ||||
82 | 80 | 73µs | my ( $this, $query, $inputTopicSet, $session, $options ) = @_; | ||
83 | |||||
84 | 80 | 265µs | 80 | 289µs | if ( $query->isEmpty() ) # spent 150µs making 40 calls to Foswiki::Search::Node::isEmpty, avg 4µs/call
# spent 139µs making 40 calls to Foswiki::Query::Node::isEmpty, avg 3µs/call |
85 | { #TODO: does this do anything in a type=query context? | ||||
86 | #Note: Must return an empty results set, including pager, to avoid crash. Item13383 | ||||
87 | my $resultset = | ||||
88 | new Foswiki::Search::ResultSet( [], $options->{groupby}, | ||||
89 | $options->{order}, Foswiki::isTrue( $options->{reverse} ) ); | ||||
90 | return $this->addPager( $resultset, $options ); | ||||
91 | } | ||||
92 | |||||
93 | 80 | 107µs | my $date = $options->{'date'} || ''; | ||
94 | |||||
95 | # Fold constants | ||||
96 | 80 | 218µs | 80 | 786µs | my $context = Foswiki::Meta->new( $session, $session->{webName} ); # spent 786µs making 80 calls to Foswiki::Meta::new, avg 10µs/call |
97 | print STDERR "--- before: " . $query->stringify() . "\n" if MONITOR; | ||||
98 | 80 | 294µs | 80 | 3.80ms | $query->simplify( tom => $context, data => $context ); # spent 3.69ms making 40 calls to Foswiki::Query::Node::simplify, avg 92µs/call
# spent 108µs making 40 calls to Foswiki::Search::Node::simplify, avg 3µs/call |
99 | print STDERR "--- simplified: " . $query->stringify() . "\n" if MONITOR; | ||||
100 | |||||
101 | 80 | 212µs | 80 | 8.41ms | my $webItr = $this->getWebIterator( $session, $options ); # spent 8.41ms making 80 calls to Foswiki::Store::Interfaces::QueryAlgorithm::getWebIterator, avg 105µs/call |
102 | |||||
103 | #do the search | ||||
104 | my $queryItr = Foswiki::Iterator::ProcessIterator->new( | ||||
105 | $webItr, | ||||
106 | # spent 157s (925µs+157) within Foswiki::Store::Interfaces::QueryAlgorithm::__ANON__[/var/www/foswikidev/core/lib/Foswiki/Store/Interfaces/QueryAlgorithm.pm:119] which was called 80 times, avg 1.97s/call:
# 80 times (925µs+157s) by Foswiki::Iterator::ProcessIterator::next at line 58 of /var/www/foswikidev/core/lib/Foswiki/Iterator/ProcessIterator.pm, avg 1.97s/call | ||||
107 | 80 | 31µs | my $web = shift; | ||
108 | 80 | 19µs | my $params = shift; | ||
109 | |||||
110 | 80 | 293µs | 80 | 157s | my $infoCache = # spent 108s making 40 calls to Foswiki::Store::QueryAlgorithms::BruteForce::_webQuery, avg 2.70s/call
# spent 49.1s making 40 calls to Foswiki::Store::SearchAlgorithms::Forking::_webQuery, avg 1.23s/call |
111 | $this->_webQuery( $params->{query}, $web, $params->{inputset}, | ||||
112 | $params->{session}, $params->{options} ); | ||||
113 | |||||
114 | 80 | 42µs | if ($date) { | ||
115 | $infoCache->filterByDate($date); | ||||
116 | } | ||||
117 | |||||
118 | 80 | 506µs | return $infoCache; | ||
119 | }, | ||||
120 | { | ||||
121 | 80 | 739µs | 80 | 465µs | query => $query, # spent 465µs making 80 calls to Foswiki::Iterator::ProcessIterator::new, avg 6µs/call |
122 | inputset => $inputTopicSet, | ||||
123 | session => $session, | ||||
124 | options => $options | ||||
125 | } | ||||
126 | ); | ||||
127 | |||||
128 | #sadly, the resultSet currently wants a real array, rather than an unevaluated web iterator | ||||
129 | 80 | 293µs | 80 | 108s | my @resultCacheList = $queryItr->all(); # spent 157s making 80 calls to Foswiki::Iterator::ProcessIterator::all, avg 1.97s/call, recursion: max depth 1, sum of overlapping time 49.1s |
130 | |||||
131 | #and thus if the ResultSet could be created using an unevaluated process itr, which would somehow rely on........ eeeeek | ||||
132 | 80 | 1.69ms | 160 | 2.21ms | my $resultset = # spent 1.53ms making 80 calls to Foswiki::Search::ResultSet::new, avg 19µs/call
# spent 681µs making 80 calls to Foswiki::isTrue, avg 9µs/call |
133 | new Foswiki::Search::ResultSet( \@resultCacheList, $options->{groupby}, | ||||
134 | $options->{order}, Foswiki::isTrue( $options->{reverse} ) ); | ||||
135 | |||||
136 | #add permissions check | ||||
137 | 80 | 484µs | 80 | 3.12ms | $resultset = $this->addACLFilter( $resultset, $options ); # spent 3.12ms making 80 calls to Foswiki::Store::Interfaces::QueryAlgorithm::addACLFilter, avg 39µs/call |
138 | |||||
139 | #sort as late as possible | ||||
140 | 80 | 311µs | 80 | 182ms | $resultset->sortResults($options); # spent 182ms making 80 calls to Foswiki::Iterator::FilterIterator::sortResults, avg 2.28ms/call |
141 | |||||
142 | #add paging if applicable. | ||||
143 | 80 | 3.75ms | 80 | 503µs | $this->addPager( $resultset, $options ); # spent 503µs making 80 calls to Foswiki::Store::Interfaces::QueryAlgorithm::addPager, avg 6µs/call |
144 | } | ||||
145 | |||||
146 | # spent 503µs within Foswiki::Store::Interfaces::QueryAlgorithm::addPager which was called 80 times, avg 6µs/call:
# 80 times (503µs+0s) by Foswiki::Store::Interfaces::QueryAlgorithm::query at line 143, avg 6µs/call | ||||
147 | 80 | 70µs | my $this = shift; | ||
148 | 80 | 29µs | my $resultset = shift; | ||
149 | 80 | 29µs | my $options = shift; | ||
150 | |||||
151 | 80 | 100µs | if ( $options->{paging_on} ) { | ||
152 | $resultset = | ||||
153 | new Foswiki::Iterator::PagerIterator( $resultset, | ||||
154 | $options->{pagesize}, $options->{showpage} ); | ||||
155 | } | ||||
156 | |||||
157 | 80 | 321µs | return $resultset; | ||
158 | } | ||||
159 | |||||
160 | # spent 3.12ms (2.06+1.05) within Foswiki::Store::Interfaces::QueryAlgorithm::addACLFilter which was called 80 times, avg 39µs/call:
# 80 times (2.06ms+1.05ms) by Foswiki::Store::Interfaces::QueryAlgorithm::query at line 137, avg 39µs/call | ||||
161 | 80 | 47µs | my $this = shift; | ||
162 | 80 | 18µs | my $resultset = shift; | ||
163 | 80 | 26µs | my $options = shift; | ||
164 | |||||
165 | #add filtering for ACL test - probably should make it a seperate filter | ||||
166 | $resultset = new Foswiki::Iterator::FilterIterator( | ||||
167 | $resultset, | ||||
168 | # spent 53.9s (806ms+53.1) within Foswiki::Store::Interfaces::QueryAlgorithm::__ANON__[/var/www/foswikidev/core/lib/Foswiki/Store/Interfaces/QueryAlgorithm.pm:194] which was called 17520 times, avg 3.08ms/call:
# 17520 times (806ms+53.1s) by Foswiki::Iterator::FilterIterator::hasNext at line 73 of /var/www/foswikidev/core/lib/Foswiki/Iterator/FilterIterator.pm, avg 3.08ms/call | ||||
169 | 17520 | 3.90ms | my $listItem = shift; | ||
170 | 17520 | 2.59ms | my $params = shift; | ||
171 | |||||
172 | #ACL test | ||||
173 | 17520 | 26.6ms | 17520 | 251ms | my ( $web, $topic ) = # spent 251ms making 17520 calls to Foswiki::Func::normalizeWebTopicName, avg 14µs/call |
174 | Foswiki::Func::normalizeWebTopicName( '', $listItem ); | ||||
175 | |||||
176 | 17520 | 60.7ms | 52560 | 52.1s | my $topicMeta = # spent 52.1s making 17520 calls to Foswiki::MetaCache::addMeta, avg 2.97ms/call
# spent 29.7ms making 17520 calls to Foswiki::search, avg 2µs/call
# spent 25.5ms making 17520 calls to Foswiki::Search::metacache, avg 1µs/call |
177 | $Foswiki::Plugins::SESSION->search->metacache->addMeta( $web, | ||||
178 | $topic ); | ||||
179 | 17520 | 2.08ms | if ( not defined($topicMeta) ) { | ||
180 | |||||
181 | #TODO: OMG! Search.pm relies on Meta::load (in the metacache) returning a meta object even when the topic does not exist. | ||||
182 | #lets change that | ||||
183 | $topicMeta = | ||||
184 | new Foswiki::Meta( $Foswiki::Plugins::SESSION, $web, $topic ); | ||||
185 | } | ||||
186 | 17520 | 59.7ms | 52560 | 734ms | my $info = # spent 680ms making 17520 calls to Foswiki::MetaCache::get, avg 39µs/call
# spent 29.4ms making 17520 calls to Foswiki::search, avg 2µs/call
# spent 24.1ms making 17520 calls to Foswiki::Search::metacache, avg 1µs/call |
187 | $Foswiki::Plugins::SESSION->search->metacache->get( $web, $topic, | ||||
188 | $topicMeta ); | ||||
189 | ##ASSERT( defined( $info->{tom} ) ) if DEBUG; | ||||
190 | |||||
191 | # Check security (don't show topics the current user does not have permission to view) | ||||
192 | 17520 | 7.46ms | return 0 unless ( $info->{allowView} ); | ||
193 | 17520 | 550ms | return 1; | ||
194 | }, | ||||
195 | 80 | 1.92ms | 80 | 1.05ms | $options # spent 1.05ms making 80 calls to Foswiki::Iterator::FilterIterator::new, avg 13µs/call |
196 | ); | ||||
197 | } | ||||
198 | |||||
199 | # spent 8.41ms (2.40+6.01) within Foswiki::Store::Interfaces::QueryAlgorithm::getWebIterator which was called 80 times, avg 105µs/call:
# 80 times (2.40ms+6.01ms) by Foswiki::Store::Interfaces::QueryAlgorithm::query at line 101, avg 105µs/call | ||||
200 | 80 | 28µs | my $this = shift; | ||
201 | 80 | 26µs | my $session = shift; | ||
202 | 80 | 17µs | my $options = shift; | ||
203 | |||||
204 | 80 | 60µs | my $webNames = $options->{web} || ''; | ||
205 | 80 | 64µs | my $recurse = $options->{'recurse'} || ''; | ||
206 | 80 | 336µs | 80 | 432µs | my $isAdmin = $session->{users}->isAdmin( $session->{user} ); # spent 432µs making 80 calls to Foswiki::Users::isAdmin, avg 5µs/call |
207 | |||||
208 | #get a complete list of webs to search | ||||
209 | 80 | 224µs | my $searchAllFlag = ( $webNames =~ m/(^|[\,\s])(all|on)([\,\s]|$)/i ); | ||
210 | 80 | 305µs | 80 | 4.55ms | my @webs = # spent 4.55ms making 80 calls to Foswiki::Store::Interfaces::QueryAlgorithm::getListOfWebs, avg 57µs/call |
211 | Foswiki::Store::Interfaces::QueryAlgorithm::getListOfWebs( $webNames, | ||||
212 | $recurse, $searchAllFlag ); | ||||
213 | 80 | 358µs | 80 | 548µs | my $rawWebIter = new Foswiki::ListIterator( \@webs ); # spent 548µs making 80 calls to Foswiki::ListIterator::new, avg 7µs/call |
214 | my $webItr = new Foswiki::Iterator::FilterIterator( | ||||
215 | $rawWebIter, | ||||
216 | # spent 15.0ms (1.57+13.4) within Foswiki::Store::Interfaces::QueryAlgorithm::__ANON__[/var/www/foswikidev/core/lib/Foswiki/Store/Interfaces/QueryAlgorithm.pm:235] which was called 80 times, avg 187µs/call:
# 80 times (1.57ms+13.4ms) by Foswiki::Iterator::FilterIterator::hasNext at line 73 of /var/www/foswikidev/core/lib/Foswiki/Iterator/FilterIterator.pm, avg 187µs/call | ||||
217 | 80 | 25µs | my $web = shift; | ||
218 | 80 | 17µs | my $params = shift; | ||
219 | |||||
220 | # can't process what ain't thar | ||||
221 | 80 | 280µs | 80 | 5.88ms | return 0 unless $session->webExists($web); # spent 5.88ms making 80 calls to Foswiki::webExists, avg 74µs/call |
222 | |||||
223 | 80 | 245µs | 80 | 863µs | my $webObject = Foswiki::Meta->new( $session, $web ); # spent 863µs making 80 calls to Foswiki::Meta::new, avg 11µs/call |
224 | 80 | 310µs | 160 | 6.64ms | my $thisWebNoSearchAll = # spent 5.92ms making 80 calls to Foswiki::Meta::getPreference, avg 74µs/call
# spent 721µs making 80 calls to Foswiki::isTrue, avg 9µs/call |
225 | Foswiki::isTrue( $webObject->getPreference('NOSEARCHALL') ); | ||||
226 | |||||
227 | # make sure we can report this web on an 'all' search | ||||
228 | # DON'T filter out unless it's part of an 'all' search. | ||||
229 | 80 | 20µs | return 0 | ||
230 | if ( $searchAllFlag | ||||
231 | && !$isAdmin | ||||
232 | && ( $thisWebNoSearchAll || $web =~ m/^[\.\_]/ ) | ||||
233 | && $web ne $session->{webName} ); | ||||
234 | 80 | 394µs | return 1; | ||
235 | }, | ||||
236 | {} | ||||
237 | 80 | 873µs | 80 | 477µs | ); # spent 477µs making 80 calls to Foswiki::Iterator::FilterIterator::new, avg 6µs/call |
238 | } | ||||
239 | |||||
240 | =begin TML | ||||
241 | |||||
242 | ---++ StaticMethod getField($class, $node, $data, $field ) -> $result | ||||
243 | * =$class= is this package | ||||
244 | * =$node= is the query node | ||||
245 | * =$data= is the indexed object | ||||
246 | * =$field= is the scalar being used to index the object | ||||
247 | =getField= is used by the query evaluation code in Foswiki::Query::Node to get | ||||
248 | information about a leaf node, or 'field'. A field can be a name, or a literal, | ||||
249 | and the information it refers to can be a scalar, a reference to a hash, or | ||||
250 | a reference to an array. The exact interpretation of fields is | ||||
251 | context-dependant, according to reasonably complex rules best documented by | ||||
252 | the Fn_SEARCH unit test and System.QuerySearch. | ||||
253 | |||||
254 | The function must map the query schema to whatever the underlying | ||||
255 | store uses to store a topic. See System.QuerySearch for more information | ||||
256 | on the query schema. | ||||
257 | |||||
258 | =cut | ||||
259 | |||||
260 | # Implements Foswiki::Store::Interfaces::QueryAlgorithm | ||||
261 | # spent 162ms (109+52.5) within Foswiki::Store::Interfaces::QueryAlgorithm::getField which was called 8760 times, avg 18µs/call:
# 8760 times (109ms+52.5ms) by Foswiki::Query::Node::_getField at line 242 of /var/www/foswikidev/core/lib/Foswiki/Query/Node.pm, avg 18µs/call | ||||
262 | |||||
263 | # The getField function allows for Store specific optimisations | ||||
264 | # such as direct database lookups. The default implementation | ||||
265 | # works with the Foswiki::Meta object. | ||||
266 | 8760 | 5.53ms | my ( $this, $node, $data, $field ) = @_; | ||
267 | |||||
268 | 8760 | 1.11ms | my $result; | ||
269 | ASSERT( UNIVERSAL::isa( $data, 'Foswiki::Meta' ) ) if DEBUG; | ||||
270 | |||||
271 | 8760 | 661µs | print STDERR "\n----- getField($field)\n" if MONITOR; | ||
272 | |||||
273 | 8760 | 2.85ms | if ( $field eq 'META:VERSIONS' ) { | ||
274 | |||||
275 | # Disallow reloading versions for an object loaded here | ||||
276 | # SMELL: violates Foswiki::Meta encapsulation | ||||
277 | return [] if $data->{_loadedByQueryAlgorithm}; | ||||
278 | |||||
279 | # Oooh, this is inefficient. | ||||
280 | my $it = $data->getRevisionHistory(); | ||||
281 | my @revs; | ||||
282 | while ( $it->hasNext() ) { | ||||
283 | my $n = $it->next(); | ||||
284 | my $t = | ||||
285 | $this->getRefTopic( $data, $data->web(), $data->topic(), $n ); | ||||
286 | $t->{_loadedByQueryAlgorithm} = 1; | ||||
287 | push( @revs, $t ); | ||||
288 | } | ||||
289 | return \@revs; | ||||
290 | } | ||||
291 | |||||
292 | 8760 | 6.74ms | if ( $field =~ s/^META:// ) { | ||
293 | if ( $field eq 'TOPICINFO' ) { | ||||
294 | |||||
295 | # Ensure the revision info is populated from the store | ||||
296 | $data->getRevisionInfo(); | ||||
297 | } | ||||
298 | |||||
299 | if ( $Foswiki::Query::Node::isArrayType{$field} ) { | ||||
300 | |||||
301 | # Array type, have to use find | ||||
302 | my @e = $data->find($field); | ||||
303 | return \@e; | ||||
304 | } | ||||
305 | return $data->get($field); | ||||
306 | } | ||||
307 | |||||
308 | 8760 | 1.12ms | if ( $field eq 'name' ) { | ||
309 | |||||
310 | # Special accessor to compensate for lack of a topic | ||||
311 | # name anywhere in the saved fields of meta | ||||
312 | return $data->topic(); | ||||
313 | } | ||||
314 | |||||
315 | 8760 | 1.02ms | if ( $field eq 'text' ) { | ||
316 | |||||
317 | # Special accessor to compensate for lack of the topic text | ||||
318 | # name anywhere in the saved fields of meta | ||||
319 | return $data->text(); | ||||
320 | } | ||||
321 | |||||
322 | 8760 | 1.02ms | if ( $field eq 'web' ) { | ||
323 | |||||
324 | # Special accessor to compensate for lack of a web | ||||
325 | # name anywhere in the saved fields of meta | ||||
326 | return $data->web(); | ||||
327 | } | ||||
328 | |||||
329 | 8760 | 1.00ms | if ( $field eq ':topic_meta:' ) { | ||
330 | |||||
331 | #TODO: Sven expects this to be replaced with a fast call to | ||||
332 | # versions[0] - atm, thats needlessly slow | ||||
333 | # return the meta obj itself | ||||
334 | # actually should do this the way the versions feature is | ||||
335 | # supposed to return a particular one.. | ||||
336 | # SMELL: CDot can't work out what this is for.... | ||||
337 | return $data; | ||||
338 | } | ||||
339 | |||||
340 | 8760 | 10.5ms | 8760 | 18.2ms | return undef unless $data->topic(); # spent 18.2ms making 8760 calls to Foswiki::Meta::topic, avg 2µs/call |
341 | |||||
342 | if (MONITOR) { | ||||
343 | print STDERR "----- getField(FIELD value $field)\n"; | ||||
344 | 2 | 768µs | 2 | 68µs | # spent 41µs (14+27) within Foswiki::Store::Interfaces::QueryAlgorithm::BEGIN@344 which was called:
# once (14µs+27µs) by Foswiki::Store::QueryAlgorithms::BruteForce::BEGIN@29 at line 344 # spent 41µs making 1 call to Foswiki::Store::Interfaces::QueryAlgorithm::BEGIN@344
# spent 27µs making 1 call to Exporter::import |
345 | print STDERR Dumper($data) . "\n"; | ||||
346 | } | ||||
347 | |||||
348 | # SHORTCUT; not a predefined name; assume it's a field | ||||
349 | # 'name' instead. | ||||
350 | 8760 | 12.0ms | 8760 | 34.3ms | $result = $data->get( 'FIELD', $field ); # spent 34.3ms making 8760 calls to Foswiki::Meta::get, avg 4µs/call |
351 | 8760 | 6.01ms | $result = $result->{value} if $result; | ||
352 | 8760 | 64.6ms | return $result; | ||
353 | } | ||||
354 | |||||
355 | =begin TML | ||||
356 | |||||
357 | ---++ StaticMethod getForm($class, $node, $data, $field ) -> $result | ||||
358 | * =$class= is this package | ||||
359 | * =$node= is the query node | ||||
360 | * =$data= is the indexed object (must be Foswiki::Meta) | ||||
361 | * =$formname= is the required form name | ||||
362 | |||||
363 | =cut | ||||
364 | |||||
365 | sub getForm { | ||||
366 | my ( $this, $node, $data, $formname ) = @_; | ||||
367 | return undef unless $data->topic(); | ||||
368 | |||||
369 | my $form = $data->get('FORM'); | ||||
370 | return undef unless $form && $formname eq $form->{name}; | ||||
371 | print STDERR "----- getForm($formname)\n" if MONITOR; | ||||
372 | |||||
373 | # TODO: This is where multiple form support needs to reside. | ||||
374 | # Return the array of FIELD for further indexing. | ||||
375 | my @e = $data->find('FIELD'); | ||||
376 | return \@e; | ||||
377 | } | ||||
378 | |||||
379 | =begin TML | ||||
380 | |||||
381 | ---++ StaticMethod getRefTopic($class, $relativeTo, $web, $topic, $rev) -> $topic | ||||
382 | * =$class= is this package | ||||
383 | * =$relativeTo= is a pointer into the data structure of this module where | ||||
384 | the ref is relative to; for example, in the expression | ||||
385 | "other/'Web.Topic'" then =$relativeTo= is =other=. | ||||
386 | * =$web= the web; =Web= in the above example | ||||
387 | * =$topic= the topic; =Topic= in the above example | ||||
388 | * =$rev= optional revision to load | ||||
389 | This method supports the =Foswiki::Query::OP_ref= and =Foswiki::Query::OP_at= | ||||
390 | operators by abstracting the loading of a topic referred to in a string. | ||||
391 | |||||
392 | =cut | ||||
393 | |||||
394 | # Default implements gets a new Foswiki::Meta | ||||
395 | sub getRefTopic { | ||||
396 | |||||
397 | # Get a referenced topic | ||||
398 | my ( $this, $relativeTo, $w, $t, $rev ) = @_; | ||||
399 | my $meta = Foswiki::Meta->load( $relativeTo->session, $w, $t, $rev ); | ||||
400 | print STDERR "----- getRefTopic($w, $t) -> " | ||||
401 | . ( $meta->getLoadedRev() ) . "\n" | ||||
402 | if MONITOR; | ||||
403 | return $meta; | ||||
404 | } | ||||
405 | |||||
406 | =begin TML | ||||
407 | |||||
408 | ---++ StaticMethod getRev1Info($meta) -> %info | ||||
409 | |||||
410 | Return revision info for the first revision in %info with at least: | ||||
411 | * ={date}= in epochSec | ||||
412 | * ={author}= canonical user ID | ||||
413 | * ={version}= the revision number | ||||
414 | |||||
415 | =cut | ||||
416 | |||||
417 | # Default implements gets a new Foswiki::Meta | ||||
418 | sub getRev1Info { | ||||
419 | my $this = shift; | ||||
420 | my $meta = shift; | ||||
421 | |||||
422 | my $wikiname = $meta->getRev1Info('createwikiname'); | ||||
423 | return $meta->{_getRev1Info}->{rev1info}; | ||||
424 | } | ||||
425 | |||||
426 | =begin TML | ||||
427 | |||||
428 | ---+ getListOfWebs($webnames, $recurse, $serachAllFlag) -> @webs | ||||
429 | |||||
430 | Convert a comma separated list of webs into the list we'll process | ||||
431 | TODO: this is part of the Store now, and so should not need to reference | ||||
432 | Meta - it rather uses the store. | ||||
433 | |||||
434 | =cut | ||||
435 | |||||
436 | # spent 4.55ms (2.19+2.36) within Foswiki::Store::Interfaces::QueryAlgorithm::getListOfWebs which was called 80 times, avg 57µs/call:
# 80 times (2.19ms+2.36ms) by Foswiki::Store::Interfaces::QueryAlgorithm::getWebIterator at line 210, avg 57µs/call | ||||
437 | 80 | 109µs | my ( $webName, $recurse, $searchAllFlag ) = @_; | ||
438 | 80 | 31µs | my $session = $Foswiki::Plugins::SESSION; | ||
439 | |||||
440 | 80 | 11µs | my %excludeWeb; | ||
441 | 80 | 18µs | my @tmpWebs; | ||
442 | |||||
443 | #$web = Foswiki::Sandbox::untaint( $web,\&Foswiki::Sandbox::validateWebName ); | ||||
444 | |||||
445 | 80 | 52µs | if ($webName) { | ||
446 | 40 | 109µs | foreach my $web ( split( /[\,\s]+/, $webName ) ) { | ||
447 | 40 | 65µs | $web =~ s#\.#/#g; | ||
448 | |||||
449 | # the web processing loop filters for valid web names, | ||||
450 | # so don't do it here. | ||||
451 | 40 | 72µs | if ( $web =~ s/^-// ) { | ||
452 | $excludeWeb{$web} = 1; | ||||
453 | } | ||||
454 | else { | ||||
455 | 40 | 164µs | 40 | 350µs | if ( $web =~ m/^(all|on)$/i # spent 350µs making 40 calls to Foswiki::isTrue, avg 9µs/call |
456 | || $Foswiki::cfg{EnableHierarchicalWebs} | ||||
457 | && Foswiki::isTrue($recurse) ) | ||||
458 | { | ||||
459 | my $webObject; | ||||
460 | my $prefix = "$web/"; | ||||
461 | if ( $web =~ m/^(all|on)$/i ) { | ||||
462 | $webObject = Foswiki::Meta->new($session); | ||||
463 | $prefix = ''; | ||||
464 | } | ||||
465 | else { | ||||
466 | $web = Foswiki::Sandbox::untaint( $web, | ||||
467 | \&Foswiki::Sandbox::validateWebName ); | ||||
468 | ASSERT($web) if DEBUG; | ||||
469 | push( @tmpWebs, $web ); | ||||
470 | $webObject = Foswiki::Meta->new( $session, $web ); | ||||
471 | } | ||||
472 | my $it = $webObject->eachWeb(1); | ||||
473 | while ( $it->hasNext() ) { | ||||
474 | my $w = $prefix . $it->next(); | ||||
475 | next | ||||
476 | unless Foswiki::WebFilter->user_allowed() | ||||
477 | ->ok( $session, $w ); | ||||
478 | $w = Foswiki::Sandbox::untaint( $w, | ||||
479 | \&Foswiki::Sandbox::validateWebName ); | ||||
480 | ASSERT($web) if DEBUG; | ||||
481 | push( @tmpWebs, $w ); | ||||
482 | } | ||||
483 | } | ||||
484 | else { | ||||
485 | 40 | 104µs | 40 | 605µs | $web = Foswiki::Sandbox::untaint( $web, # spent 605µs making 40 calls to Foswiki::Sandbox::untaint, avg 15µs/call |
486 | \&Foswiki::Sandbox::validateWebName ); | ||||
487 | 40 | 30µs | push( @tmpWebs, $web ); | ||
488 | } | ||||
489 | } | ||||
490 | } | ||||
491 | |||||
492 | } | ||||
493 | else { | ||||
494 | |||||
495 | # default to current web | ||||
496 | 40 | 226µs | 40 | 1.12ms | my $web = # spent 1.12ms making 40 calls to Foswiki::Sandbox::untaint, avg 28µs/call |
497 | Foswiki::Sandbox::untaint( $session->{webName}, | ||||
498 | \&Foswiki::Sandbox::validateWebName ); | ||||
499 | 40 | 38µs | push( @tmpWebs, $web ); | ||
500 | 40 | 61µs | 40 | 283µs | if ( Foswiki::isTrue($recurse) ) { # spent 283µs making 40 calls to Foswiki::isTrue, avg 7µs/call |
501 | require Foswiki::Meta; | ||||
502 | my $webObject = Foswiki::Meta->new( $session, $session->{webName} ); | ||||
503 | my $it = | ||||
504 | $webObject->eachWeb( $Foswiki::cfg{EnableHierarchicalWebs} ); | ||||
505 | while ( $it->hasNext() ) { | ||||
506 | my $w = $session->{webName} . '/' . $it->next(); | ||||
507 | next | ||||
508 | unless Foswiki::WebFilter->user_allowed()->ok( $session, $w ); | ||||
509 | $w = Foswiki::Sandbox::untaint( $w, | ||||
510 | \&Foswiki::Sandbox::validateWebName ); | ||||
511 | push( @tmpWebs, $w ); | ||||
512 | } | ||||
513 | } | ||||
514 | } | ||||
515 | |||||
516 | 80 | 24µs | my @webs; | ||
517 | 80 | 99µs | foreach my $web (@tmpWebs) { | ||
518 | 80 | 14µs | next unless defined $web; | ||
519 | 80 | 108µs | push( @webs, $web ) unless $excludeWeb{$web}; | ||
520 | 80 | 130µs | $excludeWeb{$web} = 1; # eliminate duplicates | ||
521 | } | ||||
522 | |||||
523 | # Default to alphanumeric sort order | ||||
524 | 80 | 484µs | return sort @webs; | ||
525 | } | ||||
526 | |||||
527 | 1 | 2µs | 1; | ||
528 | __END__ |