Using Storable with DBIx::Class - Can't locate object method "result_source_instance"

6 messages Options
Embed this post
Permalink
Bill Moseley

Using Storable with DBIx::Class - Can't locate object method "result_source_instance"

Reply Threaded More More options
Print post
Permalink
How does Storable know when to attempt to load ("use")  a thawed object's module from disk?

We are adding new functionality to an application.  The new functionality uses DBIx::Class and is a separate application deployed on separate machines.  The machines need to share data (via Memcached) back and forth, so all applications are configured to use the same cache.

The DBIC-based application has no problem reading this shared cache.  The deserialized hash has data of different types, including many blessed objects -- many that do not have
associated modules on those machines.

The problem, though, is when the DBIC-based application places a row object into the cache and serializes it back then the old app can no longer read the cache.  The application dies with:

Can't locate object method "result_source_instance" via package "MyApp::Result::Artist" (perhaps you forgot to load "MyApp::Result::Artist"?) at /usr/local/share/perl/5.10.0/DBIx/Class/ResultSourceHandle.pm line 105

Actually, some machines don't have DBIx::Class installed and they die with:

Can't locate DBIx/Class/ResultSourceHandle.pm in @INC

As I mentioned, in the stored hash there are other objects other than the Artist object.  And those are blessed into classes that do not have associated modules on some machines, yet they do not generate these errors.  I'm wondering why some objects trigger an attempt to load the module and some don't.


I can solve the second error above by installing DBIx::Class on all machines that read this data via Storable.  But, is there a workaround to allow these non-DBIC applcations
to thaw this hash and just ignore the DBIC-blessed objects?  There's other data (not DBIx::Class objects) that also need to get stored in the cache and passed to the old application.  This works fine w/o adding the DBIC objects into the cache.

The old app doesn't need to read the DBIC objects, so I could use two caches -- one just for the DBIC-based application and the other for inter-app state sharing, but that's less than ideal.


--
Bill Moseley
[hidden email]

_______________________________________________
List: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/dbix-class
IRC: irc.perl.org#dbix-class
SVN: http://dev.catalyst.perl.org/repos/bast/DBIx-Class/
Searchable Archive: http://www.grokbase.com/group/dbix-class@...
Bill Moseley

Re: Using Storable with DBIx::Class - Can't locate object method "result_source_instance"

Reply Threaded More More options
Print post
Permalink
$VERSION = '0.08111';

Ok, starting simple, what's the correct way to store and retrieve dbic row objects from Storable?

#!/usr/bin/perl
use warnings;
use strict;
use Storable;
use MyApp;

my $schema = MyApp->connect({ dsn => 'dbi:Pg:database=music' });

my $artist = $schema->resultset( 'Artist' )->find( 1 );
my @cds = $artist->cds;

warn "storing\n";
store { artist => $artist, }, 'stored';

warn "retrieve\n";
my $h = retrieve 'stored';

warn "calling ->cds on deserialized object\n";
$h->{artist}->cds;

Results in:

storing
retrieve
Unable to restore schema at ../../lib/Storable.pm (autosplit into ../../lib/auto/Storable/thaw.al) line 415
calling ->cds on deserialized object
Can't call method "source" on an undefined value at /usr/local/share/perl/5.10.0/DBIx/Class/R


My Artist class uses this base class, although I get the same thing regardless of including
Serialize::Storable.

package MyApp::Result;
use strict;
use warnings;
use base qw( DBIx::Class );

__PACKAGE__->load_components(qw/
    Serialize::Storable
    InflateColumn::DateTime
    Core
/);

1;


FYI, here's the Artist class.

package MyApp::Result::Artist;

use strict;
use warnings;

use base 'MyApp::Result';

#__PACKAGE__->load_components("InflateColumn::DateTime", "Core");
__PACKAGE__->table("artist");
__PACKAGE__->add_columns(
  "id",
  {
    data_type => "integer",
    default_value => "nextval('artist_id_seq'::regclass)",
    is_auto_increment => 1,
    is_nullable => 0,
    size => 4,
  },
  "name",
  {
    data_type => "text",
    default_value => undef,
    is_nullable => 1,
    size => undef,
  },
  "label",
  {
    data_type => "integer",
    default_value => undef,
    is_foreign_key => 1,
    is_nullable => 0,
    size => 4,
  },
);
__PACKAGE__->set_primary_key("id");
__PACKAGE__->belongs_to("label", "MyApp::Result::Label", { id => "label" });
__PACKAGE__->has_many("cds", "MyApp::Result::Cd", { "foreign.artist" => "self.id" });


# Created by DBIx::Class::Schema::Loader v0.04999_08 @ 2009-09-21 11:25:54
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:VpcwTJEGCmz+LZCDMjwqqw


# You can replace this text with custom content, and it will be preserved on regeneration
1;


--
Bill Moseley
[hidden email]

_______________________________________________
List: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/dbix-class
IRC: irc.perl.org#dbix-class
SVN: http://dev.catalyst.perl.org/repos/bast/DBIx-Class/
Searchable Archive: http://www.grokbase.com/group/dbix-class@...
Wallace Reis

Re: Re: Using Storable with DBIx::Class - Can't locate object method "result_source_instance"

Reply Threaded More More options
Print post
Permalink
On Wed, Sep 30, 2009 at 1:10 PM, Bill Moseley <[hidden email]> wrote:
> $VERSION = '0.08111';
>
> Ok, starting simple, what's the correct way to store and retrieve dbic row
> objects from Storable?
> Unable to restore schema at ../../lib/Storable.pm (autosplit into
> ../../lib/auto/Storable/thaw.al) line 415
> calling ->cds on deserialized object
> Can't call method "source" on an undefined value at
> /usr/local/share/perl/5.10.0/DBIx/Class/R

The error message is clever in 0.08112. You need to 'freeze' and
'thaw' your dbic row. Look at DBIC::Schema docs about it.

--
     wallace reis/wreis         Catalyst and DBIx::Class consultancy with a clue
     Software Engineer and a commit bit: http://shadowcat.co.uk/catalyst/
 Shadowcat Systems Limited
 http://www.shadowcat.co.uk     http://www.linkedin.com/in/wallacereis

_______________________________________________
List: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/dbix-class
IRC: irc.perl.org#dbix-class
SVN: http://dev.catalyst.perl.org/repos/bast/DBIx-Class/
Searchable Archive: http://www.grokbase.com/group/dbix-class@...
Bill Moseley

Re: Re: Using Storable with DBIx::Class - Can't locate object method "result_source_instance"

Reply Threaded More More options
Print post
Permalink


On Wed, Sep 30, 2009 at 3:00 PM, Wallace Reis <[hidden email]> wrote:

> Unable to restore schema at ../../lib/Storable.pm (autosplit into
> ../../lib/auto/Storable/thaw.al) line 415
> calling ->cds on deserialized object
> Can't call method "source" on an undefined value at
> /usr/local/share/perl/5.10.0/DBIx/Class/R

The error message is clever in 0.08112. You need to 'freeze' and
'thaw' your dbic row. Look at DBIC::Schema docs about it.

Well, I wonder about that message.   That would have me think that the approach would be to do a Storable round trip like:

$schema->thaw( $schema->freeze( $artist ) );

And then a common use case might be to store an object in a session hash, as with Catalyst.  Are you saying that the recommended approach is this?

$c->session->{foo} = $schema->freeze( $object );

And then later

$object = $schema->thaw( $c->session->{foo} );

Which ends up running through Storable twice.

I wonder if that message should not point to the DBIx::Class::ResultSourceHandle docs (which is where it is generated from).  There it would point out that you can set

$DBIx::Class::ResultSourceHandle::thaw_schema = $schema;

before thawing and then the Storable hooks will work.  There it also recommends using $schema->thaw, but then it's back to pre-serializing, unless I'm missing the expected use.

Of course, a global $schema is sometimes not desirable.  Perhaps allowing thaw_schema to be a coderef might be useful as then you could inspect the deserialized object and have a chance at selecting and returning the correct schema.


Then, there's  DBIx::Class::Serialize::Storable with the synopsis:
    my $cd = $schema->resultset('CD')->find(12);
# if the cache uses Storable, this will work automatically
$cache->set($cd->ID, $cd);
What does that do?  Freezing isn't the issue.  Plus, seems that $cd freezes and thaws fine without it.  And that synopsis isn't showing the $cache->get.  I guess I'm missing the point of that component.



--
Bill Moseley
[hidden email]

_______________________________________________
List: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/dbix-class
IRC: irc.perl.org#dbix-class
SVN: http://dev.catalyst.perl.org/repos/bast/DBIx-Class/
Searchable Archive: http://www.grokbase.com/group/dbix-class@...
Alexander Hartmaier

Re: Re: Using Storable with DBIx::Class - Can't locate object method "result_source_instance"

Reply Threaded More More options
Print post
Permalink
Am Donnerstag, den 01.10.2009, 03:41 +0200 schrieb Bill Moseley:

>
>
> On Wed, Sep 30, 2009 at 3:00 PM, Wallace Reis <[hidden email]>
> wrote:
>
>
>         > Unable to restore schema at ../../lib/Storable.pm (autosplit
>         into
>         > ../../lib/auto/Storable/thaw.al) line 415
>         > calling ->cds on deserialized object
>         > Can't call method "source" on an undefined value at
>         > /usr/local/share/perl/5.10.0/DBIx/Class/R
>
>
>         The error message is clever in 0.08112. You need to 'freeze'
>         and
>         'thaw' your dbic row. Look at DBIC::Schema docs about it.
>
> Well, I wonder about that message.   That would have me think that the
> approach would be to do a Storable round trip like:
>
>
> $schema->thaw( $schema->freeze( $artist ) );

I'd like this more because the $artist knows about his schema, using a
different one might end up in unexpected results:

$schema->thaw( $artist->freeze );

>
>
> And then a common use case might be to store an object in a session
> hash, as with Catalyst.  Are you saying that the recommended approach
> is this?
>
> $c->session->{foo} = $schema->freeze( $object );
>
> And then later
>
> $object = $schema->thaw( $c->session->{foo} );
>
> Which ends up running through Storable twice.
>
> I wonder if that message should not point to the
> DBIx::Class::ResultSourceHandle docs (which is where it is generated
> from).  There it would point out that you can set
>
> $DBIx::Class::ResultSourceHandle::thaw_schema = $schema;
>
>
> before thawing and then the Storable hooks will work.  There it also
> recommends using $schema->thaw, but then it's back to pre-serializing,
> unless I'm missing the expected use.
>
> Of course, a global $schema is sometimes not desirable.  Perhaps
> allowing thaw_schema to be a coderef might be useful as then you could
> inspect the deserialized object and have a chance at selecting and
> returning the correct schema.
>
>
> Then, there's  DBIx::Class::Serialize::Storable with the synopsis:
> my $cd = $schema->resultset('CD')->find(12);
>     # if the cache uses Storable, this will work automatically
>     $cache->set($cd->ID, $cd);
>
> What does that do?  Freezing isn't the issue.  Plus, seems that $cd
> freezes and thaws fine without it.  And that synopsis isn't showing
> the $cache->get.  I guess I'm missing the point of that component.
>
>
>
>
> --
> Bill Moseley
> [hidden email]
--
best regards, Alex


*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*
T-Systems Austria GesmbH   Rennweg 97-99, 1030 Wien
Handelsgericht Wien, FN 79340b
*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*
Notice: This e-mail contains information that is confidential and may be privileged.
If you are not the intended recipient, please notify the sender and then
delete this e-mail immediately.
*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*

_______________________________________________
List: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/dbix-class
IRC: irc.perl.org#dbix-class
SVN: http://dev.catalyst.perl.org/repos/bast/DBIx-Class/
Searchable Archive: http://www.grokbase.com/group/dbix-class@...
Bill Moseley

Re: Re: Using Storable with DBIx::Class - Can't locate object method "result_source_instance"

Reply Threaded More More options
Print post
Permalink


On Thu, Oct 1, 2009 at 12:33 AM, Alexander Hartmaier <[hidden email]> wrote:
I'd like this more because the $artist knows about his schema, using a
different one might end up in unexpected results:

$schema->thaw( $artist->freeze );

True.  Well at for the freeze step anyway.  Have to supply a $schema on thaw.  (Plus, freeze is not a method on $artist).


Back to my original question.  Which turned out to be two questions.

First, I never got anyone to comment (commit) on how to save dbic objects in a session hash.  Is that not done by anyone?  Or is it:

$c->session->{foo} = $schema->freeze( $foo );

Then later:

$foo = $c->$schema->thaw( $c->session->{foo} ) if exists $c->session->{foo};

I assume running the serialized $foo though Storable again is not a significant performance issue.


And my original question:

Legacy application has session data in Memcached.  Runs on separate machines.  No DBIx::Class installed (and not sure could install if dependencies cause breakage).  New Catalyst application should transparently handle some new pages on application.  Users should be able to move seemlessly (and transparently) between two applications.  Two applications need to share state information in session back-and-forth.

If dbic is not on legacy machines then can't have dbic objects in any data thawed by Storable.

Suggestions?  Use two different sessions on the new (dbic) application?

Do ugly hack on legacy app so that Storeable won't try and load dbic?

{
    no warnings 'redefine';
    sub DBIx::Class::ResultSet::STORABLE_thaw {}
    sub DBIx::Class::ResultSourceHandle::STORABLE_thaw {}

    $INC{'DBIx/Class/ResultSet.pm'} = 1;
    $INC{'DBIx/Class/ResultSourceHandle.pm'} = 1;

    DBIx::Class::ResultSourceHandle->overload::OVERLOAD(q/""/ => sub {});
    DBIx::Class::ResultSet->overload::OVERLOAD(q/""/ => sub {});
}




--
Bill Moseley
[hidden email]

_______________________________________________
List: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/dbix-class
IRC: irc.perl.org#dbix-class
SVN: http://dev.catalyst.perl.org/repos/bast/DBIx-Class/
Searchable Archive: http://www.grokbase.com/group/dbix-class@...