← Index
NYTProf Performance Profile   « block view • line view • sub view »
For /usr/local/src/github.com/foswiki/core/bin/view
  Run on Sun Dec 4 17:17:59 2011
Reported on Sun Dec 4 17:26:50 2011

Filename/usr/local/src/github.com/foswiki/core/lib/Foswiki/MetaCache.pm
StatementsExecuted 2877 statements in 12.7ms
Subroutines
Calls P F Exclusive
Time
Inclusive
Time
Subroutine
67223.13ms2.81sFoswiki::MetaCache::::addMetaFoswiki::MetaCache::addMeta
45333.10ms1.19sFoswiki::MetaCache::::getFoswiki::MetaCache::get
189312.98ms3.58msFoswiki::MetaCache::::current_userFoswiki::MetaCache::current_user
77221.42ms2.95msFoswiki::MetaCache::::getMetaFoswiki::MetaCache::getMeta
111491µs491µsFoswiki::MetaCache::::finishFoswiki::MetaCache::finish
11125µs32µsFoswiki::MetaCache::::BEGIN@3Foswiki::MetaCache::BEGIN@3
11122µs159µsFoswiki::MetaCache::::BEGIN@28Foswiki::MetaCache::BEGIN@28
11119µs19µsFoswiki::MetaCache::::newFoswiki::MetaCache::new
11116µs53µsFoswiki::MetaCache::::BEGIN@20Foswiki::MetaCache::BEGIN@20
11116µs34µsFoswiki::MetaCache::::BEGIN@4Foswiki::MetaCache::BEGIN@4
1119µs9µsFoswiki::MetaCache::::BEGIN@23Foswiki::MetaCache::BEGIN@23
1119µs9µsFoswiki::MetaCache::::BEGIN@21Foswiki::MetaCache::BEGIN@21
1118µs8µsFoswiki::MetaCache::::BEGIN@22Foswiki::MetaCache::BEGIN@22
0000s0sFoswiki::MetaCache::::hasCachedFoswiki::MetaCache::hasCached
0000s0sFoswiki::MetaCache::::insertFoswiki::MetaCache::insert
0000s0sFoswiki::MetaCache::::removeFoswiki::MetaCache::remove
0000s0sFoswiki::MetaCache::::removeMetaFoswiki::MetaCache::removeMeta
0000s0sFoswiki::MetaCache::::updateFoswiki::MetaCache::update
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::MetaCache;
3245µs239µs
# spent 32µs (25+7) within Foswiki::MetaCache::BEGIN@3 which was called: # once (25µs+7µs) by Foswiki::Search::BEGIN@25 at line 3
use strict;
# spent 32µs making 1 call to Foswiki::MetaCache::BEGIN@3 # spent 7µs making 1 call to strict::import
4256µs251µs
# spent 34µs (16+18) within Foswiki::MetaCache::BEGIN@4 which was called: # once (16µs+18µs) by Foswiki::Search::BEGIN@25 at line 4
use warnings;
# spent 34µs making 1 call to Foswiki::MetaCache::BEGIN@4 # spent 18µs making 1 call to warnings::import
5
6=begin TML
7
8---+ package Foswiki::MetaCache
9
10A cache of Meta objects - initially used to speed up searching and sorting, but by foswiki 2.0 hopefully this
11will be used for all readonly accesses to the store.
12
13Replaces the mishmash of the Search InfoCache Support package; cache of topic info.
14When information about search hits is
15compiled for output, this cache is used to avoid recovering the same info
16about the same topic more than once.
17
18=cut
19
20242µs291µs
# spent 53µs (16+37) within Foswiki::MetaCache::BEGIN@20 which was called: # once (16µs+37µs) by Foswiki::Search::BEGIN@25 at line 20
use Assert;
# spent 53µs making 1 call to Foswiki::MetaCache::BEGIN@20 # spent 37µs making 1 call to Assert::import
21237µs19µs
# spent 9µs within Foswiki::MetaCache::BEGIN@21 which was called: # once (9µs+0s) by Foswiki::Search::BEGIN@25 at line 21
use Foswiki::Func ();
# spent 9µs making 1 call to Foswiki::MetaCache::BEGIN@21
22237µs18µs
# spent 8µs within Foswiki::MetaCache::BEGIN@22 which was called: # once (8µs+0s) by Foswiki::Search::BEGIN@25 at line 22
use Foswiki::Meta ();
# spent 8µs making 1 call to Foswiki::MetaCache::BEGIN@22
23244µs19µs
# spent 9µs within Foswiki::MetaCache::BEGIN@23 which was called: # once (9µs+0s) by Foswiki::Search::BEGIN@25 at line 23
use Foswiki::Users::BaseUserMapping ();
# spent 9µs making 1 call to Foswiki::MetaCache::BEGIN@23
24
25#use Monitor ();
26#Monitor::MonitorMethod('Foswiki::MetaCache', 'getTopicListIterator');
27
2821.83ms2296µs
# spent 159µs (22+137) within Foswiki::MetaCache::BEGIN@28 which was called: # once (22µs+137µs) by Foswiki::Search::BEGIN@25 at line 28
use constant TRACE => 0;
# spent 159µs making 1 call to Foswiki::MetaCache::BEGIN@28 # spent 137µs making 1 call to constant::import
29
30=begin TML
31
32---++ ClassMethod new($session)
33
34=cut
35
36
# spent 19µs within Foswiki::MetaCache::new which was called: # once (19µs+0s) by Foswiki::Search::metacache at line 98 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Search.pm
sub new {
37323µs my ( $class, $session ) = @_;
38
39 #my $this = $class->SUPER::new([]);
40 my $this = bless(
41 {
42 session => $session,
43 cache => {},
44 new_count => 0,
45 get_count => 0,
46 undef_count => 0,
47 meta_cache_session_user => $session->{user},
48 },
49 $class
50 );
51
52 return $this;
53}
54
55#need to delete from cache if the store saves / updates it :/
56#otherwise the Meta::load thing is busted.
57
58=begin TML
59
60---++ ObjectMethod finish()
61Break circular references.
62
63 Note to developers; please undef *all* fields in the object explicitly,
64 whether they are references or not. That way this method is "golden
65 documentation" of the live fields in the object.
66
67=cut
68
69
# spent 491µs within Foswiki::MetaCache::finish which was called: # once (491µs+0s) by Foswiki::Search::finish at line 81 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Search.pm
sub finish {
70525µs my $this = shift;
71 undef $this->{session};
72
73 #must clear cache every request until the cache is hooked up to Store's save
7412µs foreach my $cuid ( keys( %{ $this->{cache} } ) ) {
75625µs foreach my $web ( keys( %{ $this->{cache}->{$cuid} } ) ) {
76331µs foreach my $topic ( keys( %{ $this->{cache}->{$cuid}->{$web} } ) ) {
7746409µs undef $this->{cache}->{$cuid}{$web}{$topic};
78 $this->{undef_count}++;
79 }
80 undef $this->{cache}->{$cuid}{$web};
81 }
82 undef $this->{cache}->{$cuid};
83 }
84 undef $this->{cache};
85
86 if (TRACE) {
87 print STDERR
88"MetaCache: new: $this->{new_count} get: $this->{get_count} undef: $this->{undef_count} \n";
89 }
90
91 return;
92}
93
94=begin TML
95
96---++ ObjectMethod hasCached($webtopic) -> boolean
97
98returns true if the topic is already int he cache.
99
100=cut
101
102sub hasCached {
103 my ( $this, $web, $topic ) = @_;
104 ASSERT( defined($topic) ) if DEBUG;
105 return unless ( defined($topic) );
106
107 return ( $this->{session}->{user}
108 and defined( $this->{cache}->{ $this->current_user() }{$web}{$topic} )
109 );
110}
111
112sub removeMeta {
113 my ( $this, $web, $topic ) = @_;
114 my $user = $this->current_user();
115
116 if ( defined($topic) and defined( $this->{cache}->{$user}{$web}{$topic} ) )
117 {
118 $this->{cache}->{$user}{$web}{$topic}->finish();
119 delete $this->{cache}->{$user}{$web}{$topic};
120 }
121 else {
122 foreach my $topic ( keys( %{ $this->{cache}->{$user}{$web} } ) ) {
123 $this->removeMeta( $web, $topic );
124 }
125 delete $this->{cache}->{$user}{$web};
126 }
127
128 return;
129}
130
131#returns undef if the meta is not the latestRev, or if it failed to load
132#else returns the $meta
133
# spent 2.81s (3.13ms+2.81) within Foswiki::MetaCache::addMeta which was called 67 times, avg 42.0ms/call: # 45 times (1.68ms+1.18s) by Foswiki::MetaCache::get at line 203, avg 26.3ms/call # 22 times (1.45ms+1.63s) by Foswiki::Store::Interfaces::QueryAlgorithm::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki/Store/Interfaces/QueryAlgorithm.pm:187] at line 169 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Store/Interfaces/QueryAlgorithm.pm, avg 74.2ms/call
sub addMeta {
1345361.85ms my ( $this, $web, $topic, $meta ) = @_;
135
13623206µs if ( not defined($meta) ) {
137232.81s $meta = Foswiki::Meta->load( $this->{session}, $web, $topic );
# spent 2.81s making 23 calls to Foswiki::Meta::load, avg 122ms/call
138 }
139134602µs if ( ( defined($meta) and $meta ne '' )
140 and defined( $meta->{_latestIsLoaded} )
141 and defined( $meta->{_loadedRev} )
142 and ( $meta->{_loadedRev} > 0 ) )
143 {
14467226µs ASSERT( $meta->{_latestIsLoaded} ) if DEBUG;
# spent 226µs making 67 calls to Assert::ASSERTS_OFF, avg 3µs/call
14567206µs ASSERT( defined( $meta->{_loadedRev} ) and ( $meta->{_loadedRev} > 0 ) )
# spent 206µs making 67 calls to Assert::ASSERTS_OFF, avg 3µs/call
146 if DEBUG;
147 }
148 else {
149 return;
150 }
151
152671.20ms my $user = $this->current_user();
# spent 1.20ms making 67 calls to Foswiki::MetaCache::current_user, avg 18µs/call
153
15418µs unless ( $this->{cache}->{$user}{$web} ) {
155 $this->{cache}->{$user}{$web} = {};
156 }
15723114µs unless ( $this->{cache}->{$user}{$web}{$topic} ) {
158 $this->{cache}->{$user}{$web}{$topic} = {};
159 }
16046108µs unless ( defined( $this->{cache}->{$user}{$web}{$topic}->{tom} ) ) {
161 $this->{cache}->{$user}{$web}{$topic}->{tom} = $meta;
162 $this->{new_count}++;
163 }
164 return $meta;
165}
166
167
# spent 2.95ms (1.42+1.54) within Foswiki::MetaCache::getMeta which was called 77 times, avg 38µs/call: # 55 times (982µs+1.16ms) by Foswiki::Meta::load at line 468 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Meta.pm, avg 39µs/call # 22 times (435µs+380µs) by Foswiki::Search::formatResults at line 736 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Search.pm, avg 37µs/call
sub getMeta {
1682971.39ms my ( $this, $web, $topic, $meta ) = @_;
169771.54ms my $user = $this->current_user();
# spent 1.54ms making 77 calls to Foswiki::MetaCache::current_user, avg 20µs/call
170
171 return unless ( defined( $this->{cache}->{$user}{$web} ) );
172 return unless ( defined( $this->{cache}->{$user}{$web}{$topic} ) );
173 return $this->{cache}->{$user}{$web}{$topic}->{tom};
174}
175
176=begin TML
177
178---++ ObjectMethod get($web, $topic, $meta) -> a cache obj (sorry, needs to be refactored out to return a Foswiki::Meta obj only
179
180get a requested meta object - web or topic typically, might work for attachments too
181
182optionally the $meta parameter can be used to add that to the cache - useful if you've already loaded and parsed the topic.
183
184
185TODO: the non-meta SEARCH render specific bits need to be moved elsewhere
186and then, the MetaCache can only return Meta objects that actually exist
187
188=cut
189
190
# spent 1.19s (3.10ms+1.19) within Foswiki::MetaCache::get which was called 45 times, avg 26.4ms/call: # 22 times (1.92ms+5.59ms) by Foswiki::Store::Interfaces::QueryAlgorithm::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki/Store/Interfaces/QueryAlgorithm.pm:187] at line 179 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Store/Interfaces/QueryAlgorithm.pm, avg 341µs/call # 22 times (1.04ms+1.89ms) by Foswiki::Search::formatResults at line 743 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Search.pm, avg 133µs/call # once (143µs+1.18s) by Foswiki::Store::QueryAlgorithms::BruteForce::_webQuery at line 78 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Store/QueryAlgorithms/BruteForce.pm
sub get {
1915852.06ms my ( $this, $web, $topic, $meta ) = @_;
19244141µs ASSERT( $meta->isa('Foswiki::Meta') ) if ( defined($meta) and DEBUG );
# spent 141µs making 44 calls to Assert::ASSERTS_OFF, avg 3µs/call
193
194#sadly, Search.pm actually beleives that it can send out for info on Meta objects that do not exist
195#ASSERT( defined($meta->{_loadedRev}) ) if ( defined($meta) and DEBUG );
196
197 if ( !defined($topic) ) {
198
199#there are some instances - like the result set sorting, where we need to quickly pass "$web.$topic"
200 ( $web, $topic ) = Foswiki::Func::normalizeWebTopicName( '', $web );
201 }
202
203451.18s my $m = $this->addMeta( $web, $topic, $meta );
# spent 1.18s making 45 calls to Foswiki::MetaCache::addMeta, avg 26.3ms/call
204 $meta = $m if ( defined($m) );
20545154µs ASSERT( defined($meta) ) if DEBUG;
# spent 154µs making 45 calls to Assert::ASSERTS_OFF, avg 3µs/call
206
207 $this->{get_count}++;
208
209 my $info = { tom => $meta };
21045842µs my $user = $this->current_user();
# spent 842µs making 45 calls to Foswiki::MetaCache::current_user, avg 19µs/call
211
21245159µs ASSERT( defined $user ) if DEBUG;
# spent 159µs making 45 calls to Assert::ASSERTS_OFF, avg 4µs/call
213 $info = $this->{cache}->{$user}{$web}{$topic}
214 if defined( $this->{cache}->{$user}{$web}{$topic} );
215161562µs if ( not defined( $info->{editby} ) ) {
216
217 #TODO: extract this to the Meta Class, or remove entirely
218 # Extract sort fields
219231.28ms my $ri = $info->{tom}->getRevisionInfo();
# spent 1.28ms making 23 calls to Foswiki::Meta::getRevisionInfo, avg 56µs/call
220
221 # Rename fields to match sorting criteria
222 $info->{editby} = $ri->{author} || '';
223 $info->{modified} = $ri->{date};
224 $info->{revNum} = $ri->{version};
225
226#TODO: this is _not_ actually sufficient.. as there are other things that appear to be evaluated in turn
227#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.
228#it'll probably be better to make the MetaCache know what
229#Item10097: make the cache multi-user safe by storing the haveAccess on a per user basis
2302359µs if ( not defined( $info->{ $this->{session}->{user} } ) ) {
231 $info->{ $this->{session}->{user} } = ();
232 }
23323204µs if ( not defined( $info->{ $this->{session}->{user} }{allowView} ) ) {
234232.60ms $info->{ $this->{session}->{user} }{allowView} =
# spent 2.60ms making 23 calls to Foswiki::Meta::haveAccess, avg 113µs/call
235 $info->{tom}->haveAccess('VIEW');
236 }
237
238 #use the cached permission
239 $info->{allowView} = $info->{ $this->{session}->{user} }{allowView};
240 }
241
242 return $info;
243}
244
245##########################################
246# use the Listener API to detect when to flush the cache
247#magically enable it.
248
24914µs$Foswiki::cfg{Store}{Listeners}{'Foswiki::MetaCache'} = 1;
250
251sub insert {
252 my ( $self, %args ) = @_;
253
254 $self->removeMeta( $args{newmeta}->web, $args{newmeta}->topic );
255
256 return;
257}
258
259sub update {
260 my ( $self, %args ) = @_;
261
262 $self->removeMeta( $args{oldmeta}->web, $args{oldmeta}->topic )
263 if ( defined( $args{oldmeta} ) );
264 $self->removeMeta( $args{newmeta}->web, $args{newmeta}->topic );
265
266 return;
267}
268
269sub remove {
270 my ( $self, %args ) = @_;
271
272 ASSERT( $args{oldmeta} ) if DEBUG;
273
274 $self->removeMeta( $args{oldmeta}->web, $args{oldmeta}->topic )
275 if ( defined( $args{oldmeta} ) );
276
277 return;
278}
279
280
# spent 3.58ms (2.98+601µs) within Foswiki::MetaCache::current_user which was called 189 times, avg 19µs/call: # 77 times (1.27ms+264µs) by Foswiki::MetaCache::getMeta at line 169, avg 20µs/call # 67 times (1.00ms+200µs) by Foswiki::MetaCache::addMeta at line 152, avg 18µs/call # 45 times (705µs+137µs) by Foswiki::MetaCache::get at line 210, avg 19µs/call
sub current_user {
2819452.88ms my $self = shift;
282
283189601µs ASSERT( defined $self->{session} ) if DEBUG;
# spent 601µs making 189 calls to Assert::ASSERTS_OFF, avg 3µs/call
284 my $user = $self->{session}->{user};
285 if ( not defined $user ) {
286 $user = $Foswiki::Users::BaseUserMapping::UNKNOWN_USER_CUID;
287 }
288
289 return $user;
290}
291
29216µs1;
293__END__