DBI
view release on metacpan or search on metacpan
lib/DBD/Gofer.pm view on Meta::CPAN
# do the store locally anyway, just in case
$sth->SUPER::STORE($attrib => $value);
return $sth->set_err($DBI::stderr, $msg);
}
# sub bind_param_array
# we use DBI's default, which sets $sth->{ParamArrays}{$param} = $value
# and calls bind_param($param, undef, $attr) if $attr.
sub execute_array {
my $sth = shift;
my $attr = shift;
$sth->bind_param_array($_, $_[$_-1]) for (1..@_);
push @{ $sth->{go_method_calls} }, [ 'execute_array', $attr ];
return $sth->go_sth_method($attr);
}
*go_cache = \&DBD::Gofer::go_cache;
}
1;
__END__
=head1 NAME
DBD::Gofer - A stateless-proxy driver for communicating with a remote DBI
=head1 SYNOPSIS
use DBI;
$original_dsn = "dbi:..."; # your original DBI Data Source Name
$dbh = DBI->connect("dbi:Gofer:transport=$transport;...;dsn=$original_dsn",
$user, $passwd, \%attributes);
... use $dbh as if it was connected to $original_dsn ...
The C<transport=$transport> part specifies the name of the module to use to
transport the requests to the remote DBI. If $transport doesn't contain any
double colons then it's prefixed with C<DBD::Gofer::Transport::>.
The C<dsn=$original_dsn> part I<must be the last element> of the DSN because
everything after C<dsn=> is assumed to be the DSN that the remote DBI should
use.
The C<...> represents attributes that influence the operation of the Gofer
driver or transport. These are described below or in the documentation of the
transport module being used.
=encoding ISO8859-1
=head1 DESCRIPTION
DBD::Gofer is a DBI database driver that forwards requests to another DBI
driver, usually in a separate process, often on a separate machine. It tries to
be as transparent as possible so it appears that you are using the remote
driver directly.
DBD::Gofer is very similar to DBD::Proxy. The major difference is that with
DBD::Gofer no state is maintained on the remote end. That means every
request contains all the information needed to create the required state. (So,
for example, every request includes the DSN to connect to.) Each request can be
sent to any available server. The server executes the request and returns a
single response that includes all the data.
This is very similar to the way http works as a stateless protocol for the web.
Each request from your web browser can be handled by a different web server process.
=head2 Use Cases
This may seem like pointless overhead but there are situations where this is a
very good thing. Let's consider a specific case.
Imagine using DBD::Gofer with an http transport. Your application calls
connect(), prepare("select * from table where foo=?"), bind_param(), and execute().
At this point DBD::Gofer builds a request containing all the information
about the method calls. It then uses the httpd transport to send that request
to an apache web server.
This 'dbi execute' web server executes the request (using DBI::Gofer::Execute
and related modules) and builds a response that contains all the rows of data,
if the statement returned any, along with all the attributes that describe the
results, such as $sth->{NAME}. This response is sent back to DBD::Gofer which
unpacks it and presents it to the application as if it had executed the
statement itself.
=head2 Advantages
Okay, but you still don't see the point? Well let's consider what we've gained:
=head3 Connection Pooling and Throttling
The 'dbi execute' web server leverages all the functionality of web
infrastructure in terms of load balancing, high-availability, firewalls, access
management, proxying, caching.
At its most basic level you get a configurable pool of persistent database connections.
=head3 Simple Scaling
Got thousands of processes all trying to connect to the database? You can use
DBD::Gofer to connect them to your smaller pool of 'dbi execute' web servers instead.
=head3 Caching
Client-side caching is as simple as adding "C<cache=1>" to the DSN.
This feature alone can be worth using DBD::Gofer for.
=head3 Fewer Network Round-trips
DBD::Gofer sends as few requests as possible (dependent on the policy being used).
=head3 Thin Clients / Unsupported Platforms
You no longer need drivers for your database on every system. DBD::Gofer is pure perl.
lib/DBD/Gofer.pm view on Meta::CPAN
$transport = $h->{go_transport};
$retry = $transport->go_retry_hook->($request, $response, $transport);
If it returns true then the request will be retried, up to the C<retry_limit>.
If it returns a false but defined value then the request will not be retried.
If it returns undef then the default behaviour will be used, as if C<retry_hook>
had not been specified.
The default behaviour is to retry requests where $request->is_idempotent is true,
or the error message matches C</induced by DBI_GOFER_RANDOM/>.
=head3 cache
Specifies that client-side caching should be performed. The value is the name
of a cache class to use.
Any class implementing get($key) and set($key, $value) methods can be used.
That includes a great many powerful caching classes on CPAN, including the
Cache and Cache::Cache distributions.
You can use "C<cache=1>" is a shortcut for "C<cache=DBI::Util::CacheMemory>".
See L<DBI::Util::CacheMemory> for a description of this simple fast default cache.
The cache object can be accessed via $h->go_cache. For example:
$dbh->go_cache->clear; # free up memory being used by the cache
The cache keys are the frozen (serialized) requests, and the values are the
frozen responses.
The default behaviour is to only use the cache for requests where
$request->is_idempotent is true (i.e., the dbh has the ReadOnly attribute set
or the SQL statement is obviously a SELECT without a FOR UPDATE clause.)
For even more control you can use the C<go_cache> attribute to pass in an
instantiated cache object. Individual methods, including prepare(), can also
specify alternative caches via the C<go_cache> attribute. For example, to
specify no caching for a particular query, you could use
$sth = $dbh->prepare( $sql, { go_cache => 0 } );
This can be used to implement different caching policies for different statements.
It's interesting to note that DBD::Gofer can be used to add client-side caching
to any (gofer compatible) application, with no code changes and no need for a
gofer server. Just set the DBI_AUTOPROXY environment variable like this:
DBI_AUTOPROXY='dbi:Gofer:transport=null;cache=1'
=head1 CONFIGURING BEHAVIOUR POLICY
DBD::Gofer supports a 'policy' mechanism that allows you to fine-tune the number of round-trips to the Gofer server.
The policies are grouped into classes (which may be subclassed) and referenced by the name of the class.
The L<DBD::Gofer::Policy::Base> class is the base class for all the policy
packages and describes all the available policies.
Three policy packages are supplied with DBD::Gofer:
L<DBD::Gofer::Policy::pedantic> is most 'transparent' but slowest because it
makes more round-trips to the Gofer server.
L<DBD::Gofer::Policy::classic> is a reasonable compromise - it's the default policy.
L<DBD::Gofer::Policy::rush> is fastest, but may require code changes in your applications.
Generally the default C<classic> policy is fine. When first testing an existing
application with Gofer it is a good idea to start with the C<pedantic> policy
first and then switch to C<classic> or a custom policy, for final testing.
=head1 AUTHOR
Tim Bunce, L<http://www.tim.bunce.name>
=head1 LICENCE AND COPYRIGHT
Copyright (c) 2007, Tim Bunce, Ireland. All rights reserved.
This module is free software; you can redistribute it and/or
modify it under the same terms as Perl itself. See L<perlartistic>.
=head1 ACKNOWLEDGEMENTS
The development of DBD::Gofer and related modules was sponsored by
Shopzilla.com (L<http://Shopzilla.com>), where I currently work.
=head1 SEE ALSO
L<DBI::Gofer::Request>, L<DBI::Gofer::Response>, L<DBI::Gofer::Execute>.
L<DBI::Gofer::Transport::Base>, L<DBD::Gofer::Policy::Base>.
L<DBI>
=head1 Caveats for specific drivers
This section aims to record issues to be aware of when using Gofer with specific drivers.
It usually only documents issues that are not natural consequences of the limitations
of the Gofer approach - as documented above.
=head1 TODO
This is just a random brain dump... (There's more in the source of the Changes file, not the pod)
Document policy mechanism
Add mechanism for transports to list config params and for Gofer to apply any that match (and warn if any left over?)
Driver-private sth attributes - set via prepare() - change DBI spec
add hooks into transport base class for checking & updating a result set cache
ie via a standard cache interface such as:
http://search.cpan.org/~robm/Cache-FastMmap/FastMmap.pm
http://search.cpan.org/~bradfitz/Cache-Memcached/lib/Cache/Memcached.pm
http://search.cpan.org/~dclinton/Cache-Cache/
http://search.cpan.org/~cleishman/Cache/
Also caching instructions could be passed through the httpd transport layer
in such a way that appropriate http cache headers are added to the results
so that web caches (squid etc) could be used to implement the caching.
( run in 1.843 second using v1.01-cache-2.11-cpan-75ffa21a3d4 )