1 package DBIx::Class::Storage::DBI::Replicated;
6 use DBIx::Class::Storage::DBI;
9 use base qw/Class::Accessor::Fast/;
11 __PACKAGE__->mk_accessors( qw/read_source write_source/ );
15 DBIx::Class::Storage::DBI::Replicated - ALPHA Replicated database support
19 The Following example shows how to change an existing $schema to a replicated
20 storage type and update it's connection information to contain a master DSN and
23 ## Change storage_type in your schema class
24 $schema->storage_type( '::DBI::Replicated' );
26 ## Set your connection.
28 $dsn, $user, $password, {
30 ## Other standard DBI connection or DBD custom attributes added as
31 ## usual. Additionally, we have two custom attributes for defining
32 ## slave information and controlling how the underlying DBD::Multi
33 slaves_connect_info => [
34 ## Define each slave like a 'normal' DBI connection, but you add
35 ## in a DBD::Multi custom attribute to define how the slave is
36 ## prioritized. Please see DBD::Multi for more.
37 [$slave1dsn, $user, $password, {%slave1opts, priority=>10}],
38 [$slave2dsn, $user, $password, {%slave2opts, priority=>10}],
39 [$slave3dsn, $user, $password, {%slave3opts, priority=>20}],
40 ## add in a preexisting database handle
41 [$dbh, '','', {priority=>30}],
42 ## DBD::Multi will call this coderef for connects
43 [sub { DBI->connect(< DSN info >) }, '', '', {priority=>40}],
44 ## If the last item is hashref, we use that for DBD::Multi's
45 ## configuration information. Again, see DBD::Multi for more.
46 {timeout=>25, failed_max=>2},
51 ## Now, just use the schema as normal
52 $schema->resultset('Table')->find(< unique >); ## Reads will use slaves
53 $schema->resultset('Table')->create(\%info); ## Writes will use master
57 Warning: This class is marked ALPHA. We are using this in development and have
58 some basic test coverage but the code hasn't yet been stressed by a variety
59 of databases. Individual DB's may have quirks we are not aware of. Please
60 use this in development and pass along your experiences/bug fixes.
62 This class implements replicated data store for DBI. Currently you can define
63 one master and numerous slave database connections. All write-type queries
64 (INSERT, UPDATE, DELETE and even LAST_INSERT_ID) are routed to master
65 database, all read-type queries (SELECTs) go to the slave database.
67 For every slave database you can define a priority value, which controls data
68 source usage pattern. It uses L<DBD::Multi>, so first the lower priority data
69 sources used (if they have the same priority, the are used randomized), than
70 if all low priority data sources fail, higher ones tried in order.
74 Please see L<DBD::Multi> for most configuration information.
80 my $class = ref( $proto ) || $proto;
83 bless( $self, $class );
85 $self->write_source( DBIx::Class::Storage::DBI->new );
86 $self->read_source( DBIx::Class::Storage::DBI->new );
94 my @sources = ($self->read_source, $self->write_source);
96 return wantarray ? @sources : \@sources;
101 my $master = $self->write_source->_connect_info;
102 $master->[-1]->{slave_connect_info} = $self->read_source->_connect_info;
107 my ($self, $source_info) = @_;
109 ## if there is no $source_info, treat this sub like an accessor
110 return $self->_connect_info
113 ## Alright, let's conect the master
114 $self->write_source->connect_info($source_info);
116 ## Now, build and then connect the Slaves
117 my @slaves_connect_info = @{$source_info->[-1]->{slaves_connect_info}};
118 my $dbd_multi_config = ref $slaves_connect_info[-1] eq 'HASH'
119 ? pop @slaves_connect_info : {};
121 ## We need to do this since SQL::Abstract::Limit can't guess what DBD::Multi is
122 $dbd_multi_config->{limit_dialect} = $self->write_source->sql_maker->limit_dialect
123 unless defined $dbd_multi_config->{limit_dialect};
125 @slaves_connect_info = map {
126 ## if the first element in the arrayhash is a ref, make that the value
127 my $db = ref $_->[0] ? $_->[0] : $_;
128 my $priority = $_->[-1]->{priority} || 10; ## default priority is 10
130 } @slaves_connect_info;
132 $self->read_source->connect_info([
133 'dbi:Multi:', undef, undef, {
134 dsns => [@slaves_connect_info],
139 ## Return the formated connection information
140 return $self->_connect_info;
144 shift->read_source->select( @_ );
147 shift->read_source->select_single( @_ );
149 sub throw_exception {
150 shift->read_source->throw_exception( @_ );
153 shift->read_source->sql_maker( @_ );
155 sub columns_info_for {
156 shift->read_source->columns_info_for( @_ );
159 shift->read_source->sqlt_type( @_ );
162 shift->read_source->create_ddl_dir( @_ );
164 sub deployment_statements {
165 shift->read_source->deployment_statements( @_ );
167 sub datetime_parser {
168 shift->read_source->datetime_parser( @_ );
170 sub datetime_parser_type {
171 shift->read_source->datetime_parser_type( @_ );
173 sub build_datetime_parser {
174 shift->read_source->build_datetime_parser( @_ );
177 sub limit_dialect { $_->limit_dialect( @_ ) for( shift->all_sources ) }
178 sub quote_char { $_->quote_char( @_ ) for( shift->all_sources ) }
179 sub name_sep { $_->quote_char( @_ ) for( shift->all_sources ) }
180 sub disconnect { $_->disconnect( @_ ) for( shift->all_sources ) }
181 sub set_schema { $_->set_schema( @_ ) for( shift->all_sources ) }
186 undef $self->{write_source};
187 undef $self->{read_sources};
191 shift->write_source->last_insert_id( @_ );
194 shift->write_source->insert( @_ );
197 shift->write_source->update( @_ );
200 shift->write_source->update_all( @_ );
203 shift->write_source->delete( @_ );
206 shift->write_source->delete_all( @_ );
209 shift->write_source->create( @_ );
212 shift->write_source->find_or_create( @_ );
214 sub update_or_create {
215 shift->write_source->update_or_create( @_ );
218 shift->write_source->connected( @_ );
220 sub ensure_connected {
221 shift->write_source->ensure_connected( @_ );
224 shift->write_source->dbh( @_ );
227 shift->write_source->txn_do( @_ );
230 shift->write_source->txn_commit( @_ );
233 shift->write_source->txn_rollback( @_ );
236 shift->write_source->sth( @_ );
239 shift->write_source->deploy( @_ );
241 sub _prep_for_execute {
242 shift->write_source->_prep_for_execute(@_);
246 shift->write_source->debugobj(@_);
249 shift->write_source->debug(@_);
252 sub debugfh { shift->_not_supported( 'debugfh' ) };
253 sub debugcb { shift->_not_supported( 'debugcb' ) };
256 my( $self, $method ) = @_;
258 die "This Storage does not support $method method.";
263 L<DBI::Class::Storage::DBI>, L<DBD::Multi>, L<DBI>
267 Norbert Csongrádi <bert@cpan.org>
269 Peter Siklósi <einon@einon.hu>
271 John Napiorkowski <john.napiorkowski@takkle.com>
275 You may distribute this code under the same terms as Perl itself.