| Filename | /home/doy/perl5/perlbrew/perls/perl-5.10.1/lib/site_perl/5.10.1/KiokuDB/TypeMap/Entry/MOP.pm |
| Statements | Executed 36 statements in 10.1ms |
| Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
|---|---|---|---|---|---|
| 1 | 1 | 1 | 1.52ms | 86.7ms | KiokuDB::TypeMap::Entry::MOP::BEGIN@9 |
| 1 | 1 | 1 | 76µs | 21.3ms | KiokuDB::TypeMap::Entry::MOP::BEGIN@4 |
| 1 | 1 | 1 | 60µs | 1.80ms | KiokuDB::TypeMap::Entry::MOP::BEGIN@19 |
| 1 | 1 | 1 | 57µs | 121µs | KiokuDB::TypeMap::Entry::MOP::BEGIN@239 |
| 1 | 1 | 1 | 47µs | 97µs | KiokuDB::TypeMap::Entry::MOP::BEGIN@261 |
| 1 | 1 | 1 | 46µs | 95µs | KiokuDB::TypeMap::Entry::MOP::BEGIN@287 |
| 1 | 1 | 1 | 42µs | 111µs | KiokuDB::TypeMap::Entry::MOP::BEGIN@11 |
| 1 | 1 | 1 | 42µs | 206µs | KiokuDB::TypeMap::Entry::MOP::BEGIN@6 |
| 1 | 1 | 1 | 40µs | 166µs | KiokuDB::TypeMap::Entry::MOP::BEGIN@7 |
| 0 | 0 | 0 | 0s | 0s | KiokuDB::TypeMap::Entry::MOP::__ANON__[:179] |
| 0 | 0 | 0 | 0s | 0s | KiokuDB::TypeMap::Entry::MOP::__ANON__[:230] |
| 0 | 0 | 0 | 0s | 0s | KiokuDB::TypeMap::Entry::MOP::__ANON__[:343] |
| 0 | 0 | 0 | 0s | 0s | KiokuDB::TypeMap::Entry::MOP::__ANON__[:364] |
| 0 | 0 | 0 | 0s | 0s | KiokuDB::TypeMap::Entry::MOP::__ANON__[:373] |
| 0 | 0 | 0 | 0s | 0s | KiokuDB::TypeMap::Entry::MOP::__ANON__[:37] |
| 0 | 0 | 0 | 0s | 0s | KiokuDB::TypeMap::Entry::MOP::__ANON__[:428] |
| 0 | 0 | 0 | 0s | 0s | KiokuDB::TypeMap::Entry::MOP::__ANON__[:431] |
| 0 | 0 | 0 | 0s | 0s | KiokuDB::TypeMap::Entry::MOP::__ANON__[:43] |
| 0 | 0 | 0 | 0s | 0s | KiokuDB::TypeMap::Entry::MOP::__ANON__[:464] |
| 0 | 0 | 0 | 0s | 0s | KiokuDB::TypeMap::Entry::MOP::_process_upgrade_handler |
| 0 | 0 | 0 | 0s | 0s | KiokuDB::TypeMap::Entry::MOP::clear_version_cache |
| 0 | 0 | 0 | 0s | 0s | KiokuDB::TypeMap::Entry::MOP::compile_clear |
| 0 | 0 | 0 | 0s | 0s | KiokuDB::TypeMap::Entry::MOP::compile_collapse_body |
| 0 | 0 | 0 | 0s | 0s | KiokuDB::TypeMap::Entry::MOP::compile_create |
| 0 | 0 | 0 | 0s | 0s | KiokuDB::TypeMap::Entry::MOP::compile_expand |
| 0 | 0 | 0 | 0s | 0s | KiokuDB::TypeMap::Entry::MOP::compile_expand_data |
| 0 | 0 | 0 | 0s | 0s | KiokuDB::TypeMap::Entry::MOP::compile_id |
| 0 | 0 | 0 | 0s | 0s | KiokuDB::TypeMap::Entry::MOP::does_role |
| 0 | 0 | 0 | 0s | 0s | KiokuDB::TypeMap::Entry::MOP::find_version_handlers |
| 0 | 0 | 0 | 0s | 0s | KiokuDB::TypeMap::Entry::MOP::inflate_class_meta |
| 0 | 0 | 0 | 0s | 0s | KiokuDB::TypeMap::Entry::MOP::is_version_up_to_date |
| 0 | 0 | 0 | 0s | 0s | KiokuDB::TypeMap::Entry::MOP::reconstruct_anon_class |
| 0 | 0 | 0 | 0s | 0s | KiokuDB::TypeMap::Entry::MOP::should_compile_intrinsic |
| 0 | 0 | 0 | 0s | 0s | KiokuDB::TypeMap::Entry::MOP::upgrade_entry |
| 0 | 0 | 0 | 0s | 0s | KiokuDB::TypeMap::Entry::MOP::upgrade_entry_from_version |
| Line | State ments |
Time on line |
Calls | Time in subs |
Code |
|---|---|---|---|---|---|
| 1 | #!/usr/bin/perl | ||||
| 2 | |||||
| 3 | package KiokuDB::TypeMap::Entry::MOP; | ||||
| 4 | 3 | 163µs | 2 | 42.6ms | # spent 21.3ms (76µs+21.3) within KiokuDB::TypeMap::Entry::MOP::BEGIN@4 which was called:
# once (76µs+21.3ms) by KiokuDB::TypeMap::Resolver::BEGIN@9 at line 4 # spent 21.3ms making 1 call to KiokuDB::TypeMap::Entry::MOP::BEGIN@4
# spent 21.3ms making 1 call to Moose::Exporter::__ANON__[Moose/Exporter.pm:456] |
| 5 | |||||
| 6 | 3 | 110µs | 2 | 369µs | # spent 206µs (42+164) within KiokuDB::TypeMap::Entry::MOP::BEGIN@6 which was called:
# once (42µs+164µs) by KiokuDB::TypeMap::Resolver::BEGIN@9 at line 6 # spent 206µs making 1 call to KiokuDB::TypeMap::Entry::MOP::BEGIN@6
# spent 164µs making 1 call to Exporter::import |
| 7 | 3 | 175µs | 2 | 291µs | # spent 166µs (40+126) within KiokuDB::TypeMap::Entry::MOP::BEGIN@7 which was called:
# once (40µs+126µs) by KiokuDB::TypeMap::Resolver::BEGIN@9 at line 7 # spent 166µs making 1 call to KiokuDB::TypeMap::Entry::MOP::BEGIN@7
# spent 126µs making 1 call to Exporter::import |
| 8 | |||||
| 9 | 3 | 626µs | 1 | 86.7ms | # spent 86.7ms (1.52+85.1) within KiokuDB::TypeMap::Entry::MOP::BEGIN@9 which was called:
# once (1.52ms+85.1ms) by KiokuDB::TypeMap::Resolver::BEGIN@9 at line 9 # spent 86.7ms making 1 call to KiokuDB::TypeMap::Entry::MOP::BEGIN@9 |
| 10 | |||||
| 11 | 3 | 260µs | 2 | 180µs | # spent 111µs (42+69) within KiokuDB::TypeMap::Entry::MOP::BEGIN@11 which was called:
# once (42µs+69µs) by KiokuDB::TypeMap::Resolver::BEGIN@9 at line 11 # spent 111µs making 1 call to KiokuDB::TypeMap::Entry::MOP::BEGIN@11
# spent 69µs making 1 call to warnings::unimport |
| 12 | |||||
| 13 | sub does_role { | ||||
| 14 | my ($meta, $role) = @_; | ||||
| 15 | return unless my $does = $meta->can('does_role'); | ||||
| 16 | return $meta->$does($role); | ||||
| 17 | } | ||||
| 18 | |||||
| 19 | 3 | 3.59ms | 2 | 3.54ms | # spent 1.80ms (60µs+1.74) within KiokuDB::TypeMap::Entry::MOP::BEGIN@19 which was called:
# once (60µs+1.74ms) by KiokuDB::TypeMap::Resolver::BEGIN@9 at line 19 # spent 1.80ms making 1 call to KiokuDB::TypeMap::Entry::MOP::BEGIN@19
# spent 1.74ms making 1 call to namespace::clean::import |
| 20 | |||||
| 21 | 1 | 34µs | 1 | 292ms | with ( # spent 292ms making 1 call to Moose::with |
| 22 | 'KiokuDB::TypeMap::Entry::Std', | ||||
| 23 | 'KiokuDB::TypeMap::Entry::Std::Expand' => { | ||||
| 24 | alias => { compile_expand => 'compile_expand_body' }, | ||||
| 25 | } | ||||
| 26 | ); | ||||
| 27 | |||||
| 28 | 1 | 20µs | 1 | 10.2ms | has check_class_versions => ( # spent 10.2ms making 1 call to Moose::has |
| 29 | isa => "Bool", | ||||
| 30 | is => "ro", | ||||
| 31 | default => 1, | ||||
| 32 | ); | ||||
| 33 | |||||
| 34 | has version_table => ( | ||||
| 35 | isa => "HashRef[Str|CodeRef|HashRef]", | ||||
| 36 | is => "ro", | ||||
| 37 | default => sub { return {} }, | ||||
| 38 | 1 | 20µs | 1 | 16.3ms | ); # spent 16.3ms making 1 call to Moose::has |
| 39 | |||||
| 40 | has class_version_table => ( | ||||
| 41 | isa => "HashRef[HashRef[Str|CodeRef|HashRef]]", | ||||
| 42 | is => "ro", | ||||
| 43 | default => sub { return {} }, | ||||
| 44 | 1 | 21µs | 1 | 22.5ms | ); # spent 22.5ms making 1 call to Moose::has |
| 45 | |||||
| 46 | 1 | 13µs | 1 | 8.30ms | has write_upgrades => ( # spent 8.30ms making 1 call to Moose::has |
| 47 | isa => "Bool", | ||||
| 48 | is => "ro", | ||||
| 49 | default => 0, | ||||
| 50 | ); | ||||
| 51 | |||||
| 52 | # FIXME collapser and expaner should both be methods in Class::MOP::Class, | ||||
| 53 | # apart from the visit call | ||||
| 54 | |||||
| 55 | sub compile_collapse_body { | ||||
| 56 | my ( $self, $class, @args ) = @_; | ||||
| 57 | |||||
| 58 | my $meta = Class::MOP::get_metaclass_by_name($class); | ||||
| 59 | |||||
| 60 | my @attrs = grep { | ||||
| 61 | !does_role($_->meta, 'KiokuDB::Meta::Attribute::DoNotSerialize') | ||||
| 62 | and | ||||
| 63 | !does_role($_->meta, 'MooseX::Storage::Meta::Attribute::Trait::DoNotSerialize') | ||||
| 64 | } $meta->get_all_attributes; | ||||
| 65 | |||||
| 66 | my %lazy; | ||||
| 67 | foreach my $attr ( @attrs ) { | ||||
| 68 | $lazy{$attr->name} = does_role($attr->meta, "KiokuDB::Meta::Attribute::Lazy"); | ||||
| 69 | } | ||||
| 70 | |||||
| 71 | my $meta_instance = $meta->get_meta_instance; | ||||
| 72 | |||||
| 73 | my %attrs; | ||||
| 74 | |||||
| 75 | if ( $meta->is_anon_class ) { | ||||
| 76 | |||||
| 77 | # FIXME ancestral roles all the way up to first non anon ancestor, | ||||
| 78 | # at least check for additional attributes or other metadata which we | ||||
| 79 | # should probably error on anything we can't store | ||||
| 80 | |||||
| 81 | # theoretically this can do multiple inheritence too | ||||
| 82 | |||||
| 83 | my $ancestor = $meta; | ||||
| 84 | my @anon; | ||||
| 85 | |||||
| 86 | search: { | ||||
| 87 | push @anon, $ancestor; | ||||
| 88 | |||||
| 89 | my @super = $ancestor->superclasses; | ||||
| 90 | |||||
| 91 | if ( @super == 1 ) { | ||||
| 92 | $ancestor = Class::MOP::get_metaclass_by_name($super[0]); | ||||
| 93 | if ( $ancestor->is_anon_class ) { | ||||
| 94 | redo search; | ||||
| 95 | } | ||||
| 96 | } elsif ( @super > 1 ) { | ||||
| 97 | croak "Cannot resolve anonymous class with multiple inheritence: " . $meta->name; | ||||
| 98 | } else { | ||||
| 99 | croak "no super, ancestor: $ancestor (" . $ancestor->name . ")"; | ||||
| 100 | } | ||||
| 101 | } | ||||
| 102 | |||||
| 103 | my $class_meta = $ancestor->name; | ||||
| 104 | |||||
| 105 | foreach my $anon ( reverse @anon ) { | ||||
| 106 | $class_meta = { | ||||
| 107 | roles => [ | ||||
| 108 | map { $_->name } map { | ||||
| 109 | $_->isa("Moose::Meta::Role::Composite") | ||||
| 110 | ? @{$_->get_roles} | ||||
| 111 | : $_ | ||||
| 112 | } @{ $anon->roles } | ||||
| 113 | ], | ||||
| 114 | superclasses => [ $class_meta ], | ||||
| 115 | }; | ||||
| 116 | } | ||||
| 117 | |||||
| 118 | if ( $class_meta->{superclasses}[0] eq $ancestor->name ) { | ||||
| 119 | # no need for redundancy, expansion will provide this as the default | ||||
| 120 | delete $class_meta->{superclasses}; | ||||
| 121 | } | ||||
| 122 | |||||
| 123 | %attrs = ( | ||||
| 124 | class => $ancestor->name, | ||||
| 125 | class_meta => $class_meta, | ||||
| 126 | ); | ||||
| 127 | } | ||||
| 128 | |||||
| 129 | my $immutable = does_role($meta, "KiokuDB::Role::Immutable"); | ||||
| 130 | my $content_id = does_role($meta, "KiokuDB::Role::ID::Content"); | ||||
| 131 | |||||
| 132 | my @extra_args; | ||||
| 133 | |||||
| 134 | if ( defined( my $version = $meta->version ) ) { | ||||
| 135 | push @extra_args, class_version => "$version"; # force stringification for version objects | ||||
| 136 | } | ||||
| 137 | |||||
| 138 | return ( | ||||
| 139 | sub { | ||||
| 140 | my ( $self, %args ) = @_; | ||||
| 141 | |||||
| 142 | my $object = $args{object}; | ||||
| 143 | |||||
| 144 | if ( $immutable ) { | ||||
| 145 | # FIXME this doesn't handle unset_root | ||||
| 146 | if ( $self->live_objects->object_in_storage($object) ) { | ||||
| 147 | return $self->make_skip_entry( %args, prev => $self->live_objects->object_to_entry($object) ); | ||||
| 148 | } elsif ( $content_id ) { | ||||
| 149 | if ( ($self->backend->exists($args{id}))[0] ) { # exists works in list context | ||||
| 150 | return $self->make_skip_entry(%args); | ||||
| 151 | } | ||||
| 152 | } | ||||
| 153 | } | ||||
| 154 | |||||
| 155 | my %collapsed; | ||||
| 156 | |||||
| 157 | attr: foreach my $attr ( @attrs ) { | ||||
| 158 | my $name = $attr->name; | ||||
| 159 | if ( $attr->has_value($object) ) { | ||||
| 160 | if ( $lazy{$name} ) { | ||||
| 161 | my $value = $meta_instance->Class::MOP::Instance::get_slot_value($object, $name); # FIXME fix KiokuDB::Meta::Instance to allow fetching thunk | ||||
| 162 | |||||
| 163 | if ( ref $value eq 'KiokuDB::Thunk' ) { | ||||
| 164 | $collapsed{$name} = $value->collapsed; | ||||
| 165 | next attr; | ||||
| 166 | } | ||||
| 167 | } | ||||
| 168 | |||||
| 169 | my $value = $attr->get_raw_value($object); | ||||
| 170 | $collapsed{$name} = ref($value) ? $self->visit($value) : $value; | ||||
| 171 | } | ||||
| 172 | } | ||||
| 173 | |||||
| 174 | return $self->make_entry( | ||||
| 175 | @extra_args, | ||||
| 176 | %args, | ||||
| 177 | data => \%collapsed, | ||||
| 178 | ); | ||||
| 179 | }, | ||||
| 180 | %attrs, | ||||
| 181 | ); | ||||
| 182 | } | ||||
| 183 | |||||
| 184 | sub compile_expand { | ||||
| 185 | my ( $self, $class, $resolver, @args ) = @_; | ||||
| 186 | |||||
| 187 | my $meta = Class::MOP::get_metaclass_by_name($class); | ||||
| 188 | |||||
| 189 | my $typemap_entry = $self; | ||||
| 190 | |||||
| 191 | my $anon = $meta->is_anon_class; | ||||
| 192 | |||||
| 193 | my $inner = $self->compile_expand_body($class, $resolver, @args); | ||||
| 194 | |||||
| 195 | my $version = $meta->version; | ||||
| 196 | |||||
| 197 | return sub { | ||||
| 198 | my ( $linker, $entry, @args ) = @_; | ||||
| 199 | |||||
| 200 | if ( $entry->has_class_meta and !$anon ) { | ||||
| 201 | # the entry is for an anonymous subclass of this class, we need to | ||||
| 202 | # compile that entry and short circuit to it. if $anon is true then | ||||
| 203 | # we're already compiled, and the class_meta is already handled | ||||
| 204 | my $anon_meta = $self->reconstruct_anon_class($entry); | ||||
| 205 | |||||
| 206 | my $anon_class = $anon_meta->name; | ||||
| 207 | |||||
| 208 | unless ( $resolver->resolved($anon_class) ) { | ||||
| 209 | $resolver->compile_entry($anon_class, $typemap_entry); | ||||
| 210 | } | ||||
| 211 | |||||
| 212 | my $method = $resolver->expand_method($anon_class); | ||||
| 213 | return $linker->$method($entry, @args); | ||||
| 214 | } | ||||
| 215 | |||||
| 216 | if ( !$self->check_class_versions or $self->is_version_up_to_date($meta, $version, $entry->class_version) ) { | ||||
| 217 | $linker->$inner($entry, @args); | ||||
| 218 | } else { | ||||
| 219 | my $upgraded = $self->upgrade_entry( linker => $linker, meta => $meta, entry => $entry, expand_args => \@args); | ||||
| 220 | |||||
| 221 | if ( $self->write_upgrades ) { | ||||
| 222 | croak "Upgraded entry can't be updated (mismatch in 'prev' chain)" | ||||
| 223 | unless refaddr($entry) == refaddr($upgraded->root_prev); | ||||
| 224 | |||||
| 225 | $linker->backend->insert($upgraded); | ||||
| 226 | } | ||||
| 227 | |||||
| 228 | $linker->$inner($upgraded, @args); | ||||
| 229 | } | ||||
| 230 | } | ||||
| 231 | } | ||||
| 232 | |||||
| 233 | 2 | 7µs | { my %cache; | ||
| 234 | sub is_version_up_to_date { | ||||
| 235 | my ( $self, $meta, $version, $entry_version ) = @_; | ||||
| 236 | |||||
| 237 | # no clever stuff, only if they are the same string they are the same version | ||||
| 238 | |||||
| 239 | 3 | 522µs | 2 | 185µs | # spent 121µs (57+64) within KiokuDB::TypeMap::Entry::MOP::BEGIN@239 which was called:
# once (57µs+64µs) by KiokuDB::TypeMap::Resolver::BEGIN@9 at line 239 # spent 121µs making 1 call to KiokuDB::TypeMap::Entry::MOP::BEGIN@239
# spent 64µs making 1 call to warnings::unimport |
| 240 | return 1 if $version eq $entry_version; | ||||
| 241 | |||||
| 242 | my $key = join(":", $meta->name, $entry_version); # $VERSION isn't supposed to change at runtime | ||||
| 243 | |||||
| 244 | return $cache{$key} if exists $cache{$key}; | ||||
| 245 | |||||
| 246 | # check the version table for equivalent versions (recursively) | ||||
| 247 | # ref handlers are upgrade hooks | ||||
| 248 | foreach my $handler ( $self->find_version_handlers($meta, $entry_version) ) { | ||||
| 249 | return $cache{$key} = $self->is_version_up_to_date( $meta, $version, $handler ) if not ref $handler; | ||||
| 250 | } | ||||
| 251 | |||||
| 252 | return $cache{$key} = undef; | ||||
| 253 | } | ||||
| 254 | |||||
| 255 | sub clear_version_cache { %cache = () } | ||||
| 256 | } | ||||
| 257 | |||||
| 258 | sub find_version_handlers { | ||||
| 259 | my ( $self, $meta, $version ) = @_; | ||||
| 260 | |||||
| 261 | 3 | 669µs | 2 | 148µs | # spent 97µs (47+50) within KiokuDB::TypeMap::Entry::MOP::BEGIN@261 which was called:
# once (47µs+50µs) by KiokuDB::TypeMap::Resolver::BEGIN@9 at line 261 # spent 97µs making 1 call to KiokuDB::TypeMap::Entry::MOP::BEGIN@261
# spent 50µs making 1 call to warnings::unimport |
| 262 | |||||
| 263 | if ( does_role($meta, "KiokuDB::Role::Upgrade::Handlers") ) { | ||||
| 264 | return $meta->name->kiokudb_upgrade_handler($version); | ||||
| 265 | } else { | ||||
| 266 | return grep { defined } map { $_->{$version} } $self->class_version_table->{$meta->name}, $self->version_table; | ||||
| 267 | } | ||||
| 268 | } | ||||
| 269 | |||||
| 270 | sub upgrade_entry { | ||||
| 271 | my ( $self, %args ) = @_; | ||||
| 272 | |||||
| 273 | my ( $meta, $entry ) = @args{qw(meta entry)}; | ||||
| 274 | |||||
| 275 | if ( does_role($meta, "KiokuDB::Role::Upgrade::Data") ) { | ||||
| 276 | return $meta->name->kiokudb_upgrade_data(%args); | ||||
| 277 | } else { | ||||
| 278 | return $self->upgrade_entry_from_version( %args, from_version => $entry->class_version ); | ||||
| 279 | } | ||||
| 280 | } | ||||
| 281 | |||||
| 282 | sub upgrade_entry_from_version { | ||||
| 283 | my ( $self, %args ) = @_; | ||||
| 284 | |||||
| 285 | my ( $meta, $from_version, $entry ) = @args{qw(meta from_version entry)}; | ||||
| 286 | |||||
| 287 | 3 | 3.70ms | 2 | 144µs | # spent 95µs (46+49) within KiokuDB::TypeMap::Entry::MOP::BEGIN@287 which was called:
# once (46µs+49µs) by KiokuDB::TypeMap::Resolver::BEGIN@9 at line 287 # spent 95µs making 1 call to KiokuDB::TypeMap::Entry::MOP::BEGIN@287
# spent 49µs making 1 call to warnings::unimport |
| 288 | |||||
| 289 | foreach my $handler ( $self->find_version_handlers($meta, $from_version) ) { | ||||
| 290 | if ( ref $handler ) { | ||||
| 291 | |||||
| 292 | my $cb = $self->_process_upgrade_handler($handler); | ||||
| 293 | |||||
| 294 | # apply handler | ||||
| 295 | my $converted = $self->$cb(%args); | ||||
| 296 | |||||
| 297 | if ( $self->is_version_up_to_date( $meta, $meta->version, $converted->class_version ) ) { | ||||
| 298 | return $converted; | ||||
| 299 | } elsif ( $entry->class_version eq $converted->class_version ) { | ||||
| 300 | croak "Upgrade from " . $entry->class_version . " did change 'class_version' field"; | ||||
| 301 | } else { | ||||
| 302 | # more error context | ||||
| 303 | return try { | ||||
| 304 | $self->upgrade_entry_from_version(%args, entry => $converted, from_version => $converted->class_version); | ||||
| 305 | } catch { | ||||
| 306 | croak "$_\n... when upgrading from $from_version"; | ||||
| 307 | }; | ||||
| 308 | } | ||||
| 309 | } else { | ||||
| 310 | # nonref is equivalent version, recursively search for handlers for that version | ||||
| 311 | return $self->upgrade_entry_from_version( %args, from_version => $handler ); | ||||
| 312 | } | ||||
| 313 | } | ||||
| 314 | |||||
| 315 | croak "No handler found for " . $meta->name . " version $from_version" . ( $entry->class_version ne $from_version ? "(entry version is " . $entry->class_version . ")" : "" ); | ||||
| 316 | } | ||||
| 317 | |||||
| 318 | sub _process_upgrade_handler { | ||||
| 319 | my ( $self, $handler ) = @_; | ||||
| 320 | |||||
| 321 | if ( ref $handler eq 'HASH' ) { | ||||
| 322 | croak "Data provided in upgrade handler must be a hash" | ||||
| 323 | if ref $handler->{data} and ref $handler->{data} ne 'HASH'; | ||||
| 324 | |||||
| 325 | croak "No class_version provided in upgrade handler" | ||||
| 326 | unless defined $handler->{class_version}; | ||||
| 327 | |||||
| 328 | return sub { | ||||
| 329 | my ( $self, %args ) = @_; | ||||
| 330 | |||||
| 331 | my $entry = $args{entry}; | ||||
| 332 | |||||
| 333 | croak "Entry data not a hash reference" | ||||
| 334 | unless ref $entry->data eq 'HASH'; | ||||
| 335 | |||||
| 336 | $entry->derive( | ||||
| 337 | %$handler, | ||||
| 338 | data => { | ||||
| 339 | %{ $entry->data }, | ||||
| 340 | %{ $handler->{data} || {} }, | ||||
| 341 | }, | ||||
| 342 | ); | ||||
| 343 | }; | ||||
| 344 | } | ||||
| 345 | |||||
| 346 | return $handler; | ||||
| 347 | } | ||||
| 348 | |||||
| 349 | sub compile_create { | ||||
| 350 | my ( $self, $class ) = @_; | ||||
| 351 | |||||
| 352 | my $meta = Class::MOP::get_metaclass_by_name($class); | ||||
| 353 | |||||
| 354 | my $meta_instance = $meta->get_meta_instance; | ||||
| 355 | |||||
| 356 | my $cache = does_role($meta, "KiokuDB::Role::Cacheable"); | ||||
| 357 | |||||
| 358 | my @register_args = ( | ||||
| 359 | ( $cache ? ( cache => 1 ) : () ), | ||||
| 360 | ); | ||||
| 361 | |||||
| 362 | return sub { | ||||
| 363 | return ( $meta_instance->create_instance(), @register_args ); | ||||
| 364 | }; | ||||
| 365 | } | ||||
| 366 | |||||
| 367 | sub compile_clear { | ||||
| 368 | my ( $self, $class ) = @_; | ||||
| 369 | |||||
| 370 | return sub { | ||||
| 371 | my ( $linker, $obj ) = @_; | ||||
| 372 | %$obj = (); # FIXME | ||||
| 373 | } | ||||
| 374 | } | ||||
| 375 | |||||
| 376 | sub compile_expand_data { | ||||
| 377 | my ( $self, $class, @args ) = @_; | ||||
| 378 | |||||
| 379 | my $meta = Class::MOP::get_metaclass_by_name($class); | ||||
| 380 | |||||
| 381 | my $meta_instance = $meta->get_meta_instance; | ||||
| 382 | |||||
| 383 | my ( %attrs, %lazy ); | ||||
| 384 | |||||
| 385 | my @attrs = grep { | ||||
| 386 | !does_role($_->meta, 'KiokuDB::Meta::Attribute::DoNotSerialize') | ||||
| 387 | and | ||||
| 388 | !does_role($_->meta, 'MooseX::Storage::Meta::Attribute::Trait::DoNotSerialize') | ||||
| 389 | } $meta->get_all_attributes; | ||||
| 390 | |||||
| 391 | foreach my $attr ( @attrs ) { | ||||
| 392 | $attrs{$attr->name} = $attr; | ||||
| 393 | $lazy{$attr->name} = does_role($attr->meta, "KiokuDB::Meta::Attribute::Lazy"); | ||||
| 394 | } | ||||
| 395 | |||||
| 396 | return sub { | ||||
| 397 | my ( $linker, $instance, $entry, @args ) = @_; | ||||
| 398 | |||||
| 399 | my $data = $entry->data; | ||||
| 400 | |||||
| 401 | my @values; | ||||
| 402 | |||||
| 403 | foreach my $name ( keys %$data ) { | ||||
| 404 | my $attr = $attrs{$name} or croak "Unknown attribute: $name"; | ||||
| 405 | my $value = $data->{$name}; | ||||
| 406 | |||||
| 407 | if ( ref $value ) { | ||||
| 408 | if ( $lazy{$name} ) { | ||||
| 409 | my $thunk = KiokuDB::Thunk->new( collapsed => $value, linker => $linker, attr => $attr ); | ||||
| 410 | $attr->set_raw_value($instance, $thunk); | ||||
| 411 | } else { | ||||
| 412 | my @pair = ( $attr, undef ); | ||||
| 413 | |||||
| 414 | $linker->inflate_data($value, \$pair[1]) if ref $value; | ||||
| 415 | push @values, \@pair; | ||||
| 416 | } | ||||
| 417 | } else { | ||||
| 418 | $attr->set_raw_value($instance, $value); | ||||
| 419 | } | ||||
| 420 | } | ||||
| 421 | |||||
| 422 | $linker->queue_finalizer(sub { | ||||
| 423 | foreach my $pair ( @values ) { | ||||
| 424 | my ( $attr, $value ) = @$pair; | ||||
| 425 | $attr->set_raw_value($instance, $value); | ||||
| 426 | $attr->_weaken_value($instance) if $attr->is_weak_ref; | ||||
| 427 | } | ||||
| 428 | }); | ||||
| 429 | |||||
| 430 | return $instance; | ||||
| 431 | } | ||||
| 432 | } | ||||
| 433 | |||||
| 434 | sub reconstruct_anon_class { | ||||
| 435 | my ( $self, $entry ) = @_; | ||||
| 436 | |||||
| 437 | $self->inflate_class_meta( | ||||
| 438 | superclasses => [ $entry->class ], | ||||
| 439 | %{ $entry->class_meta }, | ||||
| 440 | ); | ||||
| 441 | } | ||||
| 442 | |||||
| 443 | sub inflate_class_meta { | ||||
| 444 | my ( $self, %meta ) = @_; | ||||
| 445 | |||||
| 446 | foreach my $super ( @{ $meta{superclasses} } ) { | ||||
| 447 | $super = $self->inflate_class_meta(%$super)->name if ref $super; | ||||
| 448 | } | ||||
| 449 | |||||
| 450 | # FIXME should probably get_meta_by_name($entry->class) | ||||
| 451 | Moose::Meta::Class->create_anon_class( | ||||
| 452 | cache => 1, | ||||
| 453 | %meta, | ||||
| 454 | ); | ||||
| 455 | } | ||||
| 456 | |||||
| 457 | sub compile_id { | ||||
| 458 | my ( $self, $class ) = @_; | ||||
| 459 | |||||
| 460 | if ( does_role(Class::MOP::get_metaclass_by_name($class), "KiokuDB::Role::ID") ) { | ||||
| 461 | return sub { | ||||
| 462 | my ( $self, $object ) = @_; | ||||
| 463 | return $object->kiokudb_object_id; | ||||
| 464 | } | ||||
| 465 | } else { | ||||
| 466 | return "generate_uuid"; | ||||
| 467 | } | ||||
| 468 | } | ||||
| 469 | |||||
| 470 | sub should_compile_intrinsic { | ||||
| 471 | my ( $self, $class, @args ) = @_; | ||||
| 472 | |||||
| 473 | my $meta = Class::MOP::get_metaclass_by_name($class); | ||||
| 474 | |||||
| 475 | if ( $self->has_intrinsic ) { | ||||
| 476 | return $self->intrinsic; | ||||
| 477 | } elsif ( does_role($meta, "KiokuDB::Role::Intrinsic") ) { | ||||
| 478 | return 1; | ||||
| 479 | } else { | ||||
| 480 | return 0; | ||||
| 481 | } | ||||
| 482 | } | ||||
| 483 | |||||
| 484 | 1 | 25µs | 2 | 20.7ms | __PACKAGE__->meta->make_immutable; # spent 20.6ms making 1 call to Class::MOP::Class::make_immutable
# spent 101µs making 1 call to KiokuDB::TypeMap::Entry::MOP::meta |
| 485 | |||||
| 486 | 1 | 88µs | __PACKAGE__ | ||
| 487 | |||||
| 488 | 1 | 65µs | 1 | 5.47ms | __END__ # spent 5.47ms making 1 call to B::Hooks::EndOfScope::__ANON__[B/Hooks/EndOfScope.pm:26] |