← 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/Serialise/Embedded.pm
StatementsExecuted 14027537 statements in 31.3s
Subroutines
Calls P F Exclusive
Time
Inclusive
Time
Subroutine
9276991124.0s31.4sFoswiki::Serialise::Embedded::::_readKeyValuesFoswiki::Serialise::Embedded::_readKeyValues
9276992113.6s55.5sFoswiki::Serialise::Embedded::::_readMETAFoswiki::Serialise::Embedded::_readMETA
26327118.34s64.2sFoswiki::Serialise::Embedded::::readFoswiki::Serialise::Embedded::read
11114µs27µsFoswiki::Serialise::Embedded::::BEGIN@16Foswiki::Serialise::Embedded::BEGIN@16
11110µs38µsFoswiki::Serialise::Embedded::::BEGIN@20Foswiki::Serialise::Embedded::BEGIN@20
11110µs14µsFoswiki::Serialise::Embedded::::BEGIN@17Foswiki::Serialise::Embedded::BEGIN@17
11110µs10µsFoswiki::Serialise::Embedded::::newFoswiki::Serialise::Embedded::new
1117µs7µsFoswiki::Serialise::Embedded::::BEGIN@18Foswiki::Serialise::Embedded::BEGIN@18
1113µs3µsFoswiki::Serialise::Embedded::::BEGIN@19Foswiki::Serialise::Embedded::BEGIN@19
0000s0sFoswiki::Serialise::Embedded::::_writeKeyValueFoswiki::Serialise::Embedded::_writeKeyValue
0000s0sFoswiki::Serialise::Embedded::::_writeTypesFoswiki::Serialise::Embedded::_writeTypes
0000s0sFoswiki::Serialise::Embedded::::dataEncodeFoswiki::Serialise::Embedded::dataEncode
0000s0sFoswiki::Serialise::Embedded::::writeFoswiki::Serialise::Embedded::write
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::Serialise::Embedded
6
7This is __the__ on disk format serialiser and deserialise for
8Foswiki topics legacy .txt format.
9
10__WARNING__ this is only for Foswiki::Meta objects.
11
12=cut
13
14package Foswiki::Serialise::Embedded;
15
16228µs241µs
# spent 27µs (14+14) within Foswiki::Serialise::Embedded::BEGIN@16 which was called: # once (14µs+14µs) by Foswiki::Serialise::_getSerialiser at line 16
use strict;
# spent 27µs making 1 call to Foswiki::Serialise::Embedded::BEGIN@16 # spent 14µs making 1 call to strict::import
17228µs219µs
# spent 14µs (10+5) within Foswiki::Serialise::Embedded::BEGIN@17 which was called: # once (10µs+5µs) by Foswiki::Serialise::_getSerialiser at line 17
use warnings;
# spent 14µs making 1 call to Foswiki::Serialise::Embedded::BEGIN@17 # spent 4µs making 1 call to warnings::import
18220µs17µs
# spent 7µs within Foswiki::Serialise::Embedded::BEGIN@18 which was called: # once (7µs+0s) by Foswiki::Serialise::_getSerialiser at line 18
use Foswiki ();
# spent 7µs making 1 call to Foswiki::Serialise::Embedded::BEGIN@18
19222µs13µs
# spent 3µs within Foswiki::Serialise::Embedded::BEGIN@19 which was called: # once (3µs+0s) by Foswiki::Serialise::_getSerialiser at line 19
use Foswiki::Meta ();
# spent 3µs making 1 call to Foswiki::Serialise::Embedded::BEGIN@19
2021.15ms267µs
# spent 38µs (10+28) within Foswiki::Serialise::Embedded::BEGIN@20 which was called: # once (10µs+28µs) by Foswiki::Serialise::_getSerialiser at line 20
use Assert;
# spent 38µs making 1 call to Foswiki::Serialise::Embedded::BEGIN@20 # spent 28µs making 1 call to Exporter::import
21
22=begin TML
23
24---++ ClassMethod new( $class, ) -> $cereal
25
26=cut
27
28
# spent 10µs within Foswiki::Serialise::Embedded::new which was called: # once (10µs+0s) by Foswiki::Serialise::_getSerialiser at line 78 of /var/www/foswikidev/core/lib/Foswiki/Serialise.pm
sub new {
291500ns my $class = shift;
3017µs my $this = bless( {}, $class );
3116µs return $this;
32}
33
34# Generate the embedded store form of the topic. The embedded store
35# form has meta-data values embedded using %META: lines. The text
36# stored in the meta is taken as the topic text.
37#
38# TODO: Soooo.... if we wanted to make a meta->setPreference('VARIABLE', 'Values...'); we would have to change this to
39# 1 see if that preference is set in the {_text} using the * Set syntax, in which case, replace that
40# 2 or let the META::PREF.. work as it does now..
41sub write {
42 my ( $this, $meta ) = @_;
43
44 ASSERT( $meta->isa('Foswiki::Meta') ) if DEBUG;
45
46 my $ti = $meta->get('TOPICINFO');
47 delete $ti->{rev} if $ti; # don't want this written
48
49 my $text = _writeTypes( $meta, 'TOPICINFO', 'TOPICPARENT' );
50 $text .= ( $meta->text() || '' );
51 my $end =
52 _writeTypes( $meta, 'FORM', 'FIELD', 'FILEATTACHMENT', 'TOPICMOVED' )
53 . _writeTypes( $meta, 'not', 'TOPICINFO', 'TOPICPARENT', 'FORM', 'FIELD',
54 'FILEATTACHMENT', 'TOPICMOVED' );
55 $text .= "\n" if $end;
56
57 $ti->{rev} = $ti->{version} if $ti;
58
59 return $text . $end;
60}
61
62
# spent 64.2s (8.34+55.9) within Foswiki::Serialise::Embedded::read which was called 26327 times, avg 2.44ms/call: # 26327 times (8.34s+55.9s) by Foswiki::Serialise::deserialise at line 54 of /var/www/foswikidev/core/lib/Foswiki/Serialise.pm, avg 2.44ms/call
sub read {
632632737.4ms my ( $this, $text, $meta ) = @_;
64
65 ASSERT( $meta->isa('Foswiki::Meta') ) if DEBUG;
66263276.10ms my $format = Foswiki::Meta::EMBEDDING_FORMAT_VERSION;
67
68 # head meta-data
69 # NO THIS CANNOT BE /g - TOPICINFO is _only_ valid as the first line!
7052653279ms263262.37s $text =~ s<^(%META:(TOPICINFO){(.*)}%\n)>
# spent 2.37s making 26326 calls to Foswiki::Serialise::Embedded::_readMETA, avg 90µs/call
71 <_readMETA($meta, $1, $2, $3, 1)>e;
72
73 # WARNING: if the TOPICINFO *looks* valid but has has unrecognisable
74 # fields in it, it will fail the Meta::isValidEmbedding test and
75 # a default TOPICINFO wil be used - but the bad TOPICINFO will be left
76 # in the topic so it looks like there are two TOPICINFOs. Admins
77 # will have to fix up the broken topic.
78
792632742.8ms2632769.8ms my $ti = $meta->get('TOPICINFO');
# spent 69.8ms making 26327 calls to Foswiki::Meta::get, avg 3µs/call
80263279.30ms if ($ti) {
812632613.5ms $format = $ti->{format} || 0;
82
83 # Make sure we update the topic format for when we save
842632612.1ms $ti->{format} = Foswiki::Meta::EMBEDDING_FORMAT_VERSION;
85
86 # Clean up SVN and other malformed rev nums. This can happen
87 # when old code (e.g. old plugins) generated the meta.
882632650.4ms26326127ms $ti->{version} = Foswiki::Store::cleanUpRevID( $ti->{version} );
# spent 127ms making 26326 calls to Foswiki::Store::cleanUpRevID, avg 5µs/call
892632616.1ms $ti->{rev} = $ti->{version}; # not used, maintained for compatibility
902632647.4ms2401964.3ms $ti->{reprev} = Foswiki::Store::cleanUpRevID( $ti->{reprev} )
# spent 64.3ms making 24019 calls to Foswiki::Store::cleanUpRevID, avg 3µs/call
91 if defined $ti->{reprev};
92 }
93 else {
94
95 #defaults..
96 }
97
98 # Other meta-data
99263275.16ms my $endMeta = 0;
10026327132ms if ( $format !~ /^[\d.]+$/ || $format < 1.1 ) {
101171µs require Foswiki::Compatibility;
102172µs if (
103 $text =~ s/^%META:([^{]+){(.*)}%\n/
1041315µs13428µs Foswiki::Compatibility::readSymmetricallyEncodedMETA(
# spent 428µs making 13 calls to Foswiki::Compatibility::readSymmetricallyEncodedMETA, avg 33µs/call
105133µs $meta, $1, $2 ); ''/gem
106 )
107 {
108 $endMeta = 1;
109 }
110 }
111 else {
112263263.52s if (
1139013731.11s90137353.1s $text =~ s<^(%META:([^{]+){(.*)}%\n)>
# spent 53.1s making 901373 calls to Foswiki::Serialise::Embedded::_readMETA, avg 59µs/call
114 <_readMETA($meta, $1, $2, $3, 0)>gem
115 )
116 {
117 $endMeta = 1;
118 }
119 }
120
121 # eat extra newlines put in to separate text from tail meta-data
1222632778.5ms $text =~ s/\n$//s if $endMeta;
123
124 # If there is no meta data then convert from old format
1252632747.5ms2632757.6ms if ( !$meta->count('TOPICINFO') ) {
# spent 57.6ms making 26327 calls to Foswiki::Meta::count, avg 2µs/call
126
127 # The T-word string must remain unchanged for the compatibility
12814µs if ( $text =~ m/<!--TWikiAttachment-->/ ) {
129 require Foswiki::Compatibility;
130 $text = Foswiki::Compatibility::migrateToFileAttachmentMacro(
131 $meta->{_session}, $meta, $text );
132 }
133
134 # The T-word string must remain unchanged for the compatibility
13513µs if ( $text =~ m/<!--TWikiCat-->/ ) {
136 require Foswiki::Compatibility;
137 $text =
138 Foswiki::Compatibility::upgradeCategoryTable( $meta->{_session},
139 $meta->{_web}, $meta->{_topic}, $meta, $text );
140 }
141 }
142 elsif ( $format eq '1.0beta' ) {
143 require Foswiki::Compatibility;
144
145 # This format used live at DrKW for a few months
146 # The T-word string must remain unchanged for the compatibility
147 if ( $text =~ m/<!--TWikiCat-->/ ) {
148 $text =
149 Foswiki::Compatibility::upgradeCategoryTable( $meta->{_session},
150 $meta->{_web}, $meta->{_topic}, $meta, $text );
151 }
152 Foswiki::Compatibility::upgradeFrom1v0beta( $meta->{_session}, $meta );
153 if ( $meta->count('TOPICMOVED') ) {
154 my $moved = $meta->get('TOPICMOVED');
155 $meta->put( 'TOPICMOVED', $moved );
156 }
157 }
158
1592632740.0ms if ( $format !~ /^[\d.]+$/ || $format < 1.1 ) {
160
161 # compatibility; topics version 1.0 and earlier equivalenced tab
162 # with three spaces. Respect that.
163130µs $text =~ s/\t/ /g;
164 }
165
16626327121ms2632775.7ms $meta->text($text);
# spent 75.9ms making 26327 calls to Foswiki::Meta::text, avg 3µs/call, recursion: max depth 1, sum of overlapping time 136µs
167}
168
169# STATIC Build a hash by parsing name=value comma separated pairs
170# SMELL: duplication of Foswiki::Attrs, using a different
171# system of escapes :-(
172
# spent 31.4s (24.0+7.40) within Foswiki::Serialise::Embedded::_readKeyValues which was called 927699 times, avg 34µs/call: # 927699 times (24.0s+7.40s) by Foswiki::Serialise::Embedded::_readMETA at line 186, avg 34µs/call
sub _readKeyValues {
173927699426ms my ($args) = @_;
17492769984.9ms my %res;
175
176 # Format of data is name='value' name1='value1' [...]
1779277016.87s12.85ms $args =~ s/\s*([^=]+)="([^"]*)"/
# spent 2.85ms making 1 call to utf8::AUTOLOAD
17833230986.17s33230987.39s $res{$1} = Foswiki::Meta::dataDecode( $2 ), ''/ge;
# spent 7.39s making 3323098 calls to Foswiki::Meta::dataDecode, avg 2µs/call
179
1809276994.10s return \%res;
181}
182
183
# spent 55.5s (13.6+41.9) within Foswiki::Serialise::Embedded::_readMETA which was called 927699 times, avg 60µs/call: # 901373 times (13.2s+39.9s) by Foswiki::Serialise::Embedded::read at line 113, avg 59µs/call # 26326 times (394ms+1.98s) by Foswiki::Serialise::Embedded::read at line 70, avg 90µs/call
sub _readMETA {
1849276991.11s my ( $meta, $expr, $type, $args, $readTOPICINFO ) = @_;
185927699241ms return $expr if $type eq 'TOPICINFO' && !$readTOPICINFO;
186927699850ms92769931.4s my $keys = _readKeyValues($args);
# spent 31.4s making 927699 calls to Foswiki::Serialise::Embedded::_readKeyValues, avg 34µs/call
187927699984ms9276996.20s if ( Foswiki::Meta::isValidEmbedding( $type, $keys ) ) {
# spent 6.20s making 927699 calls to Foswiki::Meta::isValidEmbedding, avg 7µs/call
1889274591.19s8750694.02s if ( defined( $keys->{name} ) ) {
# spent 4.02s making 875069 calls to Foswiki::Meta::putKeyed, avg 5µs/call
189
190 # save it keyed if it has a name
191 $meta->putKeyed( $type, $keys );
192 }
193 else {
1945239074.5ms52390329ms $meta->put( $type, $keys );
# spent 329ms making 52390 calls to Foswiki::Meta::put, avg 6µs/call
195 }
1969274593.66s return '';
197 }
198 else {
199240812µs return $expr;
200 }
201}
202
203# PRIVATE STATIC Write a meta-data key=value pair
204# The encoding is reversed in _readKeyValues
205sub _writeKeyValue {
206 my ( $key, $value ) = @_;
207
208 if ( defined($value) ) {
209 $value = dataEncode($value);
210 }
211 else {
212 $value = '';
213 }
214
215 return $key . '="' . $value . '"';
216}
217
218# PRIVATE STATIC: Write all the key=value pairs for the types listed
219sub _writeTypes {
220 my ( $meta, @types ) = @_;
221
222 my $text = '';
223
224 if ( $types[0] eq 'not' ) {
225
226 # write all types that are not in the list
227 my %seen;
228 @seen{@types} = ();
229 @types = (); # empty "not in list"
230 foreach my $key ( keys %$meta ) {
231 push( @types, $key )
232 unless ( exists $seen{$key} || $key =~ m/^_/ );
233 }
234 }
235
236 foreach my $type (@types) {
237 next if ( $type =~ m/^_/ );
238 my $data = $meta->{$type};
239 next if !defined $data;
240 foreach my $item (@$data) {
241 next if ( $item =~ m/^_/ );
242 my $sep = '';
243 $text .= '%META:' . $type . '{';
244 my $name = $item->{name};
245 if ($name) {
246
247 # If there's a name field, put first to make regexp
248 # based searching easier
249 $text .= _writeKeyValue( 'name', $item->{name} );
250 $sep = ' ';
251 }
252 foreach my $key ( sort keys %$item ) {
253
254 #next if ($key =~ m/^_/ );
255 if ( $key ne 'name' ) {
256 $text .= $sep;
257 $text .= _writeKeyValue( $key, $item->{$key} );
258 $sep = ' ';
259 }
260 }
261 $text .= '}%' . "\n";
262 }
263 }
264
265 return $text;
266}
267
268=begin TML
269
270---++ StaticMethod dataEncode( $uncoded ) -> $coded
271
272Encode meta-data field values, escaping out selected characters.
273The encoding is chosen to avoid problems with parsing the attribute
274values in embedded meta-data, while minimising the number of
275characters encoded so searches can still work (fairly) sensibly.
276
277The encoding has to be exported because Foswiki (and plugins) use
278encoded field data in other places e.g. RDiff, mainly as a shorthand
279for the properly parsed meta object. Some day we may be able to
280eliminate that....
281
282=cut
283
284sub dataEncode {
285 my $datum = shift;
286
287 $datum =~ s/([%"\r\n{}])/'%'.sprintf('%02x',ord($1))/ge;
288 return $datum;
289}
290
29112µs1;
292__END__