Filename | /var/www/foswiki11/lib/Foswiki/Store/VC/Store.pm |
Statements | Executed 290944 statements in 431ms |
Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
---|---|---|---|---|---|
46604 | 3 | 3 | 553ms | 2.49s | topicExists | Foswiki::Store::VC::Store::
426 | 1 | 1 | 24.0ms | 11.0s | readTopic | Foswiki::Store::VC::Store::
41 | 1 | 1 | 12.6ms | 329ms | eachTopic | Foswiki::Store::VC::Store::
81 | 2 | 2 | 3.74ms | 48.7s | query (recurses: max depth 1, inclusive time 43.5s) | Foswiki::Store::VC::Store::
102 | 2 | 2 | 3.13ms | 92.0ms | eachWeb (recurses: max depth 2, inclusive time 104ms) | Foswiki::Store::VC::Store::
177 | 1 | 1 | 1.99ms | 12.5ms | webExists | Foswiki::Store::VC::Store::
40 | 1 | 1 | 841µs | 43.5s | searchInWebMetaData | Foswiki::Store::VC::Store::
2 | 1 | 1 | 39µs | 394ms | getRevisionHistory | Foswiki::Store::VC::Store::
1 | 1 | 1 | 33µs | 35µs | finish | Foswiki::Store::VC::Store::
1 | 1 | 1 | 25µs | 136µs | attachmentExists | Foswiki::Store::VC::Store::
1 | 1 | 1 | 13µs | 25µs | BEGIN@33 | Foswiki::Store::VC::Store::
1 | 1 | 1 | 11µs | 25µs | BEGIN@517 | Foswiki::Store::VC::Store::
1 | 1 | 1 | 10µs | 16µs | BEGIN@46 | Foswiki::Store::VC::Store::
1 | 1 | 1 | 9µs | 14µs | BEGIN@34 | Foswiki::Store::VC::Store::
1 | 1 | 1 | 8µs | 18µs | BEGIN@519 | Foswiki::Store::VC::Store::
1 | 1 | 1 | 8µs | 22µs | BEGIN@39 | Foswiki::Store::VC::Store::
1 | 1 | 1 | 7µs | 114µs | BEGIN@40 | Foswiki::Store::VC::Store::
1 | 1 | 1 | 4µs | 4µs | BEGIN@42 | Foswiki::Store::VC::Store::
1 | 1 | 1 | 3µs | 3µs | BEGIN@36 | Foswiki::Store::VC::Store::
1 | 1 | 1 | 3µs | 3µs | BEGIN@44 | Foswiki::Store::VC::Store::
1 | 1 | 1 | 3µs | 3µs | BEGIN@43 | Foswiki::Store::VC::Store::
0 | 0 | 0 | 0s | 0s | atomicLock | Foswiki::Store::VC::Store::
0 | 0 | 0 | 0s | 0s | atomicLockInfo | Foswiki::Store::VC::Store::
0 | 0 | 0 | 0s | 0s | atomicUnlock | Foswiki::Store::VC::Store::
0 | 0 | 0 | 0s | 0s | copyAttachment | Foswiki::Store::VC::Store::
0 | 0 | 0 | 0s | 0s | delRev | Foswiki::Store::VC::Store::
0 | 0 | 0 | 0s | 0s | eachAttachment | Foswiki::Store::VC::Store::
0 | 0 | 0 | 0s | 0s | eachChange | Foswiki::Store::VC::Store::
0 | 0 | 0 | 0s | 0s | getApproxRevTime | Foswiki::Store::VC::Store::
0 | 0 | 0 | 0s | 0s | getAttachmentVersionInfo | Foswiki::Store::VC::Store::
0 | 0 | 0 | 0s | 0s | getHandler | Foswiki::Store::VC::Store::
0 | 0 | 0 | 0s | 0s | getLease | Foswiki::Store::VC::Store::
0 | 0 | 0 | 0s | 0s | getNextRevision | Foswiki::Store::VC::Store::
0 | 0 | 0 | 0s | 0s | getRevisionAtTime | Foswiki::Store::VC::Store::
0 | 0 | 0 | 0s | 0s | getRevisionDiff | Foswiki::Store::VC::Store::
0 | 0 | 0 | 0s | 0s | getVersionInfo | Foswiki::Store::VC::Store::
0 | 0 | 0 | 0s | 0s | moveAttachment | Foswiki::Store::VC::Store::
0 | 0 | 0 | 0s | 0s | moveTopic | Foswiki::Store::VC::Store::
0 | 0 | 0 | 0s | 0s | moveWeb | Foswiki::Store::VC::Store::
0 | 0 | 0 | 0s | 0s | openAttachment | Foswiki::Store::VC::Store::
0 | 0 | 0 | 0s | 0s | remove | Foswiki::Store::VC::Store::
0 | 0 | 0 | 0s | 0s | removeSpuriousLeases | Foswiki::Store::VC::Store::
0 | 0 | 0 | 0s | 0s | repRev | Foswiki::Store::VC::Store::
0 | 0 | 0 | 0s | 0s | saveAttachment | Foswiki::Store::VC::Store::
0 | 0 | 0 | 0s | 0s | saveTopic | Foswiki::Store::VC::Store::
0 | 0 | 0 | 0s | 0s | searchInWebContent | Foswiki::Store::VC::Store::
0 | 0 | 0 | 0s | 0s | setLease | Foswiki::Store::VC::Store::
0 | 0 | 0 | 0s | 0s | testAttachment | Foswiki::Store::VC::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::VC::Store | ||||
6 | |||||
7 | Almost-complete implementation of =Foswiki::Store=. The methods | ||||
8 | of this class implement the =Foswiki::Store= interface. | ||||
9 | |||||
10 | The store uses a "handler" class to handle all interactions with the | ||||
11 | actual version control system (and via it with the actual file system). | ||||
12 | A "handler" is created for each individual file in the file system, and | ||||
13 | this handler then brokers all requests to open, read, write etc the file. | ||||
14 | The handler object must implement the interface specified by | ||||
15 | =Foswiki::Store::VC::Handler=. | ||||
16 | |||||
17 | The main additional responsibilities of _this_ class are to support storing | ||||
18 | Foswiki meta-data in plain text files, and to ensure that the =Foswiki::Meta= | ||||
19 | for a page is maintained in synchronisation with the files on disk. | ||||
20 | |||||
21 | All that is required to create a working store is to subclass this class | ||||
22 | and override the 'new' method to specify the actual handler to use. See | ||||
23 | Foswiki::Store::RcsWrap for an example subclass. | ||||
24 | |||||
25 | For readers who are familiar with Foswiki version 1.0, the functionality | ||||
26 | in this class _previously_ resided in =Foswiki::Store=. | ||||
27 | |||||
28 | These methods are documented in the Foswiki:Store abstract base class | ||||
29 | |||||
30 | =cut | ||||
31 | |||||
32 | package Foswiki::Store::VC::Store; | ||||
33 | 2 | 25µs | 2 | 37µs | # spent 25µs (13+12) within Foswiki::Store::VC::Store::BEGIN@33 which was called:
# once (13µs+12µs) by Foswiki::Store::RcsWrap::BEGIN@23 at line 33 # spent 25µs making 1 call to Foswiki::Store::VC::Store::BEGIN@33
# spent 12µs making 1 call to strict::import |
34 | 2 | 24µs | 2 | 20µs | # spent 14µs (9+5) within Foswiki::Store::VC::Store::BEGIN@34 which was called:
# once (9µs+5µs) by Foswiki::Store::RcsWrap::BEGIN@23 at line 34 # spent 14µs making 1 call to Foswiki::Store::VC::Store::BEGIN@34
# spent 5µs making 1 call to warnings::import |
35 | |||||
36 | 2 | 32µs | 1 | 3µs | # spent 3µs within Foswiki::Store::VC::Store::BEGIN@36 which was called:
# once (3µs+0s) by Foswiki::Store::RcsWrap::BEGIN@23 at line 36 # spent 3µs making 1 call to Foswiki::Store::VC::Store::BEGIN@36 |
37 | 1 | 8µs | our @ISA = ('Foswiki::Store'); | ||
38 | |||||
39 | 2 | 31µs | 2 | 35µs | # spent 22µs (8+13) within Foswiki::Store::VC::Store::BEGIN@39 which was called:
# once (8µs+13µs) by Foswiki::Store::RcsWrap::BEGIN@23 at line 39 # spent 22µs making 1 call to Foswiki::Store::VC::Store::BEGIN@39
# spent 13µs making 1 call to Assert::import |
40 | 2 | 27µs | 2 | 220µs | # spent 114µs (7+106) within Foswiki::Store::VC::Store::BEGIN@40 which was called:
# once (7µs+106µs) by Foswiki::Store::RcsWrap::BEGIN@23 at line 40 # spent 114µs making 1 call to Foswiki::Store::VC::Store::BEGIN@40
# spent 106µs making 1 call to Error::import |
41 | |||||
42 | 2 | 18µs | 1 | 4µs | # spent 4µs within Foswiki::Store::VC::Store::BEGIN@42 which was called:
# once (4µs+0s) by Foswiki::Store::RcsWrap::BEGIN@23 at line 42 # spent 4µs making 1 call to Foswiki::Store::VC::Store::BEGIN@42 |
43 | 2 | 17µs | 1 | 3µs | # spent 3µs within Foswiki::Store::VC::Store::BEGIN@43 which was called:
# once (3µs+0s) by Foswiki::Store::RcsWrap::BEGIN@23 at line 43 # spent 3µs making 1 call to Foswiki::Store::VC::Store::BEGIN@43 |
44 | 2 | 43µs | 1 | 3µs | # spent 3µs within Foswiki::Store::VC::Store::BEGIN@44 which was called:
# once (3µs+0s) by Foswiki::Store::RcsWrap::BEGIN@23 at line 44 # spent 3µs making 1 call to Foswiki::Store::VC::Store::BEGIN@44 |
45 | |||||
46 | # spent 16µs (10+5) within Foswiki::Store::VC::Store::BEGIN@46 which was called:
# once (10µs+5µs) by Foswiki::Store::RcsWrap::BEGIN@23 at line 53 | ||||
47 | |||||
48 | # Do a dynamic 'use locale' for this module | ||||
49 | 1 | 4µs | if ( $Foswiki::cfg{UseLocale} ) { | ||
50 | 1 | 600ns | require locale; | ||
51 | 1 | 3µs | 1 | 5µs | import locale(); # spent 5µs making 1 call to locale::import |
52 | } | ||||
53 | 1 | 2.05ms | 1 | 16µs | } # spent 16µs making 1 call to Foswiki::Store::VC::Store::BEGIN@46 |
54 | |||||
55 | # Note to developers; please undef *all* fields in the object explicitly, | ||||
56 | # whether they are references or not. That way this method is "golden | ||||
57 | # documentation" of the live fields in the object. | ||||
58 | # spent 35µs (33+2) within Foswiki::Store::VC::Store::finish which was called:
# once (33µs+2µs) by Foswiki::finish at line 2163 of /var/www/foswiki11/lib/Foswiki.pm | ||||
59 | 1 | 800ns | my $this = shift; | ||
60 | 1 | 25µs | 1 | 2µs | $this->SUPER::finish(); # spent 2µs making 1 call to Foswiki::Store::finish |
61 | 1 | 4µs | undef $this->{searchFn}; | ||
62 | } | ||||
63 | |||||
64 | # PACKAGE PRIVATE | ||||
65 | # Get a handler for the given object in the store. | ||||
66 | sub getHandler { | ||||
67 | |||||
68 | #my ( $this, $web, $topic, $attachment ) = @_; | ||||
69 | ASSERT( 0, "Must be implemented by subclasses" ) if DEBUG; | ||||
70 | } | ||||
71 | |||||
72 | # spent 11.0s (24.0ms+10.9) within Foswiki::Store::VC::Store::readTopic which was called 426 times, avg 25.7ms/call:
# 426 times (24.0ms+10.9s) by Foswiki::Meta::loadVersion at line 968 of /var/www/foswiki11/lib/Foswiki/Meta.pm, avg 25.7ms/call | ||||
73 | 426 | 252µs | my ( $this, $topicObject, $version ) = @_; | ||
74 | |||||
75 | 426 | 374µs | 426 | 292µs | ASSERT( $topicObject->isa('Foswiki::Meta') ) if DEBUG; # spent 292µs making 426 calls to Assert::ASSERTS_OFF, avg 685ns/call |
76 | 426 | 616µs | 426 | 15.8ms | my $handler = $this->getHandler($topicObject); # spent 15.8ms making 426 calls to Foswiki::Store::RcsWrap::getHandler, avg 37µs/call |
77 | 426 | 94µs | my $isLatest = 0; | ||
78 | |||||
79 | # check that the requested revision actually exists | ||||
80 | 426 | 200µs | if ( defined $version && $version =~ /^\d+$/ ) { | ||
81 | if ( $version == 0 || !$handler->revisionExists($version) ) { | ||||
82 | $version = $handler->getLatestRevisionID(); | ||||
83 | } | ||||
84 | } | ||||
85 | else { | ||||
86 | 426 | 144µs | undef $version; # if it's a non-numeric string, we need to return undef | ||
87 | # "...$version is defined but refers to a version that does not exist, then $rev is undef" | ||||
88 | } | ||||
89 | |||||
90 | 426 | 1.96ms | 426 | 48.0ms | ( my $text, $isLatest ) = $handler->getRevision($version); # spent 48.0ms making 426 calls to Foswiki::Store::VC::RcsWrapHandler::getRevision, avg 113µs/call |
91 | 426 | 121µs | return ( undef, $isLatest ) unless defined $text; | ||
92 | |||||
93 | 426 | 1.63ms | $text =~ s/\r//g; # Remove carriage returns | ||
94 | 426 | 1.22ms | 426 | 772ms | $topicObject->setEmbeddedStoreForm($text); # spent 772ms making 426 calls to Foswiki::Meta::setEmbeddedStoreForm, avg 1.81ms/call |
95 | |||||
96 | 426 | 981µs | 426 | 9.33ms | unless ( $handler->noCheckinPending() ) { # spent 9.33ms making 426 calls to Foswiki::Store::VC::Handler::noCheckinPending, avg 22µs/call |
97 | |||||
98 | # If a checkin is pending, fix the TOPICINFO | ||||
99 | 22 | 55µs | 22 | 183µs | my $ri = $topicObject->get('TOPICINFO'); # spent 183µs making 22 calls to Foswiki::Meta::get, avg 8µs/call |
100 | 22 | 113µs | 22 | 10.1s | my $truth = $handler->getInfo($version); # spent 10.1s making 22 calls to Foswiki::Store::VC::RcsWrapHandler::getInfo, avg 459ms/call |
101 | 22 | 143µs | for my $i (qw(author version date)) { | ||
102 | 66 | 184µs | $ri->{$i} = $truth->{$i}; | ||
103 | } | ||||
104 | } | ||||
105 | |||||
106 | 426 | 130µs | my $gotRev = $version; | ||
107 | 426 | 200µs | unless ( defined $gotRev ) { | ||
108 | |||||
109 | # First try the just-loaded for the revision | ||||
110 | 426 | 943µs | 426 | 3.37ms | my $ri = $topicObject->get('TOPICINFO'); # spent 3.37ms making 426 calls to Foswiki::Meta::get, avg 8µs/call |
111 | 426 | 410µs | $gotRev = $ri->{version} if defined $ri; | ||
112 | } | ||||
113 | 426 | 76µs | if ( !defined $gotRev ) { | ||
114 | |||||
115 | # No revision from any other source; must be latest | ||||
116 | 1 | 19µs | 1 | 79µs | $gotRev = $handler->getLatestRevisionID(); # spent 79µs making 1 call to Foswiki::Store::VC::Handler::getLatestRevisionID |
117 | 1 | 3µs | 1 | 3µs | ASSERT( defined $gotRev ) if DEBUG; # spent 3µs making 1 call to Assert::ASSERTS_OFF |
118 | } | ||||
119 | |||||
120 | # Add attachments that are new from reading the pub directory. | ||||
121 | # Only check the currently requested topic. | ||||
122 | 426 | 308µs | if ( $Foswiki::cfg{RCS}{AutoAttachPubFiles} | ||
123 | && $topicObject->isSessionTopic() ) | ||||
124 | { | ||||
125 | my @knownAttachments = $topicObject->find('FILEATTACHMENT'); | ||||
126 | my @attachmentsFoundInPub = | ||||
127 | $handler->synchroniseAttachmentsList( \@knownAttachments ); | ||||
128 | my @validAttachmentsFound; | ||||
129 | foreach my $foundAttachment (@attachmentsFoundInPub) { | ||||
130 | |||||
131 | # test if the attachment filename is valid without having to | ||||
132 | # be sanitized. If not, ignore it. | ||||
133 | my $validated = Foswiki::Sandbox::validateAttachmentName( | ||||
134 | $foundAttachment->{name} ); | ||||
135 | unless ( defined $validated | ||||
136 | && $validated eq $foundAttachment->{name} ) | ||||
137 | { | ||||
138 | |||||
139 | print STDERR 'AutoAttachPubFiles ignoring ' | ||||
140 | . $foundAttachment->{name} . ' in ' | ||||
141 | . $topicObject->getPath() | ||||
142 | . ' - not a valid Foswiki Attachment filename'; | ||||
143 | } | ||||
144 | else { | ||||
145 | push @validAttachmentsFound, $foundAttachment; | ||||
146 | } | ||||
147 | } | ||||
148 | |||||
149 | $topicObject->putAll( 'FILEATTACHMENT', @validAttachmentsFound ) | ||||
150 | if @validAttachmentsFound; | ||||
151 | } | ||||
152 | |||||
153 | 426 | 1.55ms | return ( $gotRev, $isLatest ); | ||
154 | } | ||||
155 | |||||
156 | sub moveAttachment { | ||||
157 | my ( $this, $oldTopicObject, $oldAttachment, $newTopicObject, | ||||
158 | $newAttachment, $cUID ) | ||||
159 | = @_; | ||||
160 | |||||
161 | my $handler = $this->getHandler( $oldTopicObject, $oldAttachment ); | ||||
162 | if ( $handler->storedDataExists() ) { | ||||
163 | $handler->moveAttachment( $this, $newTopicObject->web, | ||||
164 | $newTopicObject->topic, $newAttachment ); | ||||
165 | $handler->recordChange( $cUID, 0 ); | ||||
166 | } | ||||
167 | } | ||||
168 | |||||
169 | sub copyAttachment { | ||||
170 | my ( $this, $oldTopicObject, $oldAttachment, $newTopicObject, | ||||
171 | $newAttachment, $cUID ) | ||||
172 | = @_; | ||||
173 | |||||
174 | my $handler = $this->getHandler( $oldTopicObject, $oldAttachment ); | ||||
175 | if ( $handler->storedDataExists() ) { | ||||
176 | $handler->copyAttachment( $this, $newTopicObject->web, | ||||
177 | $newTopicObject->topic, $newAttachment ); | ||||
178 | $handler->recordChange( $cUID, 0 ); | ||||
179 | } | ||||
180 | } | ||||
181 | |||||
182 | # spent 136µs (25+111) within Foswiki::Store::VC::Store::attachmentExists which was called:
# once (25µs+111µs) by Foswiki::Meta::hasAttachment at line 2821 of /var/www/foswiki11/lib/Foswiki/Meta.pm | ||||
183 | 1 | 2µs | my ( $this, $topicObject, $att ) = @_; | ||
184 | 1 | 2µs | 1 | 97µs | my $handler = $this->getHandler( $topicObject, $att ); # spent 97µs making 1 call to Foswiki::Store::RcsWrap::getHandler |
185 | 1 | 12µs | 1 | 14µs | return $handler->storedDataExists(); # spent 14µs making 1 call to Foswiki::Store::VC::Handler::storedDataExists |
186 | } | ||||
187 | |||||
188 | sub moveTopic { | ||||
189 | my ( $this, $oldTopicObject, $newTopicObject, $cUID ) = @_; | ||||
190 | ASSERT($cUID) if DEBUG; | ||||
191 | |||||
192 | my $handler = $this->getHandler( $oldTopicObject, '' ); | ||||
193 | my $rev = $handler->getLatestRevisionID(); | ||||
194 | |||||
195 | $handler->moveTopic( $this, $newTopicObject->web, $newTopicObject->topic ); | ||||
196 | |||||
197 | if ( $newTopicObject->web ne $oldTopicObject->web ) { | ||||
198 | |||||
199 | # Record that it was moved away | ||||
200 | $handler->recordChange( $cUID, $rev ); | ||||
201 | } | ||||
202 | |||||
203 | $handler = $this->getHandler( $newTopicObject, '' ); | ||||
204 | $handler->recordChange( $cUID, $rev ); | ||||
205 | } | ||||
206 | |||||
207 | sub moveWeb { | ||||
208 | my ( $this, $oldWebObject, $newWebObject, $cUID ) = @_; | ||||
209 | ASSERT($cUID) if DEBUG; | ||||
210 | |||||
211 | my $handler = $this->getHandler($oldWebObject); | ||||
212 | $handler->moveWeb( $newWebObject->web ); | ||||
213 | |||||
214 | # We have to log in the new web, otherwise we would re-create the dir with | ||||
215 | # a useless .changes. See Item9278 | ||||
216 | $handler = $this->getHandler($newWebObject); | ||||
217 | $handler->recordChange( $cUID, 0, 'Moved from ' . $oldWebObject->web ); | ||||
218 | } | ||||
219 | |||||
220 | sub testAttachment { | ||||
221 | my ( $this, $topicObject, $attachment, $test ) = @_; | ||||
222 | my $handler = $this->getHandler( $topicObject, $attachment ); | ||||
223 | return $handler->test($test); | ||||
224 | } | ||||
225 | |||||
226 | sub openAttachment { | ||||
227 | my ( $this, $topicObject, $att, $mode, @opts ) = @_; | ||||
228 | |||||
229 | my $handler = $this->getHandler( $topicObject, $att ); | ||||
230 | return $handler->openStream( $mode, @opts ); | ||||
231 | } | ||||
232 | |||||
233 | # spent 394ms (39µs+394) within Foswiki::Store::VC::Store::getRevisionHistory which was called 2 times, avg 197ms/call:
# 2 times (39µs+394ms) by Foswiki::Meta::getRevisionHistory at line 2341 of /var/www/foswiki11/lib/Foswiki/Meta.pm, avg 197ms/call | ||||
234 | 2 | 2µs | my ( $this, $topicObject, $attachment ) = @_; | ||
235 | |||||
236 | 2 | 5µs | 2 | 70µs | my $handler = $this->getHandler( $topicObject, $attachment ); # spent 70µs making 2 calls to Foswiki::Store::RcsWrap::getHandler, avg 35µs/call |
237 | 2 | 28µs | 2 | 394ms | return $handler->getRevisionHistory(); # spent 394ms making 2 calls to Foswiki::Store::VC::Handler::getRevisionHistory, avg 197ms/call |
238 | } | ||||
239 | |||||
240 | sub getNextRevision { | ||||
241 | my ( $this, $topicObject ) = @_; | ||||
242 | my $handler = $this->getHandler($topicObject); | ||||
243 | return $handler->getNextRevisionID(); | ||||
244 | } | ||||
245 | |||||
246 | sub getRevisionDiff { | ||||
247 | my ( $this, $topicObject, $rev2, $contextLines ) = @_; | ||||
248 | ASSERT( defined($contextLines) ) if DEBUG; | ||||
249 | |||||
250 | my $rcs = $this->getHandler($topicObject); | ||||
251 | return $rcs->revisionDiff( $topicObject->getLoadedRev(), $rev2, | ||||
252 | $contextLines ); | ||||
253 | } | ||||
254 | |||||
255 | sub getAttachmentVersionInfo { | ||||
256 | my ( $this, $topicObject, $rev, $attachment ) = @_; | ||||
257 | my $handler = $this->getHandler( $topicObject, $attachment ); | ||||
258 | return $handler->getInfo( $rev || 0 ); | ||||
259 | } | ||||
260 | |||||
261 | sub getVersionInfo { | ||||
262 | my ( $this, $topicObject ) = @_; | ||||
263 | my $handler = $this->getHandler($topicObject); | ||||
264 | return $handler->getInfo( $topicObject->getLoadedRev() ); | ||||
265 | } | ||||
266 | |||||
267 | sub saveAttachment { | ||||
268 | my ( $this, $topicObject, $name, $stream, $cUID, $comment ) = @_; | ||||
269 | my $handler = $this->getHandler( $topicObject, $name ); | ||||
270 | my $currentRev = $handler->getLatestRevisionID(); | ||||
271 | my $nextRev = $currentRev + 1; | ||||
272 | $handler->addRevisionFromStream( $stream, $comment, $cUID ); | ||||
273 | $handler->recordChange( $cUID, $nextRev ); | ||||
274 | return $nextRev; | ||||
275 | } | ||||
276 | |||||
277 | sub saveTopic { | ||||
278 | my ( $this, $topicObject, $cUID, $options ) = @_; | ||||
279 | ASSERT( $topicObject->isa('Foswiki::Meta') ) if DEBUG; | ||||
280 | ASSERT($cUID) if DEBUG; | ||||
281 | |||||
282 | my $handler = $this->getHandler($topicObject); | ||||
283 | |||||
284 | # just in case they are not sequential | ||||
285 | my $nextRev = $handler->getNextRevisionID(); | ||||
286 | my $ti = $topicObject->get('TOPICINFO'); | ||||
287 | $ti->{version} = $nextRev; | ||||
288 | $ti->{author} = $cUID; | ||||
289 | |||||
290 | $handler->addRevisionFromText( $topicObject->getEmbeddedStoreForm(), | ||||
291 | 'save topic', $cUID, $options->{forcedate} ); | ||||
292 | |||||
293 | my $extra = $options->{minor} ? 'minor' : ''; | ||||
294 | $handler->recordChange( $cUID, $nextRev, $extra ); | ||||
295 | |||||
296 | return $nextRev; | ||||
297 | } | ||||
298 | |||||
299 | sub repRev { | ||||
300 | my ( $this, $topicObject, $cUID, %options ) = @_; | ||||
301 | ASSERT( $topicObject->isa('Foswiki::Meta') ) if DEBUG; | ||||
302 | ASSERT($cUID) if DEBUG; | ||||
303 | my $info = $topicObject->getRevisionInfo(); | ||||
304 | my $handler = $this->getHandler($topicObject); | ||||
305 | $handler->replaceRevision( $topicObject->getEmbeddedStoreForm(), | ||||
306 | 'reprev', $cUID, $info->{date} ); | ||||
307 | my $rev = $handler->getLatestRevisionID(); | ||||
308 | $handler->recordChange( $cUID, $rev, 'minor, reprev' ); | ||||
309 | return $rev; | ||||
310 | } | ||||
311 | |||||
312 | sub delRev { | ||||
313 | my ( $this, $topicObject, $cUID ) = @_; | ||||
314 | ASSERT( $topicObject->isa('Foswiki::Meta') ) if DEBUG; | ||||
315 | ASSERT($cUID) if DEBUG; | ||||
316 | |||||
317 | my $handler = $this->getHandler($topicObject); | ||||
318 | my $rev = $handler->getLatestRevisionID(); | ||||
319 | if ( $rev <= 1 ) { | ||||
320 | throw Error::Simple( 'Cannot delete initial revision of ' | ||||
321 | . $topicObject->web . '.' | ||||
322 | . $topicObject->topic ); | ||||
323 | } | ||||
324 | $handler->deleteRevision(); | ||||
325 | |||||
326 | # restore last topic from repository | ||||
327 | $handler->restoreLatestRevision($cUID); | ||||
328 | |||||
329 | $handler->recordChange( $cUID, $rev ); | ||||
330 | |||||
331 | return $rev; | ||||
332 | } | ||||
333 | |||||
334 | sub atomicLockInfo { | ||||
335 | my ( $this, $topicObject ) = @_; | ||||
336 | my $handler = $this->getHandler($topicObject); | ||||
337 | return $handler->isLocked(); | ||||
338 | } | ||||
339 | |||||
340 | # It would be nice to use flock to do this, but the API is unreliable | ||||
341 | # (doesn't work on all platforms) | ||||
342 | sub atomicLock { | ||||
343 | my ( $this, $topicObject, $cUID ) = @_; | ||||
344 | my $handler = $this->getHandler($topicObject); | ||||
345 | $handler->setLock( 1, $cUID ); | ||||
346 | } | ||||
347 | |||||
348 | sub atomicUnlock { | ||||
349 | my ( $this, $topicObject, $cUID ) = @_; | ||||
350 | |||||
351 | my $handler = $this->getHandler($topicObject); | ||||
352 | $handler->setLock( 0, $cUID ); | ||||
353 | } | ||||
354 | |||||
355 | # A web _has_ to have a preferences topic to be a web. | ||||
356 | # spent 12.5ms (1.99+10.5) within Foswiki::Store::VC::Store::webExists which was called 177 times, avg 71µs/call:
# 177 times (1.99ms+10.5ms) by Foswiki::webExists at line 3751 of /var/www/foswiki11/lib/Foswiki.pm, avg 71µs/call | ||||
357 | 177 | 134µs | my ( $this, $web ) = @_; | ||
358 | |||||
359 | 177 | 44µs | return 0 unless defined $web; | ||
360 | 177 | 128µs | $web =~ s#\.#/#go; | ||
361 | |||||
362 | # Foswiki ships with TWikiCompatibilityPlugin but if it is disabled we | ||||
363 | # do not want the TWiki web to appear as a valid web to anyone. | ||||
364 | 177 | 80µs | if ( $web eq 'TWiki' ) { | ||
365 | unless ( exists $Foswiki::cfg{Plugins}{TWikiCompatibilityPlugin} | ||||
366 | && defined $Foswiki::cfg{Plugins}{TWikiCompatibilityPlugin}{Enabled} | ||||
367 | && $Foswiki::cfg{Plugins}{TWikiCompatibilityPlugin}{Enabled} == 1 ) | ||||
368 | { | ||||
369 | return 0; | ||||
370 | } | ||||
371 | } | ||||
372 | |||||
373 | 176 | 435µs | 176 | 8.38ms | my $handler = $this->getHandler( $web, $Foswiki::cfg{WebPrefsTopicName} ); # spent 8.38ms making 176 calls to Foswiki::Store::RcsWrap::getHandler, avg 48µs/call |
374 | 176 | 803µs | 176 | 2.12ms | return $handler->storedDataExists(); # spent 2.12ms making 176 calls to Foswiki::Store::VC::Handler::storedDataExists, avg 12µs/call |
375 | } | ||||
376 | |||||
377 | # spent 2.49s (553ms+1.94) within Foswiki::Store::VC::Store::topicExists which was called 46604 times, avg 53µs/call:
# 46261 times (550ms+1.92s) by Foswiki::topicExists at line 3768 of /var/www/foswiki11/lib/Foswiki.pm, avg 53µs/call
# 336 times (2.99ms+17.2ms) by Foswiki::Meta::existsInStore at line 637 of /var/www/foswiki11/lib/Foswiki/Meta.pm, avg 60µs/call
# 7 times (63µs+416µs) by Foswiki::INCLUDE at line 182 of /var/www/foswiki11/lib/Foswiki/Macros/INCLUDE.pm, avg 69µs/call | ||||
378 | 46604 | 27.3ms | my ( $this, $web, $topic ) = @_; | ||
379 | |||||
380 | 46604 | 17.8ms | return 0 unless defined $web && $web ne ''; | ||
381 | 46604 | 19.9ms | $web =~ s#\.#/#go; | ||
382 | 46604 | 6.69ms | return 0 unless defined $topic && $topic ne ''; | ||
383 | |||||
384 | 46604 | 65.4ms | 46604 | 1.51s | my $handler = $this->getHandler( $web, $topic ); # spent 1.51s making 46604 calls to Foswiki::Store::RcsWrap::getHandler, avg 32µs/call |
385 | 46604 | 266ms | 46604 | 425ms | return $handler->storedDataExists(); # spent 425ms making 46604 calls to Foswiki::Store::VC::Handler::storedDataExists, avg 9µs/call |
386 | } | ||||
387 | |||||
388 | sub getApproxRevTime { | ||||
389 | my ( $this, $web, $topic ) = @_; | ||||
390 | |||||
391 | my $handler = $this->getHandler( $web, $topic ); | ||||
392 | return $handler->getLatestRevisionTime(); | ||||
393 | } | ||||
394 | |||||
395 | sub eachChange { | ||||
396 | my ( $this, $webObject, $time ) = @_; | ||||
397 | |||||
398 | my $handler = $this->getHandler($webObject); | ||||
399 | return $handler->eachChange($time); | ||||
400 | } | ||||
401 | |||||
402 | sub eachAttachment { | ||||
403 | my ( $this, $topicObject ) = @_; | ||||
404 | |||||
405 | my $handler = $this->getHandler($topicObject); | ||||
406 | my @list = $handler->getAttachmentList(); | ||||
407 | require Foswiki::ListIterator; | ||||
408 | return new Foswiki::ListIterator( \@list ); | ||||
409 | } | ||||
410 | |||||
411 | # spent 329ms (12.6+317) within Foswiki::Store::VC::Store::eachTopic which was called 41 times, avg 8.03ms/call:
# 41 times (12.6ms+317ms) by Foswiki::Meta::eachTopic at line 882 of /var/www/foswiki11/lib/Foswiki/Meta.pm, avg 8.03ms/call | ||||
412 | 41 | 35µs | my ( $this, $webObject ) = @_; | ||
413 | |||||
414 | 41 | 72µs | 41 | 1.37ms | my $handler = $this->getHandler($webObject); # spent 1.37ms making 41 calls to Foswiki::Store::RcsWrap::getHandler, avg 33µs/call |
415 | 41 | 6.98ms | 41 | 315ms | my @list = $handler->getTopicNames(); # spent 315ms making 41 calls to Foswiki::Store::VC::Handler::getTopicNames, avg 7.68ms/call |
416 | |||||
417 | 41 | 56µs | require Foswiki::ListIterator; | ||
418 | 41 | 487µs | 41 | 498µs | return new Foswiki::ListIterator( \@list ); # spent 498µs making 41 calls to Foswiki::ListIterator::new, avg 12µs/call |
419 | } | ||||
420 | |||||
421 | # spent 92.0ms (3.13+88.9) within Foswiki::Store::VC::Store::eachWeb which was called 102 times, avg 902µs/call:
# 100 times (2.40ms+-2.40ms) by Foswiki::Store::VC::Store::eachWeb at line 435, avg 0s/call
# 2 times (724µs+91.3ms) by Foswiki::Meta::eachWeb at line 860 of /var/www/foswiki11/lib/Foswiki/Meta.pm, avg 46.0ms/call | ||||
422 | 102 | 81µs | my ( $this, $webObject, $all ) = @_; | ||
423 | |||||
424 | # Undocumented; this fn actually accepts a web name as well. This is | ||||
425 | # to make the recursion more efficient. | ||||
426 | 102 | 46µs | 2 | 7µs | my $web = ref($webObject) ? $webObject->web : $webObject; # spent 7µs making 2 calls to Foswiki::Meta::web, avg 4µs/call |
427 | |||||
428 | 102 | 147µs | 102 | 3.67ms | my $handler = $this->getHandler($web); # spent 3.67ms making 102 calls to Foswiki::Store::RcsWrap::getHandler, avg 36µs/call |
429 | 102 | 253µs | 102 | 83.8ms | my @list = $handler->getWebNames(); # spent 83.8ms making 102 calls to Foswiki::Store::VC::Handler::getWebNames, avg 822µs/call |
430 | 102 | 38µs | if ($all) { | ||
431 | 102 | 96µs | my $root = $web ? "$web/" : ''; | ||
432 | 102 | 13µs | my @expandedList; | ||
433 | 102 | 183µs | while ( my $wp = shift(@list) ) { | ||
434 | 100 | 58µs | push( @expandedList, $wp ); | ||
435 | 100 | 202µs | 100 | 0s | my $it = $this->eachWeb( $root . $wp, $all ); # spent 104ms making 100 calls to Foswiki::Store::VC::Store::eachWeb, avg 1.04ms/call, recursion: max depth 2, sum of overlapping time 104ms |
436 | 100 | 369µs | 100 | 310µs | push( @expandedList, map { "$wp/$_" } $it->all() ); # spent 310µs making 100 calls to Foswiki::ListIterator::all, avg 3µs/call |
437 | } | ||||
438 | 102 | 116µs | @list = @expandedList; | ||
439 | } | ||||
440 | 102 | 295µs | @list = sort(@list); | ||
441 | 102 | 50µs | require Foswiki::ListIterator; | ||
442 | 102 | 660µs | 102 | 1.11ms | return new Foswiki::ListIterator( \@list ); # spent 1.11ms making 102 calls to Foswiki::ListIterator::new, avg 11µs/call |
443 | } | ||||
444 | |||||
445 | sub remove { | ||||
446 | my ( $this, $cUID, $topicObject, $attachment ) = @_; | ||||
447 | ASSERT( $topicObject->web ) if DEBUG; | ||||
448 | |||||
449 | my $handler = $this->getHandler( $topicObject, $attachment ); | ||||
450 | $handler->remove(); | ||||
451 | |||||
452 | # Only log when deleting topics or attachment, otherwise we would re-create | ||||
453 | # an empty directory with just a .changes. See Item9278 | ||||
454 | if ( my $topic = $topicObject->topic ) { | ||||
455 | $handler->recordChange( $cUID, 0, 'Deleted ' . $topic ); | ||||
456 | } | ||||
457 | elsif ($attachment) { | ||||
458 | $handler->recordChange( $cUID, 0, 'Deleted attachment ' . $attachment ); | ||||
459 | } | ||||
460 | } | ||||
461 | |||||
462 | #also deprecated. (use Foswiki::Meta::query) | ||||
463 | # spent 43.5s (841µs+43.5) within Foswiki::Store::VC::Store::searchInWebMetaData which was called 40 times, avg 1.09s/call:
# 40 times (841µs+43.5s) by Foswiki::Store::QueryAlgorithms::BruteForce::_webQuery at line 192 of /var/www/foswiki11/lib/Foswiki/Store/QueryAlgorithms/BruteForce.pm, avg 1.09s/call | ||||
464 | 40 | 72µs | my ( $this, $query, $webs, $inputTopicSet, $session, $options ) = @_; | ||
465 | 40 | 52µs | 40 | 44µs | ASSERT($query); # spent 44µs making 40 calls to Assert::dummyASSERT, avg 1µs/call |
466 | 40 | 318µs | 120 | 132µs | ASSERT( UNIVERSAL::isa( $query, 'Foswiki::Query::Node' ) # spent 107µs making 80 calls to UNIVERSAL::isa, avg 1µs/call
# spent 25µs making 40 calls to Assert::dummyASSERT, avg 618ns/call |
467 | || UNIVERSAL::isa( $query, 'Foswiki::Search::Node' ) ); | ||||
468 | |||||
469 | 40 | 39µs | $options->{web} = $webs; | ||
470 | 40 | 388µs | 40 | 0s | return $this->query( $query, $inputTopicSet, $session, $options ); # spent 43.5s making 40 calls to Foswiki::Store::VC::Store::query, avg 1.09s/call, recursion: max depth 1, sum of overlapping time 43.5s |
471 | } | ||||
472 | |||||
473 | #also deprecated. (use Foswiki::Meta::query) | ||||
474 | #yes, this code is identical to Foswiki::Func::searchInWebContent | ||||
475 | sub searchInWebContent { | ||||
476 | my ( $this, $searchString, $webs, $topics, $session, $options ) = @_; | ||||
477 | |||||
478 | #my $inputTopicSet = new Foswiki::ListIterator($topics); | ||||
479 | #return $handler->searchInWebContent( $searchString, $web, $inputTopicSet, | ||||
480 | # $session, $options ); | ||||
481 | my $inputTopicSet; | ||||
482 | if ($topics) { | ||||
483 | $inputTopicSet = new Foswiki::ListIterator($topics); | ||||
484 | } | ||||
485 | $options->{web} = $webs; | ||||
486 | my $query = $session->search->parseSearch( $searchString, $options ); | ||||
487 | |||||
488 | return Foswiki::Meta::query( $query, $inputTopicSet, $session, $options ); | ||||
489 | } | ||||
490 | |||||
491 | # spent 48.7s (3.74ms+48.7) within Foswiki::Store::VC::Store::query which was called 81 times, avg 601ms/call:
# 41 times (2.06ms+48.7s) by Foswiki::Meta::query at line 839 of /var/www/foswiki11/lib/Foswiki/Meta.pm, avg 1.19s/call
# 40 times (1.68ms+-1.68ms) by Foswiki::Store::VC::Store::searchInWebMetaData at line 470, avg 0s/call | ||||
492 | 81 | 58µs | my ( $this, $query, $inputTopicSet, $session, $options ) = @_; | ||
493 | |||||
494 | 81 | 14µs | my $engine; | ||
495 | 81 | 84µs | if ( $options->{type} eq 'query' ) { | ||
496 | 41 | 35µs | unless ( $this->{queryFn} ) { | ||
497 | 1 | 30µs | eval "require $Foswiki::cfg{Store}{QueryAlgorithm}"; # spent 90µs executing statements in string eval | ||
498 | 1 | 700ns | die | ||
499 | "Bad {Store}{QueryAlgorithm}; suggest you run configure and select a different algorithm\n$@" | ||||
500 | if $@; | ||||
501 | 1 | 4µs | $this->{queryFn} = $Foswiki::cfg{Store}{QueryAlgorithm} . '::query'; | ||
502 | } | ||||
503 | 41 | 55µs | $engine = $this->{queryFn}; | ||
504 | } | ||||
505 | else { | ||||
506 | 40 | 21µs | unless ( $this->{searchQueryFn} ) { | ||
507 | 1 | 26µs | eval "require $Foswiki::cfg{Store}{SearchAlgorithm}"; # spent 70µs executing statements in string eval | ||
508 | 1 | 600ns | die | ||
509 | "Bad {Store}{SearchAlgorithm}; suggest you run configure and select a different algorithm\n$@" | ||||
510 | if $@; | ||||
511 | 1 | 4µs | $this->{searchQueryFn} = | ||
512 | $Foswiki::cfg{Store}{SearchAlgorithm} . '::query'; | ||||
513 | } | ||||
514 | 40 | 30µs | $engine = $this->{searchQueryFn}; | ||
515 | } | ||||
516 | |||||
517 | 2 | 39µs | 2 | 40µs | # spent 25µs (11+14) within Foswiki::Store::VC::Store::BEGIN@517 which was called:
# once (11µs+14µs) by Foswiki::Store::RcsWrap::BEGIN@23 at line 517 # spent 25µs making 1 call to Foswiki::Store::VC::Store::BEGIN@517
# spent 14µs making 1 call to strict::unimport |
518 | 81 | 889µs | 81 | 92.2s | return &{$engine}( $query, $inputTopicSet, $session, $options ); # spent 48.7s making 41 calls to Foswiki::Store::QueryAlgorithms::BruteForce::query, avg 1.19s/call
# spent 43.5s making 40 calls to Foswiki::Store::SearchAlgorithms::Forking::query, avg 1.09s/call |
519 | 2 | 180µs | 2 | 27µs | # spent 18µs (8+9) within Foswiki::Store::VC::Store::BEGIN@519 which was called:
# once (8µs+9µs) by Foswiki::Store::RcsWrap::BEGIN@23 at line 519 # spent 18µs making 1 call to Foswiki::Store::VC::Store::BEGIN@519
# spent 9µs making 1 call to strict::import |
520 | } | ||||
521 | |||||
522 | sub getRevisionAtTime { | ||||
523 | my ( $this, $topicObject, $time ) = @_; | ||||
524 | |||||
525 | my $handler = $this->getHandler($topicObject); | ||||
526 | return $handler->getRevisionAtTime($time); | ||||
527 | } | ||||
528 | |||||
529 | sub getLease { | ||||
530 | my ( $this, $topicObject ) = @_; | ||||
531 | |||||
532 | my $handler = $this->getHandler($topicObject); | ||||
533 | my $lease = $handler->getLease(); | ||||
534 | return $lease; | ||||
535 | } | ||||
536 | |||||
537 | sub setLease { | ||||
538 | my ( $this, $topicObject, $lease ) = @_; | ||||
539 | |||||
540 | my $handler = $this->getHandler($topicObject); | ||||
541 | $handler->setLease($lease); | ||||
542 | } | ||||
543 | |||||
544 | sub removeSpuriousLeases { | ||||
545 | my ( $this, $web ) = @_; | ||||
546 | my $handler = $this->getHandler($web); | ||||
547 | $handler->removeSpuriousLeases(); | ||||
548 | } | ||||
549 | |||||
550 | 1 | 3µs | 1; | ||
551 | __END__ |