| Filename | /home/doy/perl5/perlbrew/perls/perl-5.10.1/lib/site_perl/5.10.1/KiokuDB/Linker.pm |
| Statements | Executed 29 statements in 7.59ms |
| Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
|---|---|---|---|---|---|
| 1 | 1 | 1 | 1.60ms | 71.5ms | KiokuDB::Linker::BEGIN@18 |
| 1 | 1 | 1 | 98µs | 21.6ms | KiokuDB::Linker::BEGIN@4 |
| 1 | 1 | 1 | 56µs | 209µs | KiokuDB::Linker::BEGIN@14 |
| 1 | 1 | 1 | 50µs | 312µs | KiokuDB::Linker::BEGIN@15 |
| 1 | 1 | 1 | 44µs | 1.83ms | KiokuDB::Linker::BEGIN@20 |
| 1 | 1 | 1 | 42µs | 204µs | KiokuDB::Linker::BEGIN@13 |
| 1 | 1 | 1 | 25µs | 25µs | KiokuDB::Linker::BEGIN@16 |
| 0 | 0 | 0 | 0s | 0s | KiokuDB::Linker::__ANON__[:51] |
| 0 | 0 | 0 | 0s | 0s | KiokuDB::Linker::__ANON__[:57] |
| 0 | 0 | 0 | 0s | 0s | KiokuDB::Linker::expand_object |
| 0 | 0 | 0 | 0s | 0s | KiokuDB::Linker::expand_objects |
| 0 | 0 | 0 | 0s | 0s | KiokuDB::Linker::get_or_load_entries |
| 0 | 0 | 0 | 0s | 0s | KiokuDB::Linker::get_or_load_entry |
| 0 | 0 | 0 | 0s | 0s | KiokuDB::Linker::get_or_load_object |
| 0 | 0 | 0 | 0s | 0s | KiokuDB::Linker::get_or_load_objects |
| 0 | 0 | 0 | 0s | 0s | KiokuDB::Linker::inflate_data |
| 0 | 0 | 0 | 0s | 0s | KiokuDB::Linker::load_entries |
| 0 | 0 | 0 | 0s | 0s | KiokuDB::Linker::load_entry |
| 0 | 0 | 0 | 0s | 0s | KiokuDB::Linker::load_object |
| 0 | 0 | 0 | 0s | 0s | KiokuDB::Linker::load_objects |
| 0 | 0 | 0 | 0s | 0s | KiokuDB::Linker::load_queue |
| 0 | 0 | 0 | 0s | 0s | KiokuDB::Linker::queue_finalizer |
| 0 | 0 | 0 | 0s | 0s | KiokuDB::Linker::queue_ref |
| 0 | 0 | 0 | 0s | 0s | KiokuDB::Linker::refresh_object |
| 0 | 0 | 0 | 0s | 0s | KiokuDB::Linker::refresh_objects |
| 0 | 0 | 0 | 0s | 0s | KiokuDB::Linker::register_and_expand_entries |
| 0 | 0 | 0 | 0s | 0s | KiokuDB::Linker::register_object |
| Line | State ments |
Time on line |
Calls | Time in subs |
Code |
|---|---|---|---|---|---|
| 1 | #!/usr/bin/perl | ||||
| 2 | |||||
| 3 | package KiokuDB::Linker; | ||||
| 4 | 3 | 198µs | 2 | 43.1ms | # spent 21.6ms (98µs+21.5) within KiokuDB::Linker::BEGIN@4 which was called:
# once (98µs+21.5ms) by KiokuDB::BEGIN@12 at line 4 # spent 21.6ms making 1 call to KiokuDB::Linker::BEGIN@4
# spent 21.5ms making 1 call to Moose::Exporter::__ANON__[Moose/Exporter.pm:456] |
| 5 | |||||
| 6 | # perf improvements: | ||||
| 7 | # use a queue of required objects, queue up references, and bulk fetch | ||||
| 8 | # bulk fetch arrays | ||||
| 9 | # could support a Backend::Queueing which allows queuing of IDs for fetching, | ||||
| 10 | # to help clump or start a request and only read it when it's actually needed | ||||
| 11 | |||||
| 12 | |||||
| 13 | 3 | 116µs | 2 | 365µs | # spent 204µs (42+161) within KiokuDB::Linker::BEGIN@13 which was called:
# once (42µs+161µs) by KiokuDB::BEGIN@12 at line 13 # spent 204µs making 1 call to KiokuDB::Linker::BEGIN@13
# spent 161µs making 1 call to Exporter::import |
| 14 | 3 | 107µs | 2 | 361µs | # spent 209µs (56+153) within KiokuDB::Linker::BEGIN@14 which was called:
# once (56µs+153µs) by KiokuDB::BEGIN@12 at line 14 # spent 209µs making 1 call to KiokuDB::Linker::BEGIN@14
# spent 153µs making 1 call to Exporter::import |
| 15 | 3 | 116µs | 2 | 575µs | # spent 312µs (50+262) within KiokuDB::Linker::BEGIN@15 which was called:
# once (50µs+262µs) by KiokuDB::BEGIN@12 at line 15 # spent 312µs making 1 call to KiokuDB::Linker::BEGIN@15
# spent 263µs making 1 call to Exporter::import |
| 16 | 3 | 89µs | 1 | 25µs | # spent 25µs within KiokuDB::Linker::BEGIN@16 which was called:
# once (25µs+0s) by KiokuDB::BEGIN@12 at line 16 # spent 25µs making 1 call to KiokuDB::Linker::BEGIN@16 |
| 17 | |||||
| 18 | 3 | 663µs | 1 | 71.5ms | # spent 71.5ms (1.60+69.9) within KiokuDB::Linker::BEGIN@18 which was called:
# once (1.60ms+69.9ms) by KiokuDB::BEGIN@12 at line 18 # spent 71.5ms making 1 call to KiokuDB::Linker::BEGIN@18 |
| 19 | |||||
| 20 | 3 | 6.01ms | 2 | 3.62ms | # spent 1.83ms (44µs+1.79) within KiokuDB::Linker::BEGIN@20 which was called:
# once (44µs+1.79ms) by KiokuDB::BEGIN@12 at line 20 # spent 1.83ms making 1 call to KiokuDB::Linker::BEGIN@20
# spent 1.79ms making 1 call to namespace::clean::import |
| 21 | |||||
| 22 | 1 | 21µs | 1 | 16.9ms | has live_objects => ( # spent 16.9ms making 1 call to Moose::has |
| 23 | isa => "KiokuDB::LiveObjects", | ||||
| 24 | is => "ro", | ||||
| 25 | required => 1, | ||||
| 26 | handles => [qw(id_to_object ids_to_objects object_to_id objects_to_ids id_to_entry ids_to_entries)], | ||||
| 27 | ); | ||||
| 28 | |||||
| 29 | 1 | 14µs | 1 | 8.05ms | has backend => ( # spent 8.05ms making 1 call to Moose::has |
| 30 | does => "KiokuDB::Backend", | ||||
| 31 | is => "ro", | ||||
| 32 | required => 1, | ||||
| 33 | ); | ||||
| 34 | |||||
| 35 | 1 | 19µs | 1 | 11.1ms | has typemap_resolver => ( # spent 11.1ms making 1 call to Moose::has |
| 36 | isa => "KiokuDB::TypeMap::Resolver", | ||||
| 37 | is => "ro", | ||||
| 38 | handles => [qw(expand_method refresh_method)], | ||||
| 39 | required => 1, | ||||
| 40 | ); | ||||
| 41 | |||||
| 42 | 1 | 13µs | 1 | 7.97ms | has queue => ( # spent 7.97ms making 1 call to Moose::has |
| 43 | isa => "Bool", | ||||
| 44 | is => "ro", | ||||
| 45 | default => 1, | ||||
| 46 | ); | ||||
| 47 | |||||
| 48 | has _queue => ( | ||||
| 49 | isa => "ArrayRef", | ||||
| 50 | is => "ro", | ||||
| 51 | default => sub { [] }, | ||||
| 52 | 1 | 20µs | 1 | 10.0ms | ); # spent 10.0ms making 1 call to Moose::has |
| 53 | |||||
| 54 | has _deferred => ( | ||||
| 55 | isa => "ArrayRef", | ||||
| 56 | is => "ro", | ||||
| 57 | default => sub { [] }, | ||||
| 58 | 1 | 21µs | 1 | 8.11ms | ); # spent 8.11ms making 1 call to Moose::has |
| 59 | |||||
| 60 | sub register_object { | ||||
| 61 | my ( $self, $entry, $object, @args ) = @_; | ||||
| 62 | |||||
| 63 | if ( my $id = $entry->id ) { | ||||
| 64 | my $l = $self->live_objects; | ||||
| 65 | |||||
| 66 | $l->register_entry( $id => $entry ); | ||||
| 67 | $l->register_object( $id => $object, @args ); | ||||
| 68 | } | ||||
| 69 | } | ||||
| 70 | |||||
| 71 | sub expand_objects { | ||||
| 72 | my ( $self, @entries ) = @_; | ||||
| 73 | |||||
| 74 | my $l = $self->live_objects; | ||||
| 75 | |||||
| 76 | my @objects; | ||||
| 77 | |||||
| 78 | foreach my $entry ( @entries ) { | ||||
| 79 | # if the object was referred to in some other entry in @entries, it may | ||||
| 80 | # have already been loaded. | ||||
| 81 | if ( defined ( my $obj = $l->id_to_object($entry->id) ) ) { | ||||
| 82 | push @objects, $obj; | ||||
| 83 | } else { | ||||
| 84 | $self->inflate_data( $entry, \($objects[@objects]) ); | ||||
| 85 | } | ||||
| 86 | } | ||||
| 87 | |||||
| 88 | $self->load_queue; | ||||
| 89 | |||||
| 90 | return @objects; | ||||
| 91 | } | ||||
| 92 | |||||
| 93 | sub expand_object { | ||||
| 94 | my ( $self, $entry ) = @_; | ||||
| 95 | |||||
| 96 | $self->inflate_data( $entry, \(my $obj) ); | ||||
| 97 | |||||
| 98 | $self->load_queue; | ||||
| 99 | |||||
| 100 | return $obj; | ||||
| 101 | } | ||||
| 102 | |||||
| 103 | sub queue_ref { | ||||
| 104 | my ( $self, $ref, $into ) = @_; | ||||
| 105 | |||||
| 106 | if ( $self->queue ) { | ||||
| 107 | |||||
| 108 | #my $b = $self->backend; | ||||
| 109 | |||||
| 110 | #if ( $b->can("prefetch") ) { | ||||
| 111 | # $b->prefetch($ref->id); | ||||
| 112 | #} | ||||
| 113 | |||||
| 114 | push @{ $self->_queue }, [ $ref, $into ]; | ||||
| 115 | } else { | ||||
| 116 | if ( ref $ref ) { | ||||
| 117 | $$into = $self->get_or_load_object($ref->id); | ||||
| 118 | weaken($$into) if $ref->is_weak; | ||||
| 119 | } else { | ||||
| 120 | $$into = $self->get_or_load_object($ref); | ||||
| 121 | } | ||||
| 122 | } | ||||
| 123 | } | ||||
| 124 | |||||
| 125 | sub queue_finalizer { | ||||
| 126 | my ( $self, @hooks ) = @_; | ||||
| 127 | |||||
| 128 | if ( $self->queue ) { | ||||
| 129 | push @{ $self->_deferred }, @hooks; | ||||
| 130 | } else { | ||||
| 131 | foreach my $hook ( @hooks ) { | ||||
| 132 | $self->$hook(); | ||||
| 133 | } | ||||
| 134 | } | ||||
| 135 | } | ||||
| 136 | |||||
| 137 | sub load_queue { | ||||
| 138 | my $self = shift; | ||||
| 139 | |||||
| 140 | return unless $self->queue; | ||||
| 141 | |||||
| 142 | my $queue = $self->_queue; | ||||
| 143 | my $deferred = $self->_deferred; | ||||
| 144 | |||||
| 145 | my @queue = @$queue; | ||||
| 146 | my @deferred = @$deferred; | ||||
| 147 | |||||
| 148 | @$queue = (); | ||||
| 149 | @$deferred = (); | ||||
| 150 | |||||
| 151 | if ( @queue ) { | ||||
| 152 | my @ids; | ||||
| 153 | |||||
| 154 | foreach my $entry ( @queue ) { | ||||
| 155 | my $ref = $entry->[0]; | ||||
| 156 | push @ids, ref($ref) ? $ref->id : $ref; | ||||
| 157 | } | ||||
| 158 | |||||
| 159 | my @objects = $self->get_or_load_objects(@ids); | ||||
| 160 | |||||
| 161 | foreach my $item ( @queue ) { | ||||
| 162 | my ( $data, $into ) = @$item; | ||||
| 163 | my $obj = shift @objects; | ||||
| 164 | |||||
| 165 | $$into = $obj; | ||||
| 166 | |||||
| 167 | weaken $$into if ref $data and $data->is_weak; | ||||
| 168 | } | ||||
| 169 | } | ||||
| 170 | |||||
| 171 | if ( @deferred ) { | ||||
| 172 | foreach my $item ( @deferred ) { | ||||
| 173 | $self->$item; | ||||
| 174 | } | ||||
| 175 | } | ||||
| 176 | } | ||||
| 177 | |||||
| 178 | sub inflate_data { | ||||
| 179 | my ( $self, $data, $into, $entry ) = @_; | ||||
| 180 | |||||
| 181 | # Kinda ugly... inflates $data into the scalar ref in $into | ||||
| 182 | # but this allows us to handle weakening properly. | ||||
| 183 | # god I hate perl's reftypes, why couldn't they be a little more consistent | ||||
| 184 | |||||
| 185 | unless ( ref $data ) { | ||||
| 186 | $$into = $data; | ||||
| 187 | } elsif ( ref $data eq 'KiokuDB::Reference' ) { | ||||
| 188 | $self->queue_ref( $data, $into ); | ||||
| 189 | } elsif ( ref $data eq 'KiokuDB::Entry' ) { | ||||
| 190 | if ( my $class = $data->class ) { | ||||
| 191 | my $expand_method = $self->expand_method($class); | ||||
| 192 | $$into = $self->$expand_method($data); | ||||
| 193 | } else { | ||||
| 194 | my $obj; | ||||
| 195 | |||||
| 196 | $self->inflate_data($data->data, \$obj, $data); | ||||
| 197 | |||||
| 198 | $self->load_queue; # force vivification of $obj | ||||
| 199 | |||||
| 200 | if ( my $tie = $data->tied ) { | ||||
| 201 | if ( $tie eq 'H' ) { | ||||
| 202 | tie my %h, "Tie::ToObject" => $obj; | ||||
| 203 | $obj = \%h; | ||||
| 204 | } elsif ( $tie eq 'A' ) { | ||||
| 205 | tie my @a, "Tie::ToObject" => $obj; | ||||
| 206 | $obj = \@a; | ||||
| 207 | } elsif ( $tie eq 'G' ) { | ||||
| 208 | my $glob = gensym(); | ||||
| 209 | tie *$glob, "Tie::ToObject" => $obj, | ||||
| 210 | $obj = $glob; | ||||
| 211 | } elsif ( $tie eq 'S' ) { | ||||
| 212 | my $scalar; | ||||
| 213 | tie $scalar, "Tie::ToObject" => $obj; | ||||
| 214 | $obj = \$scalar; | ||||
| 215 | } else { | ||||
| 216 | die "Don't know how to tie $tie"; | ||||
| 217 | } | ||||
| 218 | } | ||||
| 219 | |||||
| 220 | $$into = $obj; | ||||
| 221 | } | ||||
| 222 | |||||
| 223 | $data->object($$into); | ||||
| 224 | } elsif ( ref($data) eq 'HASH' ) { | ||||
| 225 | my %targ; | ||||
| 226 | $self->register_object( $entry => \%targ ) if $entry; | ||||
| 227 | foreach my $key ( keys %$data ) { | ||||
| 228 | $self->inflate_data( $data->{$key}, \$targ{$key} ); | ||||
| 229 | } | ||||
| 230 | $$into = \%targ; | ||||
| 231 | } elsif ( ref($data) eq 'ARRAY' ) { | ||||
| 232 | my @targ; | ||||
| 233 | $self->register_object( $entry => \@targ ) if $entry; | ||||
| 234 | for (@$data ) { | ||||
| 235 | push @targ, undef; | ||||
| 236 | $self->inflate_data( $_, \$targ[-1] ); | ||||
| 237 | } | ||||
| 238 | $$into = \@targ; | ||||
| 239 | } elsif ( ref($data) eq 'SCALAR' ) { | ||||
| 240 | my $targ = $$data; | ||||
| 241 | $self->register_object( $entry => \$targ ) if $entry; | ||||
| 242 | $$into = \$targ; | ||||
| 243 | } elsif ( ref($data) eq 'REF' ) { | ||||
| 244 | my $targ; | ||||
| 245 | $self->register_object( $entry => \$targ ) if $entry; | ||||
| 246 | $self->inflate_data( $$data, \$targ ); | ||||
| 247 | $$into = \$targ; | ||||
| 248 | } else { | ||||
| 249 | if ( blessed($data) ) { | ||||
| 250 | # this branch is for passthrough intrinsic values | ||||
| 251 | $self->register_object( $entry => $data ) if $entry; | ||||
| 252 | $$into = $data; | ||||
| 253 | } else { | ||||
| 254 | die "unsupported reftype: " . ref $data; | ||||
| 255 | } | ||||
| 256 | } | ||||
| 257 | } | ||||
| 258 | |||||
| 259 | sub get_or_load_objects { | ||||
| 260 | my ( $self, @ids ) = @_; | ||||
| 261 | |||||
| 262 | return $self->get_or_load_object($ids[0]) if @ids == 1; | ||||
| 263 | |||||
| 264 | my %objects; | ||||
| 265 | @objects{@ids} = $self->live_objects->ids_to_objects(@ids); | ||||
| 266 | |||||
| 267 | my @missing = grep { not defined $objects{$_} } keys %objects; # @ids may contain duplicates | ||||
| 268 | |||||
| 269 | @objects{@missing} = $self->load_objects(@missing); | ||||
| 270 | |||||
| 271 | return @objects{@ids}; | ||||
| 272 | } | ||||
| 273 | |||||
| 274 | sub load_objects { | ||||
| 275 | my ( $self, @ids ) = @_; | ||||
| 276 | |||||
| 277 | return $self->expand_objects( $self->get_or_load_entries(@ids) ); | ||||
| 278 | } | ||||
| 279 | |||||
| 280 | sub get_or_load_entries { | ||||
| 281 | my ( $self, @ids ) = @_; | ||||
| 282 | |||||
| 283 | my %entries; | ||||
| 284 | @entries{@ids} = $self->ids_to_entries(@ids); | ||||
| 285 | |||||
| 286 | if ( my @load = grep { !$entries{$_} } @ids ) { | ||||
| 287 | @entries{@load} = $self->load_entries(@load); | ||||
| 288 | } | ||||
| 289 | |||||
| 290 | return @entries{@ids}; | ||||
| 291 | } | ||||
| 292 | |||||
| 293 | sub load_entries { | ||||
| 294 | my ( $self, @ids ) = @_; | ||||
| 295 | |||||
| 296 | my @entries = $self->backend->get(@ids); | ||||
| 297 | |||||
| 298 | if ( @entries != @ids or grep { !$_ } @entries ) { | ||||
| 299 | my %entries; | ||||
| 300 | @entries{@ids} = @entries; | ||||
| 301 | my @missing = grep { !$entries{$_} } @ids; | ||||
| 302 | |||||
| 303 | KiokuDB::Error::MissingObjects->throw( ids => \@missing ); | ||||
| 304 | } | ||||
| 305 | |||||
| 306 | my $l = $self->live_objects; | ||||
| 307 | foreach my $entry ( @entries ) { | ||||
| 308 | $l->register_entry( $entry->id, $entry, in_storage => 1 ); | ||||
| 309 | } | ||||
| 310 | |||||
| 311 | return @entries; | ||||
| 312 | } | ||||
| 313 | |||||
| 314 | sub register_and_expand_entries { | ||||
| 315 | my ( $self, @entries ) = @_; | ||||
| 316 | |||||
| 317 | my $l = $self->live_objects; | ||||
| 318 | foreach my $entry ( @entries ) { | ||||
| 319 | $l->register_entry( $entry->id, $entry, in_storage => 1 ); | ||||
| 320 | } | ||||
| 321 | |||||
| 322 | $self->expand_objects(@entries); | ||||
| 323 | } | ||||
| 324 | |||||
| 325 | sub get_or_load_object { | ||||
| 326 | my ( $self, $id ) = @_; | ||||
| 327 | |||||
| 328 | if ( defined( my $obj = $self->live_objects->id_to_object($id) ) ) { | ||||
| 329 | return $obj; | ||||
| 330 | } else { | ||||
| 331 | return $self->load_object($id); | ||||
| 332 | } | ||||
| 333 | } | ||||
| 334 | |||||
| 335 | sub refresh_objects { | ||||
| 336 | my ( $self, @objects ) = @_; | ||||
| 337 | |||||
| 338 | $self->refresh_object($_) for @objects; | ||||
| 339 | } | ||||
| 340 | |||||
| 341 | sub refresh_object { | ||||
| 342 | my ( $self, $object ) = @_; | ||||
| 343 | |||||
| 344 | my $id = $self->object_to_id($object); | ||||
| 345 | |||||
| 346 | my $entry = $self->load_entry($id); | ||||
| 347 | |||||
| 348 | my $refresh = $self->refresh_method( $entry->class ); | ||||
| 349 | |||||
| 350 | $self->$refresh($object, $entry); | ||||
| 351 | $self->load_queue; | ||||
| 352 | |||||
| 353 | return $object; | ||||
| 354 | } | ||||
| 355 | |||||
| 356 | sub get_or_load_entry { | ||||
| 357 | my ( $self, $id ) = @_; | ||||
| 358 | |||||
| 359 | return $self->id_to_entry($id) || $self->load_entry($id); | ||||
| 360 | } | ||||
| 361 | |||||
| 362 | sub load_entry { | ||||
| 363 | my ( $self, $id ) = @_; | ||||
| 364 | |||||
| 365 | my $entry = ( $self->backend->get($id) )[0] | ||||
| 366 | or KiokuDB::Error::MissingObjects->throw( ids => [ $id ] ); | ||||
| 367 | |||||
| 368 | $self->live_objects->register_entry( $id => $entry, in_storage => 1 ); | ||||
| 369 | |||||
| 370 | return $entry; | ||||
| 371 | } | ||||
| 372 | |||||
| 373 | sub load_object { | ||||
| 374 | my ( $self, $id ) = @_; | ||||
| 375 | |||||
| 376 | my $entry = $self->get_or_load_entry($id); | ||||
| 377 | |||||
| 378 | return $self->expand_object($entry); | ||||
| 379 | } | ||||
| 380 | |||||
| 381 | 1 | 25µs | 2 | 21.9ms | __PACKAGE__->meta->make_immutable; # spent 21.8ms making 1 call to Class::MOP::Class::make_immutable
# spent 101µs making 1 call to KiokuDB::Linker::meta |
| 382 | |||||
| 383 | 1 | 91µs | __PACKAGE__ | ||
| 384 | |||||
| 385 | 1 | 59µs | 1 | 5.66ms | __END__ # spent 5.66ms making 1 call to B::Hooks::EndOfScope::__ANON__[B/Hooks/EndOfScope.pm:26] |