← Index
NYTProf Performance Profile   « line view »
For ./view
  Run on Fri Jul 31 18:42:36 2015
Reported on Fri Jul 31 18:48:15 2015

Filename/var/www/foswikidev/core/lib/Foswiki/Store/Rcs/Store.pm
StatementsExecuted 555774 statements in 997ms
Subroutines
Calls P F Exclusive
Time
Inclusive
Time
Subroutine
26327111.58s75.8sFoswiki::Store::Rcs::Store::::readTopicFoswiki::Store::Rcs::Store::readTopic
40117.10ms2.79sFoswiki::Store::Rcs::Store::::eachTopicFoswiki::Store::Rcs::Store::eachTopic
80223.74ms108sFoswiki::Store::Rcs::Store::::queryFoswiki::Store::Rcs::Store::query (recurses: max depth 1, inclusive time 49.2s)
197331.44ms13.0msFoswiki::Store::Rcs::Store::::topicExistsFoswiki::Store::Rcs::Store::topicExists
10111906µs6.90msFoswiki::Store::Rcs::Store::::webExistsFoswiki::Store::Rcs::Store::webExists
2622641µs17.9msFoswiki::Store::Rcs::Store::::eachWebFoswiki::Store::Rcs::Store::eachWeb (recurses: max depth 2, inclusive time 19.9ms)
31194µs14.9msFoswiki::Store::Rcs::Store::::getVersionInfoFoswiki::Store::Rcs::Store::getVersionInfo
42132µs102µsFoswiki::Store::Rcs::Store::::__ANON__[:61]Foswiki::Store::Rcs::Store::__ANON__[:61]
21131µs731µsFoswiki::Store::Rcs::Store::::getRevisionHistoryFoswiki::Store::Rcs::Store::getRevisionHistory
11128µs30µsFoswiki::Store::Rcs::Store::::finishFoswiki::Store::Rcs::Store::finish
11119µs93µsFoswiki::Store::Rcs::Store::::attachmentExistsFoswiki::Store::Rcs::Store::attachmentExists
11118µs29µsFoswiki::Store::Rcs::Store::::BEGIN@33Foswiki::Store::Rcs::Store::BEGIN@33
11111µs11µsFoswiki::Store::Rcs::Store::::BEGIN@47Foswiki::Store::Rcs::Store::BEGIN@47
11110µs23µsFoswiki::Store::Rcs::Store::::BEGIN@665Foswiki::Store::Rcs::Store::BEGIN@665
1119µs13µsFoswiki::Store::Rcs::Store::::BEGIN@34Foswiki::Store::Rcs::Store::BEGIN@34
1119µs34µsFoswiki::Store::Rcs::Store::::BEGIN@39Foswiki::Store::Rcs::Store::BEGIN@39
1119µs114µsFoswiki::Store::Rcs::Store::::BEGIN@40Foswiki::Store::Rcs::Store::BEGIN@40
1118µs18µsFoswiki::Store::Rcs::Store::::BEGIN@667Foswiki::Store::Rcs::Store::BEGIN@667
1115µs5µsFoswiki::Store::Rcs::Store::::BEGIN@42Foswiki::Store::Rcs::Store::BEGIN@42
1114µs4µsFoswiki::Store::Rcs::Store::::BEGIN@45Foswiki::Store::Rcs::Store::BEGIN@45
1114µs4µsFoswiki::Store::Rcs::Store::::BEGIN@36Foswiki::Store::Rcs::Store::BEGIN@36
1113µs3µsFoswiki::Store::Rcs::Store::::BEGIN@44Foswiki::Store::Rcs::Store::BEGIN@44
1113µs3µsFoswiki::Store::Rcs::Store::::BEGIN@43Foswiki::Store::Rcs::Store::BEGIN@43
0000s0sFoswiki::Store::Rcs::Store::::__ANON__[:62]Foswiki::Store::Rcs::Store::__ANON__[:62]
0000s0sFoswiki::Store::Rcs::Store::::__ANON__[:65]Foswiki::Store::Rcs::Store::__ANON__[:65]
0000s0sFoswiki::Store::Rcs::Store::::__ANON__[:66]Foswiki::Store::Rcs::Store::__ANON__[:66]
0000s0sFoswiki::Store::Rcs::Store::::_getAttachmentVersionInfoFoswiki::Store::Rcs::Store::_getAttachmentVersionInfo
0000s0sFoswiki::Store::Rcs::Store::::atomicLockFoswiki::Store::Rcs::Store::atomicLock
0000s0sFoswiki::Store::Rcs::Store::::atomicLockInfoFoswiki::Store::Rcs::Store::atomicLockInfo
0000s0sFoswiki::Store::Rcs::Store::::atomicUnlockFoswiki::Store::Rcs::Store::atomicUnlock
0000s0sFoswiki::Store::Rcs::Store::::copyAttachmentFoswiki::Store::Rcs::Store::copyAttachment
0000s0sFoswiki::Store::Rcs::Store::::delRevFoswiki::Store::Rcs::Store::delRev
0000s0sFoswiki::Store::Rcs::Store::::eachAttachmentFoswiki::Store::Rcs::Store::eachAttachment
0000s0sFoswiki::Store::Rcs::Store::::eachChangeFoswiki::Store::Rcs::Store::eachChange
0000s0sFoswiki::Store::Rcs::Store::::getApproxRevTimeFoswiki::Store::Rcs::Store::getApproxRevTime
0000s0sFoswiki::Store::Rcs::Store::::getHandlerFoswiki::Store::Rcs::Store::getHandler
0000s0sFoswiki::Store::Rcs::Store::::getLeaseFoswiki::Store::Rcs::Store::getLease
0000s0sFoswiki::Store::Rcs::Store::::getNextRevisionFoswiki::Store::Rcs::Store::getNextRevision
0000s0sFoswiki::Store::Rcs::Store::::getRevisionAtTimeFoswiki::Store::Rcs::Store::getRevisionAtTime
0000s0sFoswiki::Store::Rcs::Store::::getRevisionDiffFoswiki::Store::Rcs::Store::getRevisionDiff
0000s0sFoswiki::Store::Rcs::Store::::moveAttachmentFoswiki::Store::Rcs::Store::moveAttachment
0000s0sFoswiki::Store::Rcs::Store::::moveTopicFoswiki::Store::Rcs::Store::moveTopic
0000s0sFoswiki::Store::Rcs::Store::::moveWebFoswiki::Store::Rcs::Store::moveWeb
0000s0sFoswiki::Store::Rcs::Store::::openAttachmentFoswiki::Store::Rcs::Store::openAttachment
0000s0sFoswiki::Store::Rcs::Store::::recordChangeFoswiki::Store::Rcs::Store::recordChange
0000s0sFoswiki::Store::Rcs::Store::::removeFoswiki::Store::Rcs::Store::remove
0000s0sFoswiki::Store::Rcs::Store::::removeSpuriousLeasesFoswiki::Store::Rcs::Store::removeSpuriousLeases
0000s0sFoswiki::Store::Rcs::Store::::repRevFoswiki::Store::Rcs::Store::repRev
0000s0sFoswiki::Store::Rcs::Store::::saveAttachmentFoswiki::Store::Rcs::Store::saveAttachment
0000s0sFoswiki::Store::Rcs::Store::::saveTopicFoswiki::Store::Rcs::Store::saveTopic
0000s0sFoswiki::Store::Rcs::Store::::setLeaseFoswiki::Store::Rcs::Store::setLease
0000s0sFoswiki::Store::Rcs::Store::::testAttachmentFoswiki::Store::Rcs::Store::testAttachment
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
2
3=begin TML
4
5---+ package Foswiki::Store::Rcs::Store
6
7Almost-complete implementation of =Foswiki::Store=. The methods
8of this class implement the =Foswiki::Store= interface.
9
10The store uses a "handler" class to handle all interactions with the
11actual version control system (and via it with the actual file system).
12A "handler" is created for each individual file in the file system, and
13this handler then brokers all requests to open, read, write etc the file.
14The handler object must implement the interface specified by
15=Foswiki::Store::Rcs::Handler=.
16
17The main additional responsibilities of _this_ class are to support storing
18Foswiki meta-data in plain text files, and to ensure that the =Foswiki::Meta=
19for a page is maintained in synchronisation with the files on disk.
20
21All that is required to create a working store is to subclass this class
22and override the 'new' method to specify the actual handler to use. See
23Foswiki::Store::RcsWrap for an example subclass.
24
25For readers who are familiar with Foswiki version 1.0, the functionality
26in this class _previously_ resided in =Foswiki::Store=.
27
28These methods are documented in the Foswiki:Store abstract base class
29
30=cut
31
32package Foswiki::Store::Rcs::Store;
33226µs241µs
# spent 29µs (18+12) within Foswiki::Store::Rcs::Store::BEGIN@33 which was called: # once (18µs+12µs) by Foswiki::Store::RcsWrap::BEGIN@23 at line 33
use strict;
# spent 29µs making 1 call to Foswiki::Store::Rcs::Store::BEGIN@33 # spent 12µs making 1 call to strict::import
34222µs217µs
# spent 13µs (9+4) within Foswiki::Store::Rcs::Store::BEGIN@34 which was called: # once (9µs+4µs) by Foswiki::Store::RcsWrap::BEGIN@23 at line 34
use warnings;
# spent 13µs making 1 call to Foswiki::Store::Rcs::Store::BEGIN@34 # spent 4µs making 1 call to warnings::import
35
36232µs14µs
# spent 4µs within Foswiki::Store::Rcs::Store::BEGIN@36 which was called: # once (4µs+0s) by Foswiki::Store::RcsWrap::BEGIN@23 at line 36
use Foswiki::Store ();
# spent 4µs making 1 call to Foswiki::Store::Rcs::Store::BEGIN@36
3718µsour @ISA = ('Foswiki::Store');
38
39229µs259µs
# spent 34µs (9+25) within Foswiki::Store::Rcs::Store::BEGIN@39 which was called: # once (9µs+25µs) by Foswiki::Store::RcsWrap::BEGIN@23 at line 39
use Assert;
# spent 34µs making 1 call to Foswiki::Store::Rcs::Store::BEGIN@39 # spent 25µs making 1 call to Exporter::import
40229µs2218µs
# spent 114µs (9+105) within Foswiki::Store::Rcs::Store::BEGIN@40 which was called: # once (9µs+105µs) by Foswiki::Store::RcsWrap::BEGIN@23 at line 40
use Error qw( :try );
# spent 114µs making 1 call to Foswiki::Store::Rcs::Store::BEGIN@40 # spent 105µs making 1 call to Error::import
41
42218µs15µs
# spent 5µs within Foswiki::Store::Rcs::Store::BEGIN@42 which was called: # once (5µs+0s) by Foswiki::Store::RcsWrap::BEGIN@23 at line 42
use Foswiki ();
# spent 5µs making 1 call to Foswiki::Store::Rcs::Store::BEGIN@42
43217µs13µs
# spent 3µs within Foswiki::Store::Rcs::Store::BEGIN@43 which was called: # once (3µs+0s) by Foswiki::Store::RcsWrap::BEGIN@23 at line 43
use Foswiki::Meta ();
# spent 3µs making 1 call to Foswiki::Store::Rcs::Store::BEGIN@43
44218µs13µs
# spent 3µs within Foswiki::Store::Rcs::Store::BEGIN@44 which was called: # once (3µs+0s) by Foswiki::Store::RcsWrap::BEGIN@23 at line 44
use Foswiki::Sandbox ();
# spent 3µs making 1 call to Foswiki::Store::Rcs::Store::BEGIN@44
452183µs14µs
# spent 4µs within Foswiki::Store::Rcs::Store::BEGIN@45 which was called: # once (4µs+0s) by Foswiki::Store::RcsWrap::BEGIN@23 at line 45
use Foswiki::Serialise();
# spent 4µs making 1 call to Foswiki::Store::Rcs::Store::BEGIN@45
46
47
# spent 11µs within Foswiki::Store::Rcs::Store::BEGIN@47 which was called: # once (11µs+0s) by Foswiki::Store::RcsWrap::BEGIN@23 at line 70
BEGIN {
48
49 # Do a dynamic 'use locale' for this module
501600ns if ( $Foswiki::cfg{UseLocale} ) {
51 require locale;
52 import locale();
53 }
54
55 # The RCS Handler code works on bytes, so we have to mediate
5617µs if ($Foswiki::UNICODE) {
571500ns require Encode;
58
5912µs *_decode = \&Foswiki::Store::decode;
601600ns *_encode = \&Foswiki::Store::encode;
61535µs470µs
# spent 102µs (32+70) within Foswiki::Store::Rcs::Store::__ANON__[/var/www/foswikidev/core/lib/Foswiki/Store/Rcs/Store.pm:61] which was called 4 times, avg 25µs/call: # 2 times (20µs+35µs) by Foswiki::Store::Rcs::Handler::noCheckinPending at line 306 of /var/www/foswikidev/core/lib/Foswiki/Store/Rcs/Handler.pm, avg 27µs/call # 2 times (12µs+35µs) by Foswiki::Store::Rcs::Handler::noCheckinPending at line 307 of /var/www/foswikidev/core/lib/Foswiki/Store/Rcs/Handler.pm, avg 24µs/call
*_stat = sub { stat( _encode( $_[0] ) ); };
# spent 70µs making 4 calls to Foswiki::Store::encode, avg 17µs/call
6211µs *_unlink = sub { unlink( _encode( $_[0] ) ); };
63 }
64 else {
65 *_decode = sub { return $_[0] };
66 *_encode = sub { return $_[0] };
67 *_stat = \&stat;
68 *_unlink = \&unlink;
69 }
7012.63ms111µs}
# spent 11µs making 1 call to Foswiki::Store::Rcs::Store::BEGIN@47
71
72# Note to developers; please undef *all* fields in the object explicitly,
73# whether they are references or not. That way this method is "golden
74# documentation" of the live fields in the object.
75
# spent 30µs (28+2) within Foswiki::Store::Rcs::Store::finish which was called: # once (28µs+2µs) by Foswiki::finish at line 2488 of /var/www/foswikidev/core/lib/Foswiki.pm
sub finish {
761600ns my $this = shift;
77121µs12µs $this->SUPER::finish();
# spent 2µs making 1 call to Foswiki::Store::finish
7814µs undef $this->{searchFn};
79}
80
81# SMELL: this module does not respect $Foswiki::inUnitTestMode; tests
82# just sit on top of the store which is configured in the current $Foswiki::cfg.
83# Most of the time this is ok, as store listeners will be told that
84# the store is in test mode, so caches should be unaffected. However
85# it's very untidy, potentially risky, and causes grief when unit tests
86# don't clean up after themselves.
87
88# PACKAGE PRIVATE
89# Get a handler for the given object in the store.
90sub getHandler {
91
92 #my ( $this, $web, $topic, $attachment ) = @_;
93 ASSERT( 0, "Must be implemented by subclasses" ) if DEBUG;
94}
95
96
# spent 75.8s (1.58+74.2) within Foswiki::Store::Rcs::Store::readTopic which was called 26327 times, avg 2.88ms/call: # 26327 times (1.58s+74.2s) by Foswiki::Meta::loadVersion at line 1156 of /var/www/foswikidev/core/lib/Foswiki/Meta.pm, avg 2.88ms/call
sub readTopic {
972632711.7ms my ( $this, $topicObject, $version ) = @_;
98
992632781.1ms78981808ms my $handler = $this->getHandler( $topicObject->web, $topicObject->topic );
# spent 730ms making 26327 calls to Foswiki::Store::RcsWrap::getHandler, avg 28µs/call # spent 39.3ms making 26327 calls to Foswiki::Meta::web, avg 1µs/call # spent 39.1ms making 26327 calls to Foswiki::Meta::topic, avg 1µs/call
100263274.85ms my $isLatest = 0;
101
102 # check that the requested revision actually exists
103263279.83ms if ( defined $version && $version =~ /^\d+$/ ) {
104 if ( $version == 0 || !$handler->revisionExists($version) ) {
105 $version = $handler->getLatestRevisionID();
106 }
107 }
108 else {
109263278.19ms undef $version; # if it's a non-numeric string, we need to return undef
110 }
111
1122632778.5ms263271.27s return ( undef, undef ) unless $handler->storedDataExists();
# spent 1.27s making 26327 calls to Foswiki::Store::Rcs::Handler::storedDataExists, avg 48µs/call
113
11426327141ms263274.75s ( my $text, $isLatest ) = $handler->getRevision($version);
# spent 4.75s making 26327 calls to Foswiki::Store::Rcs::RcsWrapHandler::getRevision, avg 180µs/call
115263276.06ms $text = '' unless defined $text;
1162632751.4ms263271.48s $text = _decode($text);
# spent 1.48s making 26327 calls to Foswiki::Store::decode, avg 56µs/call
11726327152ms $text =~ s/\r//g; # Remove carriage returns
1182632733.1ms2632764.5s Foswiki::Serialise::deserialise( $text, 'Embedded', $topicObject );
# spent 64.5s making 26327 calls to Foswiki::Serialise::deserialise, avg 2.45ms/call
119
120 # Item11983 - switched off for performance reasons
121 # unless ( $handler->noCheckinPending() ) {
122 #
123 # # If a checkin is pending, fix the TOPICINFO
124 # my $ri = $topicObject->get('TOPICINFO');
125 # my $truth = $handler->getInfo($version);
126 # for my $i (qw(author version date)) {
127 # $ri->{$i} = $truth->{$i};
128 # }
129 # }
130
131 # downgrade to first revision when there's no history
1322632784.6ms263271.27s unless ( $handler->revisionHistoryExists() ) {
# spent 1.27s making 26327 calls to Foswiki::Store::Rcs::Handler::revisionHistoryExists, avg 48µs/call
133 $version = 1;
134 }
135
136263277.85ms my $gotRev = $version;
137263279.48ms unless ( defined $gotRev ) {
138
139 # First try the just-loaded for the revision.
1402630440.8ms2630478.5ms my $ri = $topicObject->get('TOPICINFO');
# spent 78.5ms making 26304 calls to Foswiki::Meta::get, avg 3µs/call
1412630421.3ms $gotRev = $ri->{version} if defined $ri;
142 }
143263272.94ms if ( !defined $gotRev ) {
144
145 # No revision from any other source; must be latest
146 $gotRev = $handler->getLatestRevisionID();
147 ASSERT( defined $gotRev ) if DEBUG;
148 }
149
150 # Add attachments that are new from reading the pub directory.
151 # Only check the currently requested topic.
1522632714.3ms if ( $Foswiki::cfg{RCS}{AutoAttachPubFiles}
153 && $topicObject->isSessionTopic() )
154 {
155 my @knownAttachments = $topicObject->find('FILEATTACHMENT');
156 my @attachmentsFoundInPub =
157 $handler->synchroniseAttachmentsList( \@knownAttachments );
158 my @validAttachmentsFound;
159 foreach my $foundAttachment (@attachmentsFoundInPub) {
160
161 # test if the attachment filename is valid without having to
162 # be sanitized. If not, ignore it.
163 my $validated = Foswiki::Sandbox::validateAttachmentName(
164 $foundAttachment->{name} );
165 unless ( defined $validated
166 && $validated eq $foundAttachment->{name} )
167 {
168
169 print STDERR 'AutoAttachPubFiles ignoring '
170 . $foundAttachment->{name} . ' in '
171 . $topicObject->getPath()
172 . ' - not a valid Foswiki Attachment filename';
173 }
174 else {
175 push @validAttachmentsFound, $foundAttachment;
176
177 # SMELL: how do we tell Meta what happened?
178 }
179 }
180
181 $topicObject->putAll( 'FILEATTACHMENT', @validAttachmentsFound )
182 if @validAttachmentsFound;
183 }
184
185263273.24ms $gotRev ||= 1; # anything going out here must be > 0
186
1872632740.6ms2632757.6ms $topicObject->setLoadStatus( $gotRev, $isLatest );
# spent 57.6ms making 26327 calls to Foswiki::Meta::setLoadStatus, avg 2µs/call
18826327180ms return ( $gotRev, $isLatest );
189}
190
191sub moveAttachment {
192 my ( $this, $oldTopicObject, $oldAttachment, $newTopicObject,
193 $newAttachment, $cUID )
194 = @_;
195
196 ASSERT($oldAttachment) if DEBUG;
197 ASSERT($newAttachment) if DEBUG;
198
199 my $handler =
200 $this->getHandler( $oldTopicObject->web, $oldTopicObject->topic,
201 $oldAttachment );
202 if ( $handler->storedDataExists() ) {
203 $handler->moveAttachment( $this, $newTopicObject->web,
204 $newTopicObject->topic, $newAttachment );
205 }
206}
207
208sub copyAttachment {
209 my ( $this, $oldTopicObject, $oldAttachment, $newTopicObject,
210 $newAttachment, $cUID )
211 = @_;
212
213 ASSERT($oldAttachment) if DEBUG;
214 ASSERT($newAttachment) if DEBUG;
215
216 my $handler =
217 $this->getHandler( $oldTopicObject->web, $oldTopicObject->topic,
218 $oldAttachment );
219 return undef unless $handler->storedDataExists();
220
221 my $rev =
222 $handler->copyAttachment( $this, $newTopicObject->web,
223 $newTopicObject->topic, $newAttachment );
224 return $rev;
225}
226
227
# spent 93µs (19+74) within Foswiki::Store::Rcs::Store::attachmentExists which was called: # once (19µs+74µs) by Foswiki::Meta::hasAttachment at line 3052 of /var/www/foswikidev/core/lib/Foswiki/Meta.pm
sub attachmentExists {
22811µs my ( $this, $topicObject, $att ) = @_;
229 ASSERT($att) if DEBUG;
23014µs337µs my $handler =
# spent 34µs making 1 call to Foswiki::Store::RcsWrap::getHandler # spent 2µs making 1 call to Foswiki::Meta::topic # spent 2µs making 1 call to Foswiki::Meta::web
231 $this->getHandler( $topicObject->web, $topicObject->topic, $att );
23218µs137µs return $handler->storedDataExists();
# spent 37µs making 1 call to Foswiki::Store::Rcs::Handler::storedDataExists
233}
234
235sub moveTopic {
236 my ( $this, $oldTopicObject, $newTopicObject, $cUID ) = @_;
237 ASSERT($cUID) if DEBUG;
238
239 my $handler =
240 $this->getHandler( $oldTopicObject->web, $oldTopicObject->topic );
241 my $rev = $handler->getLatestRevisionID();
242
243 $handler->moveTopic( $this, $newTopicObject->web, $newTopicObject->topic );
244}
245
246sub moveWeb {
247 my ( $this, $oldWebObject, $newWebObject, $cUID ) = @_;
248 ASSERT($cUID) if DEBUG;
249
250 my $handler = $this->getHandler( $oldWebObject->web );
251 $handler->moveWeb( $newWebObject->web );
252}
253
254sub testAttachment {
255 my ( $this, $topicObject, $attachment, $test ) = @_;
256 ASSERT($attachment) if DEBUG;
257 my $handler =
258 $this->getHandler( $topicObject->web, $topicObject->topic, $attachment );
259 return $handler->test($test);
260}
261
262sub openAttachment {
263 my ( $this, $topicObject, $att, $mode, @opts ) = @_;
264 ASSERT($att) if DEBUG;
265
266 my $handler =
267 $this->getHandler( $topicObject->web, $topicObject->topic, $att );
268 return $handler->openStream( $mode, @opts );
269}
270
271
# spent 731µs (31+700) within Foswiki::Store::Rcs::Store::getRevisionHistory which was called 2 times, avg 366µs/call: # 2 times (31µs+700µs) by Foswiki::Meta::getRevisionHistory at line 2503 of /var/www/foswikidev/core/lib/Foswiki/Meta.pm, avg 366µs/call
sub getRevisionHistory {
27222µs my ( $this, $topicObject, $attachment ) = @_;
273
27428µs648µs my $handler =
# spent 42µs making 2 calls to Foswiki::Store::RcsWrap::getHandler, avg 21µs/call # spent 3µs making 2 calls to Foswiki::Meta::web, avg 2µs/call # spent 3µs making 2 calls to Foswiki::Meta::topic, avg 2µs/call
275 $this->getHandler( $topicObject->web, $topicObject->topic, $attachment );
276214µs2652µs return $handler->getRevisionHistory();
# spent 652µs making 2 calls to Foswiki::Store::Rcs::Handler::getRevisionHistory, avg 326µs/call
277}
278
279sub getNextRevision {
280 my ( $this, $topicObject ) = @_;
281 my $handler = $this->getHandler( $topicObject->web, $topicObject->topic );
282 return $handler->getNextRevisionID();
283}
284
285sub getRevisionDiff {
286 my ( $this, $topicObject, $rev2, $contextLines ) = @_;
287 ASSERT( defined($contextLines) ) if DEBUG;
288
289 my $rcs = $this->getHandler( $topicObject->web, $topicObject->topic );
290 my $diffs =
291 $rcs->revisionDiff( $topicObject->getLoadedRev(), $rev2, $contextLines );
292 foreach my $d (@$diffs) {
293 foreach my $i ( 1, 2 ) {
294 _decode( $d->[$i] );
295 }
296 }
297 return $diffs;
298}
299
300sub _getAttachmentVersionInfo {
301 my ( $this, $topicObject, $rev, $attachment ) = @_;
302 ASSERT($attachment) if DEBUG;
303
304 my $info;
305
306 if ( !defined($rev) ) {
307 my $attachInfo = $topicObject->get('FILEATTACHMENT');
308
309 # rewrite to info format similar to TOPICINFO
310 if ( defined $attachInfo ) {
311 $info->{date} =
312 $attachInfo->{date}
313 || $attachInfo->{movedwhen}
314 || time();
315
316 $info->{author} =
317 $attachInfo->{user}
318 || $attachInfo->{moveby}
319 || $Foswiki::Users::BaseUserMapping::UNKNOWN_USER_CUID;
320
321 $info->{version} = 1
322 unless defined $attachInfo->{version};
323
324 $info->{comment} = $attachInfo->{comment}
325 if defined $attachInfo->{comment};
326 }
327 }
328
329 if ( !defined($info) ) {
330 my $handler =
331 $this->getHandler( $topicObject->web, $topicObject->topic,
332 $attachment );
333 $info = $handler->getInfo( $rev || 0 );
334 _decode( $info->{author} );
335 _decode( $info->{comment} );
336 }
337
338 return $info;
339}
340
341
# spent 14.9ms (94µs+14.8) within Foswiki::Store::Rcs::Store::getVersionInfo which was called 3 times, avg 4.98ms/call: # 3 times (94µs+14.8ms) by Foswiki::Meta::getRevisionInfo at line 1603 of /var/www/foswikidev/core/lib/Foswiki/Meta.pm, avg 4.98ms/call
sub getVersionInfo {
34234µs my ( $this, $topicObject, $rev, $attachment ) = @_;
3433300ns my $info;
344
3453600ns return $this->_getAttachmentVersionInfo( $topicObject, $rev, $attachment )
346 if ($attachment);
347
34834µs34µs my $loadedRev = $topicObject->getLoadedRev();
# spent 4µs making 3 calls to Foswiki::Meta::getLoadedRev, avg 1µs/call
349
350 # loadedRev may be undef even after a successful topic load in
351 # META:TOPICINFO is missing from the topic.
35233µs if ( !defined($rev) || $loadedRev eq $rev ) {
35337µs38µs if ( $topicObject->latestIsLoaded() ) {
# spent 8µs making 3 calls to Foswiki::Meta::latestIsLoaded, avg 3µs/call
354 $info = $topicObject->get('TOPICINFO');
355 }
356 else {
357 # Load into a new object to avoid blowing away the object we
358 # were passed; then selectively get the bits we want.
35938µs399µs my $dummy = Foswiki::Meta->new($topicObject);
# spent 99µs making 3 calls to Foswiki::Meta::new, avg 33µs/call
36034µs31.68ms $dummy->loadVersion();
# spent 1.68ms making 3 calls to Foswiki::Meta::loadVersion, avg 560µs/call
36134µs36µs $info = $dummy->get('TOPICINFO');
# spent 6µs making 3 calls to Foswiki::Meta::get, avg 2µs/call
36234µs318µs $topicObject->put( 'TOPICINFO', $info );
# spent 18µs making 3 calls to Foswiki::Meta::put, avg 6µs/call
363312µs313.0ms $dummy->finish();
# spent 13.0ms making 3 calls to Foswiki::Meta::finish, avg 4.35ms/call
364 }
365 }
366
36731µs if ( not defined $info ) {
368 my $handler =
369 $this->getHandler( $topicObject->web, $topicObject->topic );
370 $info = $handler->getInfo($rev);
371 _decode( $info->{author} );
372 _decode( $info->{comment} );
373 }
374
375 # make sure there's at least author, date and version
37632µs $info->{author} = $Foswiki::Users::BaseUserMapping::UNKNOWN_USER_CUID
377 unless defined $info->{author};
37832µs $info->{date} = time() unless defined $info->{date};
3793600ns $info->{version} = 1 unless defined $info->{version};
380
38138µs return $info;
382}
383
384sub saveAttachment {
385 my ( $this, $topicObject, $name, $stream, $cUID, $options ) = @_;
386 ASSERT($name) if DEBUG;
387
388 my $handler =
389 $this->getHandler( $topicObject->web, $topicObject->topic, $name );
390 my $verb = ( $topicObject->hasAttachment($name) ) ? 'update' : 'insert';
391 my $comment = $options->{comment} || '';
392
393 $comment = _encode($comment);
394 $cUID = _encode($cUID);
395
396 $handler->addRevisionFromStream( $stream, $comment, $cUID,
397 $options->{forcedate} );
398
399 my $rev = $handler->getLatestRevisionID();
400
401 return $rev;
402}
403
404sub saveTopic {
405 my ( $this, $topicObject, $cUID, $options ) = @_;
406 ASSERT( $topicObject->isa('Foswiki::Meta') ) if DEBUG;
407 ASSERT($cUID) if DEBUG;
408
409 my $handler = $this->getHandler( $topicObject->web, $topicObject->topic );
410 my $verb = ( $topicObject->existsInStore() ) ? 'update' : 'insert';
411
412 # just in case they are not sequential
413 my $nextRev = $handler->getNextRevisionID();
414 my $ti = $topicObject->get('TOPICINFO');
415
416 if ( defined $ti ) {
417 $ti->{version} = $nextRev;
418 $ti->{author} = $cUID;
419 }
420 else {
421 $topicObject->setRevisionInfo(
422 version => $nextRev,
423 author => $cUID,
424 );
425 }
426 my $comment = $options->{comment} || '';
427
428 my $text = Foswiki::Serialise::serialise( $topicObject, 'Embedded' );
429 $text = _encode($text);
430 $cUID = _encode($cUID);
431 $comment = _encode($comment);
432 $handler->addRevisionFromText( $text, $comment, $cUID,
433 $options->{forcedate} );
434
435 # reload the topic object
436 $topicObject->unload();
437 $topicObject->loadVersion();
438
439 return $nextRev;
440}
441
442sub repRev {
443 my ( $this, $topicObject, $cUID, %options ) = @_;
444
445 ASSERT( $topicObject->isa('Foswiki::Meta') ) if DEBUG;
446 ASSERT($cUID) if DEBUG;
447 my $info = $topicObject->getRevisionInfo();
448 my $handler = $this->getHandler( $topicObject->web, $topicObject->topic );
449 my $text = Foswiki::Serialise::serialise( $topicObject, 'Embedded' );
450 $text = _encode($text);
451
452 $handler->replaceRevision( $text, 'reprev', $cUID,
453 defined $options{forcedate} ? $options{forcedate} : $info->{date} );
454
455 my $rev = $handler->getLatestRevisionID();
456
457 # reload the topic object
458 $topicObject->unload();
459 $topicObject->loadVersion();
460
461 return $rev;
462}
463
464sub delRev {
465 my ( $this, $topicObject, $cUID ) = @_;
466 ASSERT( $topicObject->isa('Foswiki::Meta') ) if DEBUG;
467 ASSERT($cUID) if DEBUG;
468
469 my $handler = $this->getHandler( $topicObject->web, $topicObject->topic );
470 my $rev = $handler->getLatestRevisionID();
471 if ( $rev <= 1 ) {
472 throw Error::Simple( 'Cannot delete initial revision of '
473 . $topicObject->web . '.'
474 . $topicObject->topic );
475 }
476 $handler->deleteRevision();
477
478 # restore last topic from repository
479 $handler->restoreLatestRevision($cUID);
480
481 # reload the topic object
482 $topicObject->unload();
483 $topicObject->loadVersion();
484
485 return $rev;
486}
487
488sub atomicLockInfo {
489 my ( $this, $topicObject ) = @_;
490 my $handler = $this->getHandler( $topicObject->web, $topicObject->topic );
491 return $handler->isLocked();
492}
493
494# It would be nice to use flock to do this, but the API is unreliable
495# (doesn't work on all platforms)
496sub atomicLock {
497 my ( $this, $topicObject, $cUID ) = @_;
498 my $handler = $this->getHandler( $topicObject->web, $topicObject->topic );
499 $handler->setLock( 1, $cUID );
500}
501
502sub atomicUnlock {
503 my ( $this, $topicObject, $cUID ) = @_;
504
505 my $handler = $this->getHandler( $topicObject->web, $topicObject->topic );
506 $handler->setLock( 0, $cUID );
507}
508
509# A web _has_ to have a preferences topic to be a web.
510
# spent 6.90ms (906µs+6.00) within Foswiki::Store::Rcs::Store::webExists which was called 101 times, avg 68µs/call: # 101 times (906µs+6.00ms) by Foswiki::webExists at line 4035 of /var/www/foswikidev/core/lib/Foswiki.pm, avg 68µs/call
sub webExists {
51110148µs my ( $this, $web ) = @_;
512
51310125µs return 0 unless defined $web;
514101101µs $web =~ s#\.#/#go;
515
516 # Foswiki ships with TWikiCompatibilityPlugin but if it is disabled we
517 # do not want the TWiki web to appear as a valid web to anyone.
51810150µs if ( $web eq 'TWiki' ) {
519 unless ( exists $Foswiki::cfg{Plugins}{TWikiCompatibilityPlugin}
520 && defined $Foswiki::cfg{Plugins}{TWikiCompatibilityPlugin}{Enabled}
521 && $Foswiki::cfg{Plugins}{TWikiCompatibilityPlugin}{Enabled} == 1 )
522 {
523 return 0;
524 }
525 }
526100196µs1002.38ms my $handler = $this->getHandler( $web, $Foswiki::cfg{WebPrefsTopicName} );
# spent 2.38ms making 100 calls to Foswiki::Store::RcsWrap::getHandler, avg 24µs/call
527100331µs1003.62ms return $handler->storedDataExists();
# spent 3.62ms making 100 calls to Foswiki::Store::Rcs::Handler::storedDataExists, avg 36µs/call
528}
529
530
# spent 13.0ms (1.44+11.6) within Foswiki::Store::Rcs::Store::topicExists which was called 197 times, avg 66µs/call: # 156 times (1.17ms+9.19ms) by Foswiki::topicExists at line 4052 of /var/www/foswikidev/core/lib/Foswiki.pm, avg 66µs/call # 29 times (191µs+1.59ms) by Foswiki::Meta::existsInStore at line 722 of /var/www/foswikidev/core/lib/Foswiki/Meta.pm, avg 61µs/call # 12 times (78µs+817µs) by Foswiki::_includeTopic at line 155 of /var/www/foswikidev/core/lib/Foswiki/Macros/INCLUDE.pm, avg 75µs/call
sub topicExists {
531197145µs my ( $this, $web, $topic ) = @_;
532
53319782µs return 0 unless defined $web && $web ne '';
53419785µs $web =~ s#\.#/#go;
53519742µs return 0 unless defined $topic && $topic ne '';
536
537197226µs1974.93ms my $handler = $this->getHandler( $web, $topic );
# spent 4.93ms making 197 calls to Foswiki::Store::RcsWrap::getHandler, avg 25µs/call
538197599µs1976.67ms return $handler->storedDataExists();
# spent 6.67ms making 197 calls to Foswiki::Store::Rcs::Handler::storedDataExists, avg 34µs/call
539}
540
541# Record a change in the web history
542sub recordChange {
543 my $this = shift;
544 my %args = @_;
545
546 my $web = $args{path};
547
548 # Support for Foswiki < 2
549 my $topic = '.';
550 if ( $web =~ /\./ ) {
551 ( $web, $topic ) = Foswiki->normalizeWebTopicName( undef, $web );
552 }
553
554 my $handler = $this->getHandler($web);
555 $handler->recordChange(%args);
556}
557
558# Implement Foswiki::Store
559sub eachChange {
560 my ( $this, $meta, $since ) = @_;
561
562 my $handler = $this->getHandler( $meta->web );
563 require Foswiki::ListIterator;
564
565 my @changes;
566 @changes = reverse grep { $_->{time} >= $since } $handler->readChanges();
567 return Foswiki::ListIterator->new( \@changes );
568}
569
570sub getApproxRevTime {
571 my ( $this, $web, $topic ) = @_;
572
573 my $handler = $this->getHandler( $web, $topic );
574 return $handler->getLatestRevisionTime();
575}
576
577sub eachAttachment {
578 my ( $this, $topicObject ) = @_;
579
580 my $handler = $this->getHandler( $topicObject->web, $topicObject->topic );
581 my @list = $handler->getAttachmentList();
582 require Foswiki::ListIterator;
583 return new Foswiki::ListIterator( \@list );
584}
585
586
# spent 2.79s (7.10ms+2.78) within Foswiki::Store::Rcs::Store::eachTopic which was called 40 times, avg 69.8ms/call: # 40 times (7.10ms+2.78s) by Foswiki::Meta::eachTopic at line 1026 of /var/www/foswikidev/core/lib/Foswiki/Meta.pm, avg 69.8ms/call
sub eachTopic {
5874028µs my ( $this, $webObject ) = @_;
588
58940106µs80874µs my $handler = $this->getHandler( $webObject->web );
# spent 816µs making 40 calls to Foswiki::Store::RcsWrap::getHandler, avg 20µs/call # spent 58µs making 40 calls to Foswiki::Meta::web, avg 1µs/call
590406.30ms402.78s my @list = $handler->getTopicNames();
# spent 2.78s making 40 calls to Foswiki::Store::Rcs::Handler::getTopicNames, avg 69.6ms/call
591
5924048µs require Foswiki::ListIterator;
59340400µs40282µs return new Foswiki::ListIterator( \@list );
# spent 282µs making 40 calls to Foswiki::ListIterator::new, avg 7µs/call
594}
595
596
# spent 17.9ms (641µs+17.3) within Foswiki::Store::Rcs::Store::eachWeb which was called 26 times, avg 688µs/call: # 24 times (459µs+-459µs) by Foswiki::Store::Rcs::Store::eachWeb at line 610, avg 0s/call # 2 times (182µs+17.7ms) by Foswiki::Meta::eachWeb at line 1005 of /var/www/foswikidev/core/lib/Foswiki/Meta.pm, avg 8.95ms/call
sub eachWeb {
5972617µs my ( $this, $webObject, $all ) = @_;
598
599 # Undocumented; this fn actually accepts a web name as well. This is
600 # to make the recursion more efficient.
6012612µs23µs my $web = ref($webObject) ? $webObject->web : $webObject;
# spent 3µs making 2 calls to Foswiki::Meta::web, avg 2µs/call
602
6032631µs26645µs my $handler = $this->getHandler($web);
# spent 645µs making 26 calls to Foswiki::Store::RcsWrap::getHandler, avg 25µs/call
6042654µs2616.4ms my @list = $handler->getWebNames();
# spent 16.4ms making 26 calls to Foswiki::Store::Rcs::Handler::getWebNames, avg 632µs/call
605267µs if ($all) {
6062633µs my $root = $web ? "$web/" : '';
607263µs my @expandedList;
6082637µs while ( my $wp = shift(@list) ) {
6092412µs push( @expandedList, $wp );
6102446µs240s my $it = $this->eachWeb( $root . $wp, $all );
# spent 19.9ms making 24 calls to Foswiki::Store::Rcs::Store::eachWeb, avg 828µs/call, recursion: max depth 2, sum of overlapping time 19.9ms
6112468µs2457µs push( @expandedList, map { "$wp/$_" } $it->all() );
# spent 57µs making 24 calls to Foswiki::ListIterator::all, avg 2µs/call
612 }
6132620µs @list = @expandedList;
614 }
6152638µs @list = sort(@list);
6162610µs require Foswiki::ListIterator;
61726131µs26132µs return new Foswiki::ListIterator( \@list );
# spent 132µs making 26 calls to Foswiki::ListIterator::new, avg 5µs/call
618}
619
620sub remove {
621 my ( $this, $cUID, $topicObject, $attachment ) = @_;
622 ASSERT( $topicObject->web ) if DEBUG;
623
624 my $handler =
625 $this->getHandler( $topicObject->web, $topicObject->topic, $attachment );
626 $handler->remove();
627
628 my $more = 'Deleted ' . $topicObject->web;
629 if ( my $topic = $topicObject->topic ) {
630 $more .= '.' . $topic;
631 }
632 if ($attachment) {
633 $more .= ': ' . $attachment;
634 }
635}
636
637
# spent 108s (3.74ms+108) within Foswiki::Store::Rcs::Store::query which was called 80 times, avg 1.35s/call: # 40 times (1.72ms+108s) by Foswiki::Meta::query at line 984 of /var/www/foswikidev/core/lib/Foswiki/Meta.pm, avg 2.71s/call # 40 times (2.02ms+-2.02ms) by Foswiki::Store::QueryAlgorithms::BruteForce::_webQuery at line 166 of /var/www/foswikidev/core/lib/Foswiki/Store/QueryAlgorithms/BruteForce.pm, avg 0s/call
sub query {
6388082µs my ( $this, $query, $inputTopicSet, $session, $options ) = @_;
639
6408018µs my $engine;
64180385µs80137µs if ( $query->isa('Foswiki::Query::Node') ) {
# spent 137µs making 80 calls to UNIVERSAL::isa, avg 2µs/call
6424042µs unless ( $this->{queryObj} ) {
64311µs my $module = $Foswiki::cfg{Store}{QueryAlgorithm};
644128µs eval "require $module";
# spent 85µs executing statements in string eval
6451700ns die
646"Bad {Store}{QueryAlgorithm}; suggest you run configure and select a different algorithm\n$@"
647 if $@;
64816µs132µs $this->{queryObj} = $module->new();
# spent 32µs making 1 call to Foswiki::Store::QueryAlgorithms::BruteForce::new
649 }
6504026µs $engine = $this->{queryObj};
651 }
652 else {
653 ASSERT( $query->isa('Foswiki::Search::Node') ) if DEBUG;
6544036µs unless ( $this->{searchQueryObj} ) {
65512µs my $module = $Foswiki::cfg{Store}{SearchAlgorithm};
656127µs eval "require $module";
# spent 70µs executing statements in string eval
6571400ns die
658"Bad {Store}{SearchAlgorithm}; suggest you run configure and select a different algorithm\n$@"
659 if $@;
66015µs131µs $this->{searchQueryObj} = $module->new();
# spent 31µs making 1 call to Foswiki::Store::SearchAlgorithms::Forking::new
661 }
6624025µs $engine = $this->{searchQueryObj};
663 }
664
665240µs235µs
# spent 23µs (10+12) within Foswiki::Store::Rcs::Store::BEGIN@665 which was called: # once (10µs+12µs) by Foswiki::Store::RcsWrap::BEGIN@23 at line 665
no strict 'refs';
# spent 23µs making 1 call to Foswiki::Store::Rcs::Store::BEGIN@665 # spent 12µs making 1 call to strict::unimport
66680796µs80108s return $engine->query( $query, $inputTopicSet, $session, $options );
# spent 157s making 80 calls to Foswiki::Store::Interfaces::QueryAlgorithm::query, avg 1.97s/call, recursion: max depth 1, sum of overlapping time 49.2s
6672181µs227µs
# spent 18µs (8+9) within Foswiki::Store::Rcs::Store::BEGIN@667 which was called: # once (8µs+9µs) by Foswiki::Store::RcsWrap::BEGIN@23 at line 667
use strict 'refs';
# spent 18µs making 1 call to Foswiki::Store::Rcs::Store::BEGIN@667 # spent 9µs making 1 call to strict::import
668}
669
670sub getRevisionAtTime {
671 my ( $this, $topicObject, $time ) = @_;
672
673 my $handler = $this->getHandler( $topicObject->web, $topicObject->topic );
674 return $handler->getRevisionAtTime($time);
675}
676
677sub getLease {
678 my ( $this, $topicObject ) = @_;
679
680 my $handler = $this->getHandler( $topicObject->web, $topicObject->topic );
681 my $lease = $handler->getLease();
682 return $lease;
683}
684
685sub setLease {
686 my ( $this, $topicObject, $lease ) = @_;
687
688 my $handler = $this->getHandler( $topicObject->web, $topicObject->topic );
689 $handler->setLease($lease);
690}
691
692sub removeSpuriousLeases {
693 my ( $this, $web ) = @_;
694 my $handler = $this->getHandler($web);
695 $handler->removeSpuriousLeases();
696}
697
69813µs1;
699__END__