Filename | /var/www/foswikidev/core/lib/Foswiki/Store.pm |
Statements | Executed 877497 statements in 2.17s |
Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
---|---|---|---|---|---|
132011 | 5 | 2 | 843ms | 3.45s | encode | Foswiki::Store::
126791 | 4 | 3 | 784ms | 3.78s | decode | Foswiki::Store::
50350 | 4 | 3 | 191ms | 191ms | cleanUpRevID | Foswiki::Store::
1 | 1 | 1 | 2.87ms | 3.23ms | BEGIN@63 | Foswiki::Store::
59 | 1 | 1 | 336µs | 365µs | getAttachmentURL | Foswiki::Store::
1 | 1 | 1 | 16µs | 50µs | getWorkArea | Foswiki::Store::
1 | 1 | 1 | 12µs | 25µs | BEGIN@55 | Foswiki::Store::
1 | 1 | 1 | 12µs | 12µs | new | Foswiki::Store::
1 | 1 | 1 | 9µs | 32µs | BEGIN@59 | Foswiki::Store::
1 | 1 | 1 | 8µs | 12µs | BEGIN@56 | Foswiki::Store::
1 | 1 | 1 | 8µs | 105µs | BEGIN@58 | Foswiki::Store::
1 | 1 | 1 | 5µs | 5µs | BEGIN@65 | Foswiki::Store::
1 | 1 | 1 | 3µs | 3µs | BEGIN@61 | Foswiki::Store::
1 | 1 | 1 | 3µs | 3µs | BEGIN@62 | Foswiki::Store::
1 | 1 | 1 | 2µs | 2µs | finish | Foswiki::Store::
0 | 0 | 0 | 0s | 0s | __ANON__[:278] | Foswiki::Store::
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::Store | ||||
6 | |||||
7 | This class is a pure virtual base class that specifies the interface | ||||
8 | between the actual store implementation and the rest of the Foswiki | ||||
9 | system. | ||||
10 | |||||
11 | Subclasses of this class (known as "store implementations") are | ||||
12 | responsible for checking for topic existance, access permissions, and | ||||
13 | all the other general admin tasks required of a store. | ||||
14 | |||||
15 | This class knows *nothing* about how the data is actually _stored_ - | ||||
16 | that knowledge is entirely encapsulated in the implementation. | ||||
17 | |||||
18 | The general contract for methods in the class requires that errors | ||||
19 | are signalled using exceptions. Foswiki::AccessControlException is | ||||
20 | used for access control exceptions, and Error::Simple for all other | ||||
21 | types of error. | ||||
22 | |||||
23 | The reference implementations of this base class | ||||
24 | =Foswiki::Store::PlainFileStore=, | ||||
25 | which can be obtained from PlainFileStoreContrib. | ||||
26 | |||||
27 | Methods of this class and all subclasses should *only* be called from | ||||
28 | =Foswiki= and =Foswiki::Meta=. All other system components must delegate | ||||
29 | store interactions via =Foswiki::Meta=. | ||||
30 | |||||
31 | For readers who are familiar with Foswiki version 1.0.0, this class | ||||
32 | _describes_ the interface to the old =Foswiki::Store= without actually | ||||
33 | _implementing_ it. | ||||
34 | |||||
35 | Note that most methods are passed a Foswiki::Meta object. This pattern is | ||||
36 | employed to reinforce the encapsulation of a "path" in a meta object, and | ||||
37 | also to allow the store to modify META fields in the object, something it | ||||
38 | would be unable to do if passed $web, $topic. | ||||
39 | |||||
40 | Version numbers are required to be positive, non-zero integers. When | ||||
41 | passing in version numbers to the methods of a store implementation, 0, | ||||
42 | undef and '' are treated as referring to the *latest* (most recent) | ||||
43 | revision of the object. Version numbers are required to increase (later | ||||
44 | version numbers are greater than earlier) but are *not* required to be | ||||
45 | sequential. | ||||
46 | |||||
47 | *IMPORTANT:* the store must be able to handle unicode topic and | ||||
48 | attachment names, and unicode topic content. The store is expected | ||||
49 | to do any necessary encoding/decoding from/to unicode. | ||||
50 | |||||
51 | =cut | ||||
52 | |||||
53 | package Foswiki::Store; | ||||
54 | |||||
55 | 2 | 25µs | 2 | 38µs | # spent 25µs (12+13) within Foswiki::Store::BEGIN@55 which was called:
# once (12µs+13µs) by Foswiki::UI::View::BEGIN@23 at line 55 # spent 25µs making 1 call to Foswiki::Store::BEGIN@55
# spent 13µs making 1 call to strict::import |
56 | 2 | 25µs | 2 | 17µs | # spent 12µs (8+4) within Foswiki::Store::BEGIN@56 which was called:
# once (8µs+4µs) by Foswiki::UI::View::BEGIN@23 at line 56 # spent 12µs making 1 call to Foswiki::Store::BEGIN@56
# spent 4µs making 1 call to warnings::import |
57 | |||||
58 | 2 | 28µs | 2 | 202µs | # spent 105µs (8+97) within Foswiki::Store::BEGIN@58 which was called:
# once (8µs+97µs) by Foswiki::UI::View::BEGIN@23 at line 58 # spent 105µs making 1 call to Foswiki::Store::BEGIN@58
# spent 97µs making 1 call to Error::import |
59 | 2 | 24µs | 2 | 54µs | # spent 32µs (9+22) within Foswiki::Store::BEGIN@59 which was called:
# once (9µs+22µs) by Foswiki::UI::View::BEGIN@23 at line 59 # spent 32µs making 1 call to Foswiki::Store::BEGIN@59
# spent 22µs making 1 call to Exporter::import |
60 | |||||
61 | 2 | 20µs | 1 | 3µs | # spent 3µs within Foswiki::Store::BEGIN@61 which was called:
# once (3µs+0s) by Foswiki::UI::View::BEGIN@23 at line 61 # spent 3µs making 1 call to Foswiki::Store::BEGIN@61 |
62 | 2 | 26µs | 1 | 3µs | # spent 3µs within Foswiki::Store::BEGIN@62 which was called:
# once (3µs+0s) by Foswiki::UI::View::BEGIN@23 at line 62 # spent 3µs making 1 call to Foswiki::Store::BEGIN@62 |
63 | 2 | 209µs | 1 | 3.23ms | # spent 3.23ms (2.87+360µs) within Foswiki::Store::BEGIN@63 which was called:
# once (2.87ms+360µs) by Foswiki::UI::View::BEGIN@23 at line 63 # spent 3.23ms making 1 call to Foswiki::Store::BEGIN@63 |
64 | |||||
65 | # spent 5µs within Foswiki::Store::BEGIN@65 which was called:
# once (5µs+0s) by Foswiki::UI::View::BEGIN@23 at line 70 | ||||
66 | 1 | 5µs | if ( $Foswiki::cfg{UseLocale} ) { | ||
67 | require locale; | ||||
68 | import locale(); | ||||
69 | } | ||||
70 | 1 | 516µs | 1 | 5µs | } # spent 5µs making 1 call to Foswiki::Store::BEGIN@65 |
71 | |||||
72 | # Version number of the store API | ||||
73 | 1 | 600ns | our $STORE_FORMAT_VERSION = '1.2'; | ||
74 | |||||
75 | =begin TML | ||||
76 | |||||
77 | ---++ ClassMethod new() | ||||
78 | |||||
79 | Construct a Store module. | ||||
80 | |||||
81 | =cut | ||||
82 | |||||
83 | # spent 12µs within Foswiki::Store::new which was called:
# once (12µs+0s) by Foswiki::new at line 2120 of /var/www/foswikidev/core/lib/Foswiki.pm | ||||
84 | 1 | 1µs | my $class = shift; | ||
85 | |||||
86 | 1 | 8µs | my $this = bless( {}, $class ); | ||
87 | 1 | 4µs | return $this; | ||
88 | } | ||||
89 | |||||
90 | =begin TML | ||||
91 | |||||
92 | ---++ ObjectMethod finish() | ||||
93 | Break circular references. | ||||
94 | |||||
95 | =cut | ||||
96 | |||||
97 | # Note to developers; please undef *all* fields in the object explicitly, | ||||
98 | # whether they are references or not. That way this method is "golden | ||||
99 | # documentation" of the live fields in the object. | ||||
100 | # spent 2µs within Foswiki::Store::finish which was called:
# once (2µs+0s) by Foswiki::Store::Rcs::Store::finish at line 77 of /var/www/foswikidev/core/lib/Foswiki/Store/Rcs/Store.pm | ||||
101 | 1 | 5µs | my $this = shift; | ||
102 | } | ||||
103 | |||||
104 | =begin TML | ||||
105 | |||||
106 | ---++ StaticMethod cleanUpRevID( $rev ) -> $integer | ||||
107 | |||||
108 | Cleans up (maps) a user-supplied revision ID and converts it to an integer | ||||
109 | number that can be incremented to create a new revision number. | ||||
110 | |||||
111 | This method should be used to sanitise user-provided revision IDs. | ||||
112 | |||||
113 | Returns 0 if it was unable to determine a valid rev number from the | ||||
114 | string passed. | ||||
115 | |||||
116 | Works with RCS format (e.g. 1.2) rev IDs and plain integer numbers. | ||||
117 | |||||
118 | =cut | ||||
119 | |||||
120 | # spent 191ms (191+119µs) within Foswiki::Store::cleanUpRevID which was called 50350 times, avg 4µs/call:
# 26326 times (127ms+119µs) by Foswiki::Serialise::Embedded::read at line 88 of /var/www/foswikidev/core/lib/Foswiki/Serialise/Embedded.pm, avg 5µs/call
# 24019 times (64.3ms+0s) by Foswiki::Serialise::Embedded::read at line 90 of /var/www/foswikidev/core/lib/Foswiki/Serialise/Embedded.pm, avg 3µs/call
# 3 times (7µs+0s) by Foswiki::REVINFO at line 25 of /var/www/foswikidev/core/lib/Foswiki/Macros/REVINFO.pm, avg 2µs/call
# 2 times (9µs+0s) by Foswiki::Store::Rcs::Handler::_getTOPICINFO at line 278 of /var/www/foswikidev/core/lib/Foswiki/Store/Rcs/Handler.pm, avg 4µs/call | ||||
121 | 50350 | 11.7ms | my $rev = shift; | ||
122 | |||||
123 | # RCS format: 1.2, or plain integer: 2 | ||||
124 | 50350 | 341ms | 1 | 119µs | if ( defined $rev && $rev =~ m/^(?:\d+\.)?(\d+)$/ ) { # spent 119µs making 1 call to utf8::SWASHNEW |
125 | return $1; | ||||
126 | } | ||||
127 | |||||
128 | 3 | 7µs | return 0; | ||
129 | } | ||||
130 | |||||
131 | =begin TML | ||||
132 | |||||
133 | ---+++ ObjectMethod getWorkArea( $key ) -> $directorypath | ||||
134 | |||||
135 | Gets a private directory uniquely identified by $key. The directory is | ||||
136 | intended as a work area for plugins. | ||||
137 | |||||
138 | The standard is a directory named the same as "key" under | ||||
139 | $Foswiki::cfg{WorkingDir}/work_areas | ||||
140 | |||||
141 | =cut | ||||
142 | |||||
143 | # spent 50µs (16+34) within Foswiki::Store::getWorkArea which was called:
# once (16µs+34µs) by Foswiki::getWorkArea at line 4066 of /var/www/foswikidev/core/lib/Foswiki.pm | ||||
144 | 1 | 1µs | my ( $this, $key ) = @_; | ||
145 | |||||
146 | # untaint and detect nasties. The rules are the same as for | ||||
147 | # attachment names. | ||||
148 | 1 | 3µs | 1 | 34µs | $key = Foswiki::Sandbox::untaint( $key, # spent 34µs making 1 call to Foswiki::Sandbox::untaint |
149 | \&Foswiki::Sandbox::validateAttachmentName ); | ||||
150 | 1 | 300ns | throw Error::Simple("Bad work area name $key") unless ($key); | ||
151 | |||||
152 | 1 | 2µs | my $dir = "$Foswiki::cfg{WorkingDir}/work_areas/$key"; | ||
153 | |||||
154 | 1 | 6µs | unless ( -d $dir ) { | ||
155 | mkdir($dir) || throw Error::Simple(<<ERROR); | ||||
156 | Failed to create $key work area. Check your setting of {WorkingDir} | ||||
157 | in =configure=. | ||||
158 | ERROR | ||||
159 | } | ||||
160 | 1 | 4µs | return $dir; | ||
161 | } | ||||
162 | |||||
163 | =begin TML | ||||
164 | |||||
165 | ---++ ObjectMethod getAttachmentURL( $web, $topic, $attachment, %options ) -> $url | ||||
166 | |||||
167 | Get a URL that points at an attachment. The URL may be absolute, or | ||||
168 | relative to the the page being rendered (if that makes sense for the | ||||
169 | store implementation). | ||||
170 | * =$session - the current Foswiki session | ||||
171 | * =$web= - name of the web for the URL | ||||
172 | * =$topic= - name of the topic | ||||
173 | * =$attachment= - name of the attachment, defaults to no attachment | ||||
174 | * %options - parameters to be attached to the URL | ||||
175 | |||||
176 | Supported %options are: | ||||
177 | * =topic_version= - version of topic to retrieve attachment from | ||||
178 | * =attachment_version= - version of attachment to retrieve | ||||
179 | * =absolute= - if the returned URL must be absolute, rather than relative | ||||
180 | |||||
181 | If =$web= is not given, =$topic= and =$attachment= are ignored/ | ||||
182 | If =$topic= is not given, =$attachment= is ignored. | ||||
183 | |||||
184 | If =topic_version= is not given, the most recent revision of the topic | ||||
185 | should be linked. Similarly if attachment_version= is not given, the most recent | ||||
186 | revision of the attachment will be assumed. If =topic_version= is specified | ||||
187 | but =attachment_version= is not (or the specified =attachment_version= is not | ||||
188 | present), then the most recent version of the attachment in that topic version | ||||
189 | will be linked. Stores may not support =topic_version= and =attachment_version=. | ||||
190 | |||||
191 | The default implementation is suitable for use with stores that put | ||||
192 | attachments in a web-visible directory, pointed at by | ||||
193 | $Foswiki::cfg{PubUrlPath}. As such it may also be used as a | ||||
194 | fallback for distributed topics (such as those in System) when content is not | ||||
195 | held in the store itself (e.g. if the store doesn't recognise the web it | ||||
196 | can call SUPER::getAttachmentURL) | ||||
197 | |||||
198 | As required by RFC3986, the returned URL may only contain the | ||||
199 | allowed characters -A-Za-z0-9_.~!*\'();:@&=+$,/?%#[] | ||||
200 | |||||
201 | =cut | ||||
202 | |||||
203 | # spent 365µs (336+29) within Foswiki::Store::getAttachmentURL which was called 59 times, avg 6µs/call:
# 59 times (336µs+29µs) by Foswiki::getPubURL at line 1632 of /var/www/foswikidev/core/lib/Foswiki.pm, avg 6µs/call | ||||
204 | 59 | 68µs | my ( $this, $session, $web, $topic, $attachment, %options ) = @_; | ||
205 | 59 | 26µs | my $url = $Foswiki::cfg{PubUrlPath} || ''; | ||
206 | |||||
207 | 59 | 14µs | 1 | 8µs | if ($topic) { # spent 8µs making 1 call to Foswiki::Func::normalizeWebTopicName |
208 | ( $web, $topic ) = Foswiki::Func::normalizeWebTopicName( $web, $topic ); | ||||
209 | } | ||||
210 | |||||
211 | 59 | 8µs | if ($web) { | ||
212 | 1 | 2µs | 1 | 9µs | $url .= '/' . Foswiki::urlEncode($web); # spent 9µs making 1 call to Foswiki::urlEncode |
213 | 1 | 400ns | if ($topic) { | ||
214 | 1 | 900ns | if ( defined $options{topic_version} ) { | ||
215 | |||||
216 | # TODO: check that the given topic version exists | ||||
217 | } | ||||
218 | 1 | 2µs | 1 | 6µs | $url .= '/' . Foswiki::urlEncode($topic); # spent 6µs making 1 call to Foswiki::urlEncode |
219 | 1 | 1µs | if ($attachment) { | ||
220 | 1 | 500ns | if ( defined $options{attachment_version} ) { | ||
221 | |||||
222 | # TODO: check that this attachment version actually | ||||
223 | # exists on the requested topic version | ||||
224 | } | ||||
225 | |||||
226 | # TODO: check that the attachment actually exists on the | ||||
227 | # topic at this revision | ||||
228 | 1 | 2µs | 1 | 6µs | $url .= '/' . Foswiki::urlEncode($attachment); # spent 6µs making 1 call to Foswiki::urlEncode |
229 | } | ||||
230 | } | ||||
231 | } | ||||
232 | |||||
233 | 59 | 100µs | if ( $options{absolute} && $url !~ /^[a-z]+:/ ) { | ||
234 | |||||
235 | # See http://www.ietf.org/rfc/rfc2396.txt for the definition of | ||||
236 | # "absolute URI". Foswiki bastardises this definition by assuming | ||||
237 | # that all relative URLs lack the <authority> component as well. | ||||
238 | $url = "$session->{urlHost}$url"; | ||||
239 | } | ||||
240 | |||||
241 | 59 | 154µs | return $url; | ||
242 | } | ||||
243 | |||||
244 | =begin TML | ||||
245 | |||||
246 | ---++ StaticMethod decode($octets) -> $unicode | ||||
247 | |||||
248 | Utility function to decode a binary string of octets read from | ||||
249 | the store and known known to be encoded using the | ||||
250 | currently selected {Store}{Encoding} (or UTF-8 if none is set) | ||||
251 | into perl characters (unicode). May die if $octets contains | ||||
252 | an invalid byte sequence for the encoding. | ||||
253 | |||||
254 | =cut | ||||
255 | |||||
256 | # spent 3.78s (784ms+2.99) within Foswiki::Store::decode which was called 126791 times, avg 30µs/call:
# 100320 times (557ms+1.71s) by Foswiki::Store::Rcs::Handler::getTopicNames at line 585 of /var/www/foswikidev/core/lib/Foswiki/Store/Rcs/Handler.pm, avg 23µs/call
# 26327 times (223ms+1.26s) by Foswiki::Store::Rcs::Store::readTopic at line 116 of /var/www/foswikidev/core/lib/Foswiki/Store/Rcs/Store.pm, avg 56µs/call
# 120 times (5.05ms+22.5ms) by Foswiki::Store::SearchAlgorithms::Forking::_search at line 168 of /var/www/foswikidev/core/lib/Foswiki/Store/SearchAlgorithms/Forking.pm, avg 230µs/call
# 24 times (122µs+408µs) by Foswiki::Store::Rcs::Handler::getWebNames at line 638 of /var/www/foswikidev/core/lib/Foswiki/Store/Rcs/Handler.pm, avg 22µs/call | ||||
257 | 126791 | 19.1ms | return $_[0] unless defined $_[0]; | ||
258 | 126791 | 31.0ms | my $s = $_[0]; | ||
259 | 126791 | 791ms | 253582 | 2.99s | return Encode::decode( $Foswiki::cfg{Store}{Encoding} || 'utf-8', # spent 2.93s making 126791 calls to Encode::decode, avg 23µs/call
# spent 61.0ms making 126791 calls to Encode::FB_CROAK, avg 481ns/call |
260 | $s, Encode::FB_CROAK ); | ||||
261 | } | ||||
262 | |||||
263 | =begin TML | ||||
264 | |||||
265 | ---++ StaticMethod encode($unicode) -> $octets | ||||
266 | |||||
267 | Utility function to encode a perl character string into | ||||
268 | a string of octets encoded using the currently selected | ||||
269 | {Store}{Encoding} (or UTF-8 if none is set). May die if | ||||
270 | =$unicode= cannot be represented in the {Store}{Encoding}. | ||||
271 | |||||
272 | =cut | ||||
273 | |||||
274 | # spent 3.45s (843ms+2.61) within Foswiki::Store::encode which was called 132011 times, avg 26µs/call:
# 105614 times (685ms+2.11s) by Foswiki::Store::Rcs::Handler::__ANON__[/var/www/foswikidev/core/lib/Foswiki/Store/Rcs/Handler.pm:63] at line 63 of /var/www/foswikidev/core/lib/Foswiki/Store/Rcs/Handler.pm, avg 26µs/call
# 26327 times (158ms+493ms) by Foswiki::Store::Rcs::Handler::readFile at line 1127 of /var/www/foswikidev/core/lib/Foswiki/Store/Rcs/Handler.pm, avg 25µs/call
# 40 times (216µs+648µs) by Foswiki::Store::Rcs::Handler::getTopicNames at line 577 of /var/www/foswikidev/core/lib/Foswiki/Store/Rcs/Handler.pm, avg 22µs/call
# 26 times (134µs+423µs) by Foswiki::Store::Rcs::Handler::getWebNames at line 636 of /var/www/foswikidev/core/lib/Foswiki/Store/Rcs/Handler.pm, avg 21µs/call
# 4 times (16µs+53µs) by Foswiki::Store::Rcs::Store::__ANON__[/var/www/foswikidev/core/lib/Foswiki/Store/Rcs/Store.pm:61] at line 61 of /var/www/foswikidev/core/lib/Foswiki/Store/Rcs/Store.pm, avg 17µs/call | ||||
275 | 132011 | 25.5ms | return $_[0] unless defined $_[0]; | ||
276 | 132011 | 33.1ms | my $s = $_[0]; | ||
277 | return Encode::encode( $Foswiki::cfg{Store}{Encoding} || 'utf-8', | ||||
278 | 132011 | 919ms | 132011 | 2.61s | $s, sub { HTML::Entities::encode_entities( chr(shift) ) } ); # spent 2.61s making 132011 calls to Encode::encode, avg 20µs/call |
279 | } | ||||
280 | |||||
281 | 1 | 8µs | 1; | ||
282 | __END__ |