Filename | /var/www/foswikidev/core/lib/Foswiki/Search/ResultSet.pm |
Statements | Executed 281613 statements in 304ms |
Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
---|---|---|---|---|---|
35120 | 2 | 2 | 239ms | 431ms | hasNext | Foswiki::Search::ResultSet::
17520 | 1 | 1 | 81.6ms | 98.1ms | next | Foswiki::Search::ResultSet::
80 | 1 | 1 | 1.53ms | 1.53ms | new | Foswiki::Search::ResultSet::
80 | 1 | 1 | 1.08ms | 182ms | sortResults | Foswiki::Search::ResultSet::
1 | 1 | 1 | 15µs | 29µs | BEGIN@17 | Foswiki::Search::ResultSet::
1 | 1 | 1 | 10µs | 14µs | BEGIN@18 | Foswiki::Search::ResultSet::
1 | 1 | 1 | 9µs | 35µs | BEGIN@24 | Foswiki::Search::ResultSet::
1 | 1 | 1 | 9µs | 9µs | BEGIN@23 | Foswiki::Search::ResultSet::
1 | 1 | 1 | 4µs | 4µs | BEGIN@20 | Foswiki::Search::ResultSet::
1 | 1 | 1 | 4µs | 4µs | BEGIN@26 | Foswiki::Search::ResultSet::
0 | 0 | 0 | 0s | 0s | filterByDate | Foswiki::Search::ResultSet::
0 | 0 | 0 | 0s | 0s | nextWeb | Foswiki::Search::ResultSet::
0 | 0 | 0 | 0s | 0s | numberOfTopics | Foswiki::Search::ResultSet::
0 | 0 | 0 | 0s | 0s | skip | Foswiki::Search::ResultSet::
Line | State ments |
Time on line |
Calls | Time in subs |
Code |
---|---|---|---|---|---|
1 | # See bottom of file for license and copyright information | ||||
2 | |||||
3 | =begin TML | ||||
4 | |||||
5 | ---+ package Foswiki::Search::ResultSet | ||||
6 | |||||
7 | This class implements the ResultSet API - its basically a Sorted Aggregate Iterator for foswiki 1.1 | ||||
8 | * NOTE: does not implement the unique function - by its nature, the data is unique, and it would be a non-trivial drain on memory in this context | ||||
9 | |||||
10 | (due to the partially completed InfoCache removeal) | ||||
11 | |||||
12 | in future it will probably become more clever. | ||||
13 | |||||
14 | =cut | ||||
15 | |||||
16 | package Foswiki::Search::ResultSet; | ||||
17 | 2 | 28µs | 2 | 42µs | # spent 29µs (15+14) within Foswiki::Search::ResultSet::BEGIN@17 which was called:
# once (15µs+14µs) by Foswiki::Search::BEGIN@20 at line 17 # spent 29µs making 1 call to Foswiki::Search::ResultSet::BEGIN@17
# spent 14µs making 1 call to strict::import |
18 | 2 | 25µs | 2 | 19µs | # spent 14µs (10+4) within Foswiki::Search::ResultSet::BEGIN@18 which was called:
# once (10µs+4µs) by Foswiki::Search::BEGIN@20 at line 18 # spent 14µs making 1 call to Foswiki::Search::ResultSet::BEGIN@18
# spent 4µs making 1 call to warnings::import |
19 | |||||
20 | 2 | 34µs | 1 | 4µs | # spent 4µs within Foswiki::Search::ResultSet::BEGIN@20 which was called:
# once (4µs+0s) by Foswiki::Search::BEGIN@20 at line 20 # spent 4µs making 1 call to Foswiki::Search::ResultSet::BEGIN@20 |
21 | 1 | 7µs | our @ISA = ('Foswiki::Iterator'); | ||
22 | |||||
23 | 2 | 26µs | 1 | 9µs | # spent 9µs within Foswiki::Search::ResultSet::BEGIN@23 which was called:
# once (9µs+0s) by Foswiki::Search::BEGIN@20 at line 23 # spent 9µs making 1 call to Foswiki::Search::ResultSet::BEGIN@23 |
24 | 2 | 53µs | 2 | 61µs | # spent 35µs (9+26) within Foswiki::Search::ResultSet::BEGIN@24 which was called:
# once (9µs+26µs) by Foswiki::Search::BEGIN@20 at line 24 # spent 35µs making 1 call to Foswiki::Search::ResultSet::BEGIN@24
# spent 26µs making 1 call to Exporter::import |
25 | |||||
26 | # spent 4µs within Foswiki::Search::ResultSet::BEGIN@26 which was called:
# once (4µs+0s) by Foswiki::Search::BEGIN@20 at line 31 | ||||
27 | 1 | 5µs | if ( $Foswiki::cfg{UseLocale} ) { | ||
28 | require locale; | ||||
29 | import locale(); | ||||
30 | } | ||||
31 | 1 | 790µs | 1 | 4µs | } # spent 4µs making 1 call to Foswiki::Search::ResultSet::BEGIN@26 |
32 | |||||
33 | =begin TML | ||||
34 | |||||
35 | ---++ new(\@list) | ||||
36 | |||||
37 | Create a new iterator over the given list of iterators. The list is | ||||
38 | not damaged in any way. | ||||
39 | |||||
40 | =cut | ||||
41 | |||||
42 | # spent 1.53ms within Foswiki::Search::ResultSet::new which was called 80 times, avg 19µs/call:
# 80 times (1.53ms+0s) by Foswiki::Store::Interfaces::QueryAlgorithm::query at line 132 of /var/www/foswikidev/core/lib/Foswiki/Store/Interfaces/QueryAlgorithm.pm, avg 19µs/call | ||||
43 | 80 | 254µs | my ( $class, $list, $partition, $sortby, $revSort ) = @_; | ||
44 | |||||
45 | 80 | 940µs | my $this = bless( | ||
46 | { | ||||
47 | Itr_list => $list, | ||||
48 | Itr_index => 0, | ||||
49 | next => undef, | ||||
50 | Itr_next => [], | ||||
51 | partition => $partition || 'web', | ||||
52 | sortby => $sortby || 'topic', | ||||
53 | revsort => $revSort || 0, | ||||
54 | }, | ||||
55 | $class | ||||
56 | ); | ||||
57 | |||||
58 | 80 | 394µs | return $this; | ||
59 | } | ||||
60 | |||||
61 | sub numberOfTopics { | ||||
62 | my $this = shift; | ||||
63 | |||||
64 | return $this->{count} if ( defined( $this->{count} ) ); | ||||
65 | |||||
66 | my $count = 0; | ||||
67 | foreach my $infocache ( @{ $this->{Itr_list} } ) { | ||||
68 | $count += $infocache->numberOfTopics(); | ||||
69 | } | ||||
70 | $this->{count} = $count; | ||||
71 | |||||
72 | return $count; | ||||
73 | } | ||||
74 | |||||
75 | =begin TML | ||||
76 | |||||
77 | ---++ hasNext() -> $boolean | ||||
78 | |||||
79 | Returns false when the iterator is exhausted. | ||||
80 | |||||
81 | =cut | ||||
82 | |||||
83 | # spent 431ms (239+191) within Foswiki::Search::ResultSet::hasNext which was called 35120 times, avg 12µs/call:
# 17600 times (223ms+191ms) by Foswiki::Iterator::FilterIterator::hasNext at line 71 of /var/www/foswikidev/core/lib/Foswiki/Iterator/FilterIterator.pm, avg 24µs/call
# 17520 times (16.5ms+0s) by Foswiki::Search::ResultSet::next at line 235, avg 940ns/call | ||||
84 | 35120 | 11.7ms | my ($this) = @_; | ||
85 | 35120 | 54.3ms | return 1 if $this->{next}; | ||
86 | |||||
87 | #this is the 'normal' legacy way to iterate over the list of results (one web at a time) | ||||
88 | 17600 | 8.34ms | if ( | ||
89 | ( $this->{partition} eq 'web' ) | ||||
90 | or ( | ||||
91 | scalar( @{ $this->{Itr_list} } ) <= 0 | ||||
92 | ) #no reason to got through the more complex case if there's only one itr | ||||
93 | ) | ||||
94 | { | ||||
95 | 17600 | 1.94ms | my $n; | ||
96 | 17600 | 14.8ms | do { | ||
97 | 17680 | 4.73ms | unless ( $this->{list} ) { | ||
98 | if ( $this->{Itr_index} < scalar( @{ $this->{Itr_list} } ) ) { | ||||
99 | $this->{list} = $this->{Itr_list}->[ $this->{Itr_index}++ ]; | ||||
100 | } | ||||
101 | else { | ||||
102 | 80 | 174µs | return 0; #no more iterators in list | ||
103 | } | ||||
104 | } | ||||
105 | 17600 | 48.2ms | 35120 | 191ms | if ( $this->{list}->hasNext() ) { # spent 119ms making 17520 calls to Foswiki::ListIterator::next, avg 7µs/call
# spent 72.7ms making 17600 calls to Foswiki::ListIterator::hasNext, avg 4µs/call |
106 | $n = $this->{list}->next(); | ||||
107 | } | ||||
108 | else { | ||||
109 | 80 | 56µs | $this->{list} = undef; #goto next iterator | ||
110 | } | ||||
111 | } while ( !$this->{list} ); | ||||
112 | 17520 | 6.92ms | $this->{next} = $n; | ||
113 | } | ||||
114 | else { | ||||
115 | |||||
116 | #yes, this is innefficient, for now I'm looking only to get a functioning result. | ||||
117 | my $next = -1; | ||||
118 | for ( my $idx = 0 ; $idx < scalar( @{ $this->{Itr_list} } ) ; $idx++ ) { | ||||
119 | |||||
120 | #load the next element from each of the iterators | ||||
121 | if ( !defined( $this->{Itr_next}[$idx] ) | ||||
122 | and $this->{Itr_list}[$idx]->hasNext() ) | ||||
123 | { | ||||
124 | $this->{Itr_next}[$idx] = $this->{Itr_list}[$idx]->next(); | ||||
125 | } | ||||
126 | if ( defined( $this->{Itr_next}[$idx] ) ) { | ||||
127 | |||||
128 | #find the first one of them (works because each iterator is already sorted.. | ||||
129 | if ( $next == -1 ) { | ||||
130 | $next = $idx; | ||||
131 | next; | ||||
132 | } | ||||
133 | |||||
134 | #print STDERR "------ trying ($idx) ".$this->{Itr_next}[$idx]."\n"; | ||||
135 | #compare $next's elem with $idx's and rotate if needed | ||||
136 | my @two = ( $this->{Itr_next}[$next], $this->{Itr_next}[$idx] ); | ||||
137 | Foswiki::Search::InfoCache::sortTopics( \@two, $this->{sortby}, | ||||
138 | !$this->{revsort} ); | ||||
139 | if ( $two[0] ne $this->{Itr_next}[$next] ) { | ||||
140 | $next = $idx; | ||||
141 | } | ||||
142 | } | ||||
143 | } | ||||
144 | |||||
145 | #print STDERR "---getting result from $next\n"; | ||||
146 | if ( $next == -1 ) { | ||||
147 | return 0; | ||||
148 | } | ||||
149 | else { | ||||
150 | $this->{next} = $this->{Itr_next}[$next]; | ||||
151 | $this->{Itr_next}[$next] = undef; | ||||
152 | } | ||||
153 | |||||
154 | } | ||||
155 | 17520 | 60.2ms | return 1; | ||
156 | } | ||||
157 | |||||
158 | =begin TML | ||||
159 | |||||
160 | ---++ skip(count) -> $countremaining | ||||
161 | |||||
162 | skip X elements (returns 0 if successful, or number of elements remaining to skip if there are not enough elements to skip) | ||||
163 | skip must set up next as though hasNext was called. | ||||
164 | |||||
165 | =cut | ||||
166 | |||||
167 | sub skip { | ||||
168 | my $this = shift; | ||||
169 | my $count = shift; | ||||
170 | |||||
171 | return 0 if ( $count <= 0 ); | ||||
172 | print STDERR | ||||
173 | "--------------------------------------------ResultSet::skip($count)\n" | ||||
174 | if Foswiki::Iterator::MONITOR; | ||||
175 | |||||
176 | #ask CAN skip() for faster path | ||||
177 | if ( | ||||
178 | ( | ||||
179 | ( $this->{partition} eq 'web' ) | ||||
180 | or ( scalar( @{ $this->{Itr_list} } ) == 0 ) | ||||
181 | ) | ||||
182 | and #no reason to got through the more complex case if there's only one itr | ||||
183 | ( $this->{Itr_list}->[0]->can('skip') | ||||
184 | ) #nasty assumption that all the itr's are a similar type (that happens to be true) | ||||
185 | ) | ||||
186 | { | ||||
187 | if ( not defined( $this->{list} ) ) { | ||||
188 | $this->{list} = $this->{Itr_list}->[ $this->{Itr_index}++ ]; | ||||
189 | } | ||||
190 | while ( $count > 0 ) { | ||||
191 | return $count if ( not defined( $this->{list} ) ); | ||||
192 | $count = $this->{list}->skip($count); | ||||
193 | $this->{next} = $this->{list}->{next}; | ||||
194 | if ( $count > 0 ) { | ||||
195 | $this->{list} = $this->{Itr_list}->[ $this->{Itr_index}++ ]; | ||||
196 | $this->{next} = undef; | ||||
197 | } | ||||
198 | } | ||||
199 | } | ||||
200 | else { | ||||
201 | |||||
202 | #brute force - | ||||
203 | while ( | ||||
204 | ( $count > 0 | ||||
205 | ) #must come first - don't want to advance the inner itr if count ==0 | ||||
206 | and $this->hasNext() | ||||
207 | ) | ||||
208 | { | ||||
209 | $count--; | ||||
210 | $this->next(); #drain next, so hasNext goes to next element | ||||
211 | } | ||||
212 | } | ||||
213 | |||||
214 | if ( $count >= 0 ) { | ||||
215 | |||||
216 | #skipped past the end of the set | ||||
217 | $this->{next} = undef; | ||||
218 | } | ||||
219 | print STDERR | ||||
220 | "--------------------------------------------ResultSet::skip() => $count\n" | ||||
221 | if Foswiki::Iterator::MONITOR; | ||||
222 | return $count; | ||||
223 | } | ||||
224 | |||||
225 | =begin TML | ||||
226 | |||||
227 | ---++ next() -> $data | ||||
228 | |||||
229 | Return the next entry in the list. | ||||
230 | |||||
231 | =cut | ||||
232 | |||||
233 | # spent 98.1ms (81.6+16.5) within Foswiki::Search::ResultSet::next which was called 17520 times, avg 6µs/call:
# 17520 times (81.6ms+16.5ms) by Foswiki::Iterator::FilterIterator::hasNext at line 72 of /var/www/foswikidev/core/lib/Foswiki/Iterator/FilterIterator.pm, avg 6µs/call | ||||
234 | 17520 | 3.48ms | my $this = shift; | ||
235 | 17520 | 12.3ms | 17520 | 16.5ms | $this->hasNext(); # spent 16.5ms making 17520 calls to Foswiki::Search::ResultSet::hasNext, avg 940ns/call |
236 | 17520 | 5.45ms | my $n = $this->{next}; | ||
237 | 17520 | 3.92ms | $this->{next} = undef; | ||
238 | |||||
239 | 17520 | 64.2ms | return $n; | ||
240 | } | ||||
241 | |||||
242 | =begin TML | ||||
243 | |||||
244 | ---++ nextWeb() -> $data | ||||
245 | |||||
246 | switch tot he next Web (only works on partition==web, and if we've already started iterating. | ||||
247 | =cut | ||||
248 | |||||
249 | sub nextWeb { | ||||
250 | my $this = shift; | ||||
251 | |||||
252 | ASSERT( $this->{partition} eq 'web' ) if DEBUG; | ||||
253 | ASSERT( $this->{list} ) if DEBUG; | ||||
254 | |||||
255 | $this->{list} = undef; | ||||
256 | $this->hasNext(); | ||||
257 | } | ||||
258 | |||||
259 | =begin TML | ||||
260 | ---++ sortResults | ||||
261 | |||||
262 | the implementation of %SORT{"" limit="" order="" reverse="" date=""}% | ||||
263 | |||||
264 | it should be possible for the search engine to pre-sort, making this a nop, or to | ||||
265 | delay evaluated, partially evaluated, or even delegated to the DB/SQL | ||||
266 | |||||
267 | =cut | ||||
268 | |||||
269 | # spent 182ms (1.08+181) within Foswiki::Search::ResultSet::sortResults which was called 80 times, avg 2.27ms/call:
# 80 times (1.08ms+181ms) by Foswiki::Iterator::FilterIterator::sortResults at line 64 of /var/www/foswikidev/core/lib/Foswiki/Iterator/FilterIterator.pm, avg 2.27ms/call | ||||
270 | 80 | 86µs | my ( $this, $params ) = @_; | ||
271 | |||||
272 | 80 | 473µs | foreach my $infocache ( @{ $this->{Itr_list} } ) { | ||
273 | 80 | 404µs | 80 | 181ms | $infocache->sortResults($params); # spent 181ms making 80 calls to Foswiki::Search::InfoCache::sortResults, avg 2.26ms/call |
274 | } | ||||
275 | } | ||||
276 | |||||
277 | sub filterByDate { | ||||
278 | my ( $this, $date ) = @_; | ||||
279 | |||||
280 | foreach my $infocache ( @{ $this->{Itr_list} } ) { | ||||
281 | $infocache->filterByDate($date); | ||||
282 | } | ||||
283 | } | ||||
284 | |||||
285 | 1 | 3µs | 1; | ||
286 | __END__ |