Filename | /var/www/foswikidev/core/lib/Foswiki/MetaCache.pm |
Statements | Executed 1272669 statements in 1.68s |
Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
---|---|---|---|---|---|
61320 | 4 | 4 | 1.39s | 78.8s | addMeta | Foswiki::MetaCache::
26280 | 2 | 2 | 382ms | 1.03s | get | Foswiki::MetaCache::
96363 | 4 | 1 | 162ms | 162ms | current_user | Foswiki::MetaCache::
8760 | 1 | 1 | 58.0ms | 73.0ms | getMeta | Foswiki::MetaCache::
1 | 1 | 1 | 6.03ms | 6.03ms | finish | Foswiki::MetaCache::
3 | 1 | 1 | 28µs | 35µs | removeMeta | Foswiki::MetaCache::
1 | 1 | 1 | 13µs | 26µs | BEGIN@3 | Foswiki::MetaCache::
1 | 1 | 1 | 11µs | 29µs | BEGIN@21 | Foswiki::MetaCache::
1 | 1 | 1 | 9µs | 33µs | BEGIN@20 | Foswiki::MetaCache::
1 | 1 | 1 | 9µs | 42µs | BEGIN@29 | Foswiki::MetaCache::
1 | 1 | 1 | 8µs | 8µs | new | Foswiki::MetaCache::
1 | 1 | 1 | 8µs | 12µs | BEGIN@4 | Foswiki::MetaCache::
1 | 1 | 1 | 4µs | 4µs | BEGIN@22 | Foswiki::MetaCache::
1 | 1 | 1 | 4µs | 4µs | BEGIN@31 | Foswiki::MetaCache::
1 | 1 | 1 | 3µs | 3µs | BEGIN@24 | Foswiki::MetaCache::
1 | 1 | 1 | 3µs | 3µs | BEGIN@23 | Foswiki::MetaCache::
0 | 0 | 0 | 0s | 0s | DISABLED_insert | Foswiki::MetaCache::
0 | 0 | 0 | 0s | 0s | DISABLED_remove | Foswiki::MetaCache::
0 | 0 | 0 | 0s | 0s | DISABLED_update | Foswiki::MetaCache::
0 | 0 | 0 | 0s | 0s | hasCached | Foswiki::MetaCache::
Line | State ments |
Time on line |
Calls | Time in subs |
Code |
---|---|---|---|---|---|
1 | # See bottom of file for license and copyright information | ||||
2 | package Foswiki::MetaCache; | ||||
3 | 2 | 26µs | 2 | 38µs | # spent 26µs (13+13) within Foswiki::MetaCache::BEGIN@3 which was called:
# once (13µs+13µs) by Foswiki::Search::BEGIN@26 at line 3 # spent 26µs making 1 call to Foswiki::MetaCache::BEGIN@3
# spent 13µs making 1 call to strict::import |
4 | 2 | 35µs | 2 | 16µs | # spent 12µs (8+4) within Foswiki::MetaCache::BEGIN@4 which was called:
# once (8µs+4µs) by Foswiki::Search::BEGIN@26 at line 4 # spent 12µs making 1 call to Foswiki::MetaCache::BEGIN@4
# spent 4µs making 1 call to warnings::import |
5 | |||||
6 | =begin TML | ||||
7 | |||||
8 | ---+ package Foswiki::MetaCache | ||||
9 | |||||
10 | A cache of Meta objects - initially used to speed up searching and sorting, but by foswiki 2.0 hopefully this | ||||
11 | will be used for all readonly accesses to the store. | ||||
12 | |||||
13 | Replaces the mishmash of the Search InfoCache Support package; cache of topic info. | ||||
14 | When information about search hits is | ||||
15 | compiled for output, this cache is used to avoid recovering the same info | ||||
16 | about the same topic more than once. | ||||
17 | |||||
18 | =cut | ||||
19 | |||||
20 | 2 | 27µs | 2 | 57µs | # spent 33µs (9+24) within Foswiki::MetaCache::BEGIN@20 which was called:
# once (9µs+24µs) by Foswiki::Search::BEGIN@26 at line 20 # spent 33µs making 1 call to Foswiki::MetaCache::BEGIN@20
# spent 24µs making 1 call to Exporter::import |
21 | 2 | 25µs | 2 | 48µs | # spent 29µs (11+19) within Foswiki::MetaCache::BEGIN@21 which was called:
# once (11µs+19µs) by Foswiki::Search::BEGIN@26 at line 21 # spent 29µs making 1 call to Foswiki::MetaCache::BEGIN@21
# spent 19µs making 1 call to Exporter::import |
22 | 2 | 18µs | 1 | 4µs | # spent 4µs within Foswiki::MetaCache::BEGIN@22 which was called:
# once (4µs+0s) by Foswiki::Search::BEGIN@26 at line 22 # spent 4µs making 1 call to Foswiki::MetaCache::BEGIN@22 |
23 | 2 | 17µs | 1 | 3µs | # spent 3µs within Foswiki::MetaCache::BEGIN@23 which was called:
# once (3µs+0s) by Foswiki::Search::BEGIN@26 at line 23 # spent 3µs making 1 call to Foswiki::MetaCache::BEGIN@23 |
24 | 2 | 23µs | 1 | 3µs | # spent 3µs within Foswiki::MetaCache::BEGIN@24 which was called:
# once (3µs+0s) by Foswiki::Search::BEGIN@26 at line 24 # spent 3µs making 1 call to Foswiki::MetaCache::BEGIN@24 |
25 | |||||
26 | #use Monitor (); | ||||
27 | #Monitor::MonitorMethod('Foswiki::MetaCache', 'getTopicListIterator'); | ||||
28 | |||||
29 | 2 | 47µs | 2 | 74µs | # spent 42µs (9+33) within Foswiki::MetaCache::BEGIN@29 which was called:
# once (9µs+33µs) by Foswiki::Search::BEGIN@26 at line 29 # spent 42µs making 1 call to Foswiki::MetaCache::BEGIN@29
# spent 33µs making 1 call to constant::import |
30 | |||||
31 | # spent 4µs within Foswiki::MetaCache::BEGIN@31 which was called:
# once (4µs+0s) by Foswiki::Search::BEGIN@26 at line 36 | ||||
32 | 1 | 8µs | if ( $Foswiki::cfg{UseLocale} ) { | ||
33 | require locale; | ||||
34 | import locale(); | ||||
35 | } | ||||
36 | 1 | 1.02ms | 1 | 4µs | } # spent 4µs making 1 call to Foswiki::MetaCache::BEGIN@31 |
37 | |||||
38 | =begin TML | ||||
39 | |||||
40 | ---++ ClassMethod new($session) | ||||
41 | |||||
42 | =cut | ||||
43 | |||||
44 | # spent 8µs within Foswiki::MetaCache::new which was called:
# once (8µs+0s) by Foswiki::Search::metacache at line 94 of /var/www/foswikidev/core/lib/Foswiki/Search.pm | ||||
45 | 1 | 700ns | my ( $class, $session ) = @_; | ||
46 | |||||
47 | #my $this = $class->SUPER::new([]); | ||||
48 | 1 | 6µs | my $this = bless( | ||
49 | { | ||||
50 | session => $session, | ||||
51 | cache => {}, | ||||
52 | new_count => 0, | ||||
53 | get_count => 0, | ||||
54 | undef_count => 0, | ||||
55 | meta_cache_session_user => $session->{user}, | ||||
56 | }, | ||||
57 | $class | ||||
58 | ); | ||||
59 | |||||
60 | 1 | 3µs | return $this; | ||
61 | } | ||||
62 | |||||
63 | #need to delete from cache if the store saves / updates it :/ | ||||
64 | #otherwise the Meta::load thing is busted. | ||||
65 | |||||
66 | =begin TML | ||||
67 | |||||
68 | ---++ ObjectMethod finish() | ||||
69 | Break circular references. | ||||
70 | |||||
71 | Note to developers; please undef *all* fields in the object explicitly, | ||||
72 | whether they are references or not. That way this method is "golden | ||||
73 | documentation" of the live fields in the object. | ||||
74 | |||||
75 | =cut | ||||
76 | |||||
77 | # spent 6.03ms within Foswiki::MetaCache::finish which was called:
# once (6.03ms+0s) by Foswiki::Search::finish at line 78 of /var/www/foswikidev/core/lib/Foswiki/Search.pm | ||||
78 | 1 | 400ns | my $this = shift; | ||
79 | 1 | 1µs | undef $this->{session}; | ||
80 | |||||
81 | #must clear cache every request until the cache is hooked up to Store's save | ||||
82 | 1 | 5µs | foreach my $cuid ( keys( %{ $this->{cache} } ) ) { | ||
83 | 1 | 2µs | foreach my $web ( keys( %{ $this->{cache}->{$cuid} } ) ) { | ||
84 | 1 | 427µs | foreach my $topic ( keys( %{ $this->{cache}->{$cuid}->{$web} } ) ) { | ||
85 | 219 | 5.44ms | undef $this->{cache}->{$cuid}{$web}{$topic}; | ||
86 | 219 | 77µs | $this->{undef_count}++; | ||
87 | } | ||||
88 | 1 | 64µs | undef $this->{cache}->{$cuid}{$web}; | ||
89 | } | ||||
90 | 1 | 2µs | undef $this->{cache}->{$cuid}; | ||
91 | } | ||||
92 | 1 | 700ns | undef $this->{cache}; | ||
93 | |||||
94 | if (TRACE) { | ||||
95 | print STDERR | ||||
96 | "MetaCache: new: $this->{new_count} get: $this->{get_count} undef: $this->{undef_count} \n"; | ||||
97 | } | ||||
98 | |||||
99 | 1 | 11µs | return; | ||
100 | } | ||||
101 | |||||
102 | =begin TML | ||||
103 | |||||
104 | ---++ ObjectMethod hasCached($webtopic) -> boolean | ||||
105 | |||||
106 | returns true if the topic is already int he cache. | ||||
107 | |||||
108 | =cut | ||||
109 | |||||
110 | sub hasCached { | ||||
111 | my ( $this, $web, $topic ) = @_; | ||||
112 | ASSERT( defined($topic) ) if DEBUG; | ||||
113 | return unless ( defined($topic) ); | ||||
114 | |||||
115 | return ( $this->{session}->{user} | ||||
116 | and | ||||
117 | defined( $this->{cache}->{ $this->current_user() }{$web}{$topic} ) ); | ||||
118 | } | ||||
119 | |||||
120 | # spent 35µs (28+7) within Foswiki::MetaCache::removeMeta which was called 3 times, avg 12µs/call:
# 3 times (28µs+7µs) by Foswiki::Meta::unload at line 504 of /var/www/foswikidev/core/lib/Foswiki/Meta.pm, avg 12µs/call | ||||
121 | 3 | 4µs | my ( $this, $web, $topic ) = @_; | ||
122 | 3 | 5µs | 3 | 7µs | my $user = $this->current_user(); # spent 7µs making 3 calls to Foswiki::MetaCache::current_user, avg 2µs/call |
123 | |||||
124 | 3 | 1µs | if ( defined($topic) ) { | ||
125 | 3 | 6µs | my $cached_userwebtopic = $this->{cache}->{$user}{$web}{$topic}; | ||
126 | |||||
127 | 3 | 1µs | if ($cached_userwebtopic) { | ||
128 | $cached_userwebtopic->finish() if blessed($cached_userwebtopic); | ||||
129 | delete $this->{cache}->{$user}{$web}{$topic}; | ||||
130 | } | ||||
131 | } | ||||
132 | elsif ( defined $web ) { | ||||
133 | foreach my $topic ( keys( %{ $this->{cache}->{$user}{$web} } ) ) { | ||||
134 | $this->removeMeta( $web, $topic ); | ||||
135 | } | ||||
136 | delete $this->{cache}->{$user}{$web}; | ||||
137 | } | ||||
138 | |||||
139 | 3 | 8µs | return; | ||
140 | } | ||||
141 | |||||
142 | #returns undef if the meta is not the latestRev, or if it failed to load | ||||
143 | #else returns the $meta | ||||
144 | # spent 78.8s (1.39+77.4) within Foswiki::MetaCache::addMeta which was called 61320 times, avg 1.28ms/call:
# 26280 times (464ms+134ms) by Foswiki::MetaCache::get at line 214, avg 23µs/call
# 17520 times (543ms+51.5s) by Foswiki::Store::Interfaces::QueryAlgorithm::__ANON__[/var/www/foswikidev/core/lib/Foswiki/Store/Interfaces/QueryAlgorithm.pm:194] at line 176 of /var/www/foswikidev/core/lib/Foswiki/Store/Interfaces/QueryAlgorithm.pm, avg 2.97ms/call
# 8760 times (218ms+25.7s) by Foswiki::Store::QueryAlgorithms::BruteForce::_webQuery at line 203 of /var/www/foswikidev/core/lib/Foswiki/Store/QueryAlgorithms/BruteForce.pm, avg 2.95ms/call
# 8760 times (163ms+47.6ms) by Foswiki::Search::InfoCache::addTopic at line 105 of /var/www/foswikidev/core/lib/Foswiki/Search/InfoCache.pm, avg 24µs/call | ||||
145 | 61320 | 32.5ms | my ( $this, $web, $topic, $meta ) = @_; | ||
146 | |||||
147 | 61320 | 78.6ms | 26280 | 77.0s | if ( not defined($meta) ) { # spent 77.0s making 26280 calls to Foswiki::Meta::load, avg 2.93ms/call |
148 | $meta = Foswiki::Meta->load( $this->{session}, $web, $topic ); | ||||
149 | } | ||||
150 | 61320 | 252ms | 183960 | 220ms | if ( ( defined($meta) and $meta ne '' ) # spent 138ms making 122640 calls to Foswiki::Meta::getLoadedRev, avg 1µs/call
# spent 82.5ms making 61320 calls to Foswiki::Meta::latestIsLoaded, avg 1µs/call |
151 | and defined( $meta->latestIsLoaded ) | ||||
152 | and defined( $meta->getLoadedRev ) | ||||
153 | and ( $meta->getLoadedRev > 0 ) ) | ||||
154 | { | ||||
155 | ASSERT( $meta->latestIsLoaded ) if DEBUG; | ||||
156 | 61320 | 10.0ms | ASSERT( defined( $meta->getLoadedRev ) and ( $meta->getLoadedRev > 0 ) ) | ||
157 | if DEBUG; | ||||
158 | } | ||||
159 | else { | ||||
160 | return; | ||||
161 | } | ||||
162 | |||||
163 | 61320 | 78.6ms | 61320 | 108ms | my $user = $this->current_user(); # spent 108ms making 61320 calls to Foswiki::MetaCache::current_user, avg 2µs/call |
164 | |||||
165 | 61320 | 46.4ms | unless ( $this->{cache}->{$user}{$web} ) { | ||
166 | $this->{cache}->{$user}{$web} = {}; | ||||
167 | } | ||||
168 | 61320 | 63.5ms | unless ( $this->{cache}->{$user}{$web}{$topic} ) { | ||
169 | $this->{cache}->{$user}{$web}{$topic} = {}; | ||||
170 | } | ||||
171 | 61320 | 56.5ms | unless ( defined( $this->{cache}->{$user}{$web}{$topic}->{tom} ) ) { | ||
172 | 219 | 226µs | $this->{cache}->{$user}{$web}{$topic}->{tom} = $meta; | ||
173 | 219 | 79µs | $this->{new_count}++; | ||
174 | } | ||||
175 | 61320 | 230ms | return $meta; | ||
176 | } | ||||
177 | |||||
178 | # spent 73.0ms (58.0+15.0) within Foswiki::MetaCache::getMeta which was called 8760 times, avg 8µs/call:
# 8760 times (58.0ms+15.0ms) by Foswiki::Search::formatResults at line 775 of /var/www/foswikidev/core/lib/Foswiki/Search.pm, avg 8µs/call | ||||
179 | 8760 | 5.10ms | my ( $this, $web, $topic, $meta ) = @_; | ||
180 | 8760 | 8.43ms | 8760 | 15.0ms | my $user = $this->current_user(); # spent 15.0ms making 8760 calls to Foswiki::MetaCache::current_user, avg 2µs/call |
181 | |||||
182 | 8760 | 6.06ms | return unless ( defined( $this->{cache}->{$user}{$web} ) ); | ||
183 | 8760 | 5.57ms | return unless ( defined( $this->{cache}->{$user}{$web}{$topic} ) ); | ||
184 | 8760 | 30.3ms | return $this->{cache}->{$user}{$web}{$topic}->{tom}; | ||
185 | } | ||||
186 | |||||
187 | =begin TML | ||||
188 | |||||
189 | ---++ ObjectMethod get($web, $topic, $meta) -> a cache obj (sorry, needs to be refactored out to return a Foswiki::Meta obj only | ||||
190 | |||||
191 | get a requested meta object - web or topic typically, might work for attachments too | ||||
192 | |||||
193 | optionally the $meta parameter can be used to add that to the cache - useful if you've already loaded and parsed the topic. | ||||
194 | |||||
195 | |||||
196 | TODO: the non-meta SEARCH render specific bits need to be moved elsewhere | ||||
197 | and then, the MetaCache can only return Meta objects that actually exist | ||||
198 | |||||
199 | =cut | ||||
200 | |||||
201 | # spent 1.03s (382ms+645ms) within Foswiki::MetaCache::get which was called 26280 times, avg 39µs/call:
# 17520 times (256ms+425ms) by Foswiki::Store::Interfaces::QueryAlgorithm::__ANON__[/var/www/foswikidev/core/lib/Foswiki/Store/Interfaces/QueryAlgorithm.pm:194] at line 186 of /var/www/foswikidev/core/lib/Foswiki/Store/Interfaces/QueryAlgorithm.pm, avg 39µs/call
# 8760 times (126ms+220ms) by Foswiki::Search::formatResults at line 782 of /var/www/foswikidev/core/lib/Foswiki/Search.pm, avg 40µs/call | ||||
202 | 26280 | 16.6ms | my ( $this, $web, $topic, $meta ) = @_; | ||
203 | 26280 | 5.81ms | ASSERT( $meta->isa('Foswiki::Meta') ) if ( defined($meta) and DEBUG ); | ||
204 | |||||
205 | #sadly, Search.pm actually beleives that it can send out for info on Meta objects that do not exist | ||||
206 | #ASSERT( defined($meta->getLoadedRev) ) if ( defined($meta) and DEBUG ); | ||||
207 | |||||
208 | 26280 | 2.95ms | if ( !defined($topic) ) { | ||
209 | |||||
210 | #there are some instances - like the result set sorting, where we need to quickly pass "$web.$topic" | ||||
211 | ( $web, $topic ) = Foswiki::Func::normalizeWebTopicName( '', $web ); | ||||
212 | } | ||||
213 | |||||
214 | 26280 | 24.5ms | 26280 | 598ms | my $m = $this->addMeta( $web, $topic, $meta ); # spent 598ms making 26280 calls to Foswiki::MetaCache::addMeta, avg 23µs/call |
215 | 26280 | 7.33ms | $meta = $m if ( defined($m) ); | ||
216 | ASSERT( defined($meta) ) if DEBUG; | ||||
217 | |||||
218 | 26280 | 6.68ms | $this->{get_count}++; | ||
219 | |||||
220 | 26280 | 28.0ms | my $info = { tom => $meta }; | ||
221 | 26280 | 26.7ms | 26280 | 39.2ms | my $user = $this->current_user(); # spent 39.2ms making 26280 calls to Foswiki::MetaCache::current_user, avg 1µs/call |
222 | |||||
223 | ASSERT( defined $user ) if DEBUG; | ||||
224 | 26280 | 52.9ms | $info = $this->{cache}->{$user}{$web}{$topic} | ||
225 | if defined( $this->{cache}->{$user}{$web}{$topic} ); | ||||
226 | 26280 | 13.6ms | if ( not defined( $info->{editby} ) ) { | ||
227 | |||||
228 | #TODO: extract this to the Meta Class, or remove entirely | ||||
229 | # Extract sort fields | ||||
230 | 219 | 276µs | 219 | 1.97ms | my $ri = $info->{tom}->getRevisionInfo(); # spent 1.97ms making 219 calls to Foswiki::Meta::getRevisionInfo, avg 9µs/call |
231 | |||||
232 | # Rename fields to match sorting criteria | ||||
233 | 219 | 165µs | $info->{editby} = $ri->{author} || ''; | ||
234 | 219 | 135µs | $info->{modified} = $ri->{date}; | ||
235 | 219 | 127µs | $info->{revNum} = $ri->{version}; | ||
236 | |||||
237 | #TODO: this is _not_ actually sufficient.. as there are other things that appear to be evaluated in turn | ||||
238 | #Ideally, the Store2::Meta object will _not_ contain any session info, and anything that is session / user oriented gets stored in another object that links to the 'database' object. | ||||
239 | #it'll probably be better to make the MetaCache know what | ||||
240 | #Item10097: make the cache multi-user safe by storing the haveAccess on a per user basis | ||||
241 | 219 | 205µs | if ( not defined( $info->{ $this->{session}->{user} } ) ) { | ||
242 | $info->{ $this->{session}->{user} } = (); | ||||
243 | } | ||||
244 | 219 | 615µs | 219 | 5.56ms | if ( not defined( $info->{ $this->{session}->{user} }{allowView} ) ) { # spent 5.56ms making 219 calls to Foswiki::Meta::haveAccess, avg 25µs/call |
245 | $info->{ $this->{session}->{user} }{allowView} = | ||||
246 | $info->{tom}->haveAccess('VIEW'); | ||||
247 | } | ||||
248 | |||||
249 | #use the cached permission | ||||
250 | 219 | 318µs | $info->{allowView} = $info->{ $this->{session}->{user} }{allowView}; | ||
251 | } | ||||
252 | |||||
253 | 26280 | 101ms | return $info; | ||
254 | } | ||||
255 | |||||
256 | # spent 162ms within Foswiki::MetaCache::current_user which was called 96363 times, avg 2µs/call:
# 61320 times (108ms+0s) by Foswiki::MetaCache::addMeta at line 163, avg 2µs/call
# 26280 times (39.2ms+0s) by Foswiki::MetaCache::get at line 221, avg 1µs/call
# 8760 times (15.0ms+0s) by Foswiki::MetaCache::getMeta at line 180, avg 2µs/call
# 3 times (7µs+0s) by Foswiki::MetaCache::removeMeta at line 122, avg 2µs/call | ||||
257 | 96363 | 18.1ms | my $self = shift; | ||
258 | |||||
259 | ASSERT( defined $self->{session} ) if DEBUG; | ||||
260 | 96363 | 47.2ms | my $user = $self->{session}->{user}; | ||
261 | 96363 | 11.9ms | if ( not defined $user ) { | ||
262 | $user = $Foswiki::Users::BaseUserMapping::UNKNOWN_USER_CUID; | ||||
263 | } | ||||
264 | |||||
265 | 96363 | 402ms | return $user; | ||
266 | } | ||||
267 | |||||
268 | ########################################## | ||||
269 | # this used to try to use the never-released listener API to flush the cache on changes. | ||||
270 | # Sven is not entirely sure it really worked, but the replacement for the listeners makes more | ||||
271 | # sense - it would move the MetaCache into the Store itself, allowing us to cache loaded topics | ||||
272 | # before ACL's are evaluated. however, I suspect this will require adding the readonly hash support | ||||
273 | # to Meta, which requires the Data::Foswiki work (post 2.0) | ||||
274 | |||||
275 | sub DISABLED_insert { | ||||
276 | my ( $self, %args ) = @_; | ||||
277 | |||||
278 | $self->removeMeta( $args{newmeta}->web, $args{newmeta}->topic ); | ||||
279 | |||||
280 | return; | ||||
281 | } | ||||
282 | |||||
283 | sub DISABLED_update { | ||||
284 | my ( $self, %args ) = @_; | ||||
285 | |||||
286 | $self->removeMeta( $args{oldmeta}->web, $args{oldmeta}->topic ) | ||||
287 | if ( defined( $args{oldmeta} ) ); | ||||
288 | $self->removeMeta( $args{newmeta}->web, $args{newmeta}->topic ); | ||||
289 | |||||
290 | return; | ||||
291 | } | ||||
292 | |||||
293 | sub DISABLED_remove { | ||||
294 | my ( $self, %args ) = @_; | ||||
295 | |||||
296 | ASSERT( $args{oldmeta} ) if DEBUG; | ||||
297 | |||||
298 | $self->removeMeta( $args{oldmeta}->web, $args{oldmeta}->topic ) | ||||
299 | if ( defined( $args{oldmeta} ) ); | ||||
300 | |||||
301 | return; | ||||
302 | } | ||||
303 | |||||
304 | 1 | 2µs | 1; | ||
305 | __END__ |