Skip to content

Instantly share code, notes, and snippets.

@bokutin
Created May 14, 2016 21:00
Show Gist options
  • Save bokutin/5a5deb2eef789691267d979b83433f07 to your computer and use it in GitHub Desktop.
Save bokutin/5a5deb2eef789691267d979b83433f07 to your computer and use it in GitHub Desktop.
DBIx::Class and sereal
#!/usr/bin/env perl
use rlib;
use MyApp::Container qw(container);
use Modern::Perl;
use Sereal qw(encode_sereal);
my $id = 1234;
my $rs1 = container('schema')->resultset('Item')->search(
undef,
{
prefetch => [
'too_many_rels',
],
}
);
my $rs2 = container('schema')->resultset('Item')->search(
undef,
{
prefetch => [
'too_many_rels',
],
}
)->hashref_rs;
{
no strict 'refs';
*DBIx::Class::ResultSet::FREEZE = sub {
my ($self, $serializer) = @_;
my $to_serialize = { %$self };
# A cursor in progress can't be serialized (and would make little sense anyway)
# the parser can be regenerated (and can't be serialized)
delete @{$to_serialize}{qw/cursor _row_parser _result_inflator/};
# nor is it sensical to store a not-yet-fired-count pager
if ($to_serialize->{pager} and ref $to_serialize->{pager}{total_entries} eq 'CODE') {
delete $to_serialize->{pager};
}
$to_serialize;
};
*DBIx::Class::ResultSet::THAW = sub {
my ($class, $serializer, $data) = @_;
bless $data, $class;
};
*DBIx::Class::ResultSource::FREEZE = sub {
$_[0]->handle;
};
*DBIx::Class::ResultSource::THAW = sub {
my ($class, $serializer, $self) = @_;
$self->resolve;
};
*DBIx::Class::ResultSourceHandle::FREEZE = sub {
my ($self, $serializer) = @_;
my $to_serialize = { %$self };
delete $to_serialize->{schema};
delete $to_serialize->{_detached_source};
$to_serialize->{_frozen_from_class} = $self->{schema}
? $self->{schema}->class($self->source_moniker)
: $self->{_detached_source}->result_class
;
$to_serialize;
};
*DBIx::Class::ResultSourceHandle::THAW = sub {
my ($class, $serializer, $data) = @_;
my $self = bless $data, $class;
my $thaw_schema = container('schema');
my $from_class = delete $self->{_frozen_from_class};
if( $thaw_schema ) {
$self->schema( $thaw_schema );
}
elsif( my $rs = $from_class->result_source_instance ) {
# in the off-chance we are using CDBI-compat and have leaked $schema already
if( my $s = dbic_internal_try { $rs->schema } ) {
$self->schema( $s );
}
else {
$rs->source_name( $self->source_moniker );
$rs->{_detached_thaw} = 1;
$self->_detached_source( $rs );
}
}
else {
DBIx::Class::Exception->throw(
"Thaw failed - original result class '$from_class' does not exist on this system"
);
}
$self;
};
}
my $encoder = Sereal::Encoder->new( { freeze_callbacks => 1 } );
my $decoder = Sereal::Decoder->new();
my $obj = $rs1->find($id) or die;
my $hashref = $rs2->find($id) or die;
# {
# my $schema = container('schema');
# my $obj = $schema->thaw($schema->freeze($obj));
# }
#
# {
# my $obj = $decoder->decode($encoder->encode($obj));
# }
use Benchmark qw(:all :hireswallclock);
use Storable qw(nfreeze);
my $schema = container('schema');
my $count = 3000;
cmpthese($count, {
fetch_obj => sub {
$rs1->find($id) or die;
},
fetch_hashref => sub {
$rs2->find($id) or die;
},
storable_obj => sub {
$schema->freeze($obj);
},
sereal_obj => sub {
$encoder->encode($obj);
},
storable_hashref => sub {
nfreeze($hashref);
},
sereal_hashref => sub {
encode_sereal($hashref);
},
});
__END__
Rate fetch_obj fetch_hashref storable_obj sereal_obj storable_hashref sereal_hashref
fetch_obj 40.3/s -- -7% -97% -100% -100% -100%
fetch_hashref 43.2/s 7% -- -97% -99% -100% -100%
storable_obj 1444/s 3486% 3245% -- -82% -97% -98%
sereal_obj 8170/s 20198% 18832% 466% -- -85% -87%
storable_hashref 54857/s 136186% 127014% 3700% 571% -- -14%
sereal_hashref 64000/s 158900% 148200% 4333% 683% 17% --
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment