use Sub::Name 'subname';
use Module::Find();
use Storable();
+use B qw/svref_2object/;
use namespace::clean;
use base qw/DBIx::Class/;
use warnings 'redefine';
# ensure classes are loaded and attached in inheritance order
- $class->ensure_class_loaded($_) foreach(values %results);
+ for my $res (values %results) {
+ $class->ensure_class_loaded($res);
+ }
my %inh_idx;
my @subclass_last = sort {
=cut
sub source {
- my ($self, $moniker) = @_;
+ my $self = shift;
+
+ $self->throw_exception("source() expects a source name")
+ unless @_;
+
+ my $moniker = shift;
+
my $sreg = $self->source_registrations;
return $sreg->{$moniker} if exists $sreg->{$moniker};
my $schema = $self->clone;
{
no warnings qw/redefine/;
+ no strict qw/refs/;
# local *Class::C3::reinitialize = sub { };
foreach my $moniker ($schema->sources) {
my $source = $schema->source($moniker);
$target_class => $source->result_class, ($base ? $base : ())
);
$source->result_class($target_class);
- $target_class->result_source_instance($source)
- if $target_class->can('result_source_instance');
+ if ($target_class->can('result_source_instance')) {
+
+ # since the newly created classes are registered only with
+ # the instance of $schema, it should be safe to weaken
+ # the ref (it will GC when $schema is destroyed)
+ $target_class->result_source_instance($source);
+ weaken ${"${target_class}::__cag_result_source_instance"};
+ }
$schema->register_source($moniker, $source);
}
}
=head2 freeze
-This doesn't actually do anything more than call L<Storable/freeze>, it is just
+This doesn't actually do anything more than call L<Storable/nfreeze>, it is just
provided here for symmetry.
=cut
sub freeze {
- return Storable::freeze($_[1]);
+ return Storable::nfreeze($_[1]);
}
=head2 dclone
$self->class_mappings(\%map);
}
+{
+ my $global_phase_destroy;
+
+ # SpeedyCGI runs END blocks every cycle but keeps object instances
+ # hence we have to disable the globaldestroy hatch, and rely on the
+ # eval trap below (which appears to work, but is risky done so late)
+ END { $global_phase_destroy = 1 unless $CGI::SpeedyCGI::i_am_speedy }
+
+ sub DESTROY {
+ return if $global_phase_destroy;
+
+ my $self = shift;
+ my $srcs = $self->source_registrations;
+
+ for my $moniker (keys %$srcs) {
+ # find first source that is not about to be GCed (someone other than $self
+ # holds a reference to it) and reattach to it, weakening our own link
+ #
+ # during global destruction (if we have not yet bailed out) this will throw
+ # which will serve as a signal to not try doing anything else
+ if (ref $srcs->{$moniker} and svref_2object($srcs->{$moniker})->REFCNT > 1) {
+ local $@;
+ eval {
+ $srcs->{$moniker}->schema($self);
+ 1;
+ } or do {
+ $global_phase_destroy = 1;
+ last;
+ };
+
+ weaken $srcs->{$moniker};
+ last;
+ }
+ }
+ }
+}
+
sub _unregister_source {
my ($self, $moniker) = @_;
my %reg = %{$self->source_registrations};