Added set_schema and fixed previously bad calls ($self->$_).
[dbsrgits/DBIx-Class.git] / lib / DBIx / Class / Storage / DBI / Replication.pm
CommitLineData
325e3466 1package DBIx::Class::Storage::DBI::Replication;
2
3use strict;
4use warnings;
5
6use DBIx::Class::Storage::DBI;
7use DBD::Multi;
8use base qw/Class::Accessor::Fast/;
9
10__PACKAGE__->mk_accessors( qw/read_source write_source/ );
11
12=head1 NAME
13
14DBIx::Class::Storage::DBI::Replication - Replicated database support
15
16=head1 SYNOPSIS
17
18 # change storage_type in your schema class
19 $schema->storage_type( '::DBI::Replication' );
20 $schema->connect_info( [
21 [ "dbi:mysql:database=test;hostname=master", "username", "password", { AutoCommit => 1 } ], # master
22 [ "dbi:mysql:database=test;hostname=slave1", "username", "password", { priority => 10 } ], # slave1
23 [ "dbi:mysql:database=test;hostname=slave2", "username", "password", { priority => 10 } ], # slave2
82aa2963 24 <...>,
25 { limit_dialect => 'LimitXY' } # If needed, see below
325e3466 26 ] );
27
28=head1 DESCRIPTION
29
30This class implements replicated data store for DBI. Currently you can define one master and numerous slave database
31connections. All write-type queries (INSERT, UPDATE, DELETE and even LAST_INSERT_ID) are routed to master database,
32all read-type queries (SELECTs) go to the slave database.
33
34For every slave database you can define a priority value, which controls data source usage pattern. It uses
35L<DBD::Multi>, so first the lower priority data sources used (if they have the same priority, the are used
36randomized), than if all low priority data sources fail, higher ones tried in order.
37
82aa2963 38=head1 CONFIGURATION
39
40=head2 Limit dialect
41
42If you use LIMIT in your queries (effectively, if you use SQL::Abstract::Limit), do not forget to set up limit_dialect (perldoc SQL::Abstract::Limit) by passing it as an option in the (optional) hash reference to connect_info.
43DBIC can not set it up automatically, since it can not guess DBD::Multi connection types.
44
325e3466 45=cut
46
47sub new {
48 my $proto = shift;
49 my $class = ref( $proto ) || $proto;
dbc6d854 50 my $self = {};
325e3466 51
52 bless( $self, $class );
53
54 $self->write_source( DBIx::Class::Storage::DBI->new );
55 $self->read_source( DBIx::Class::Storage::DBI->new );
56
57 return $self;
58}
59
60sub all_sources {
61 my $self = shift;
62
dbc6d854 63 my @sources = ($self->read_source, $self->write_source);
325e3466 64
65 return wantarray ? @sources : \@sources;
66}
67
68sub connect_info {
69 my( $self, $source_info ) = @_;
70
85c23e63 71 my( $info, $global_options, $options, @dsns );
82aa2963 72
85c23e63 73 $info = [ @$source_info ];
325e3466 74
85c23e63 75 $global_options = ref $info->[-1] eq 'HASH' ? pop( @$info ) : {};
76 if( ref( $options = $info->[0]->[-1] ) eq 'HASH' ) {
77 # Local options present in dsn, merge them with global options
78 map { $global_options->{$_} = $options->{$_} } keys %$options;
79 pop @{$info->[0]};
80 }
81
82 # We need to copy-pass $global_options, since connect_info clears it while processing options
83 $self->write_source->connect_info( [ @{$info->[0]}, { %$global_options } ] );
84
85 @dsns = map { ($_->[3]->{priority} || 10) => $_ } @{$info}[1..@$info-1];
86 $global_options->{dsns} = \@dsns;
87
88 $self->read_source->connect_info( [ 'dbi:Multi:', undef, undef, { %$global_options } ] );
325e3466 89}
90
91sub select {
dbc6d854 92 shift->read_source->select( @_ );
325e3466 93}
94sub select_single {
dbc6d854 95 shift->read_source->select_single( @_ );
325e3466 96}
97sub throw_exception {
dbc6d854 98 shift->read_source->throw_exception( @_ );
325e3466 99}
100sub sql_maker {
dbc6d854 101 shift->read_source->sql_maker( @_ );
325e3466 102}
103sub columns_info_for {
dbc6d854 104 shift->read_source->columns_info_for( @_ );
325e3466 105}
106sub sqlt_type {
dbc6d854 107 shift->read_source->sqlt_type( @_ );
325e3466 108}
109sub create_ddl_dir {
dbc6d854 110 shift->read_source->create_ddl_dir( @_ );
325e3466 111}
112sub deployment_statements {
dbc6d854 113 shift->read_source->deployment_statements( @_ );
325e3466 114}
115sub datetime_parser {
dbc6d854 116 shift->read_source->datetime_parser( @_ );
325e3466 117}
118sub datetime_parser_type {
dbc6d854 119 shift->read_source->datetime_parser_type( @_ );
325e3466 120}
121sub build_datetime_parser {
dbc6d854 122 shift->read_source->build_datetime_parser( @_ );
325e3466 123}
124
9b21c682 125sub limit_dialect { $_->limit_dialect( @_ ) for( shift->all_sources ) }
126sub quote_char { $_->quote_char( @_ ) for( shift->all_sources ) }
127sub name_sep { $_->quote_char( @_ ) for( shift->all_sources ) }
128sub disconnect { $_->disconnect( @_ ) for( shift->all_sources ) }
129sub set_schema { $_->set_schema( @_ ) for( shift->all_sources ) }
130
325e3466 131sub DESTROY {
132 my $self = shift;
133
dbc6d854 134 undef $self->{write_source};
135 undef $self->{read_sources};
325e3466 136}
137
138sub last_insert_id {
dbc6d854 139 shift->write_source->last_insert_id( @_ );
325e3466 140}
141sub insert {
dbc6d854 142 shift->write_source->insert( @_ );
325e3466 143}
144sub update {
dbc6d854 145 shift->write_source->update( @_ );
325e3466 146}
147sub update_all {
dbc6d854 148 shift->write_source->update_all( @_ );
325e3466 149}
150sub delete {
dbc6d854 151 shift->write_source->delete( @_ );
325e3466 152}
153sub delete_all {
dbc6d854 154 shift->write_source->delete_all( @_ );
325e3466 155}
156sub create {
dbc6d854 157 shift->write_source->create( @_ );
325e3466 158}
159sub find_or_create {
dbc6d854 160 shift->write_source->find_or_create( @_ );
325e3466 161}
162sub update_or_create {
dbc6d854 163 shift->write_source->update_or_create( @_ );
325e3466 164}
165sub connected {
dbc6d854 166 shift->write_source->connected( @_ );
325e3466 167}
168sub ensure_connected {
dbc6d854 169 shift->write_source->ensure_connected( @_ );
325e3466 170}
171sub dbh {
dbc6d854 172 shift->write_source->dbh( @_ );
325e3466 173}
174sub txn_begin {
dbc6d854 175 shift->write_source->txn_begin( @_ );
325e3466 176}
177sub txn_commit {
dbc6d854 178 shift->write_source->txn_commit( @_ );
325e3466 179}
180sub txn_rollback {
dbc6d854 181 shift->write_source->txn_rollback( @_ );
325e3466 182}
183sub sth {
dbc6d854 184 shift->write_source->sth( @_ );
325e3466 185}
186sub deploy {
dbc6d854 187 shift->write_source->deploy( @_ );
325e3466 188}
189
190
191sub debugfh { shift->_not_supported( 'debugfh' ) };
192sub debugcb { shift->_not_supported( 'debugcb' ) };
193
194sub _not_supported {
195 my( $self, $method ) = @_;
196
197 die "This Storage does not support $method method.";
198}
199
200=head1 SEE ALSO
201
202L<DBI::Class::Storage::DBI>, L<DBD::Multi>, L<DBI>
203
204=head1 AUTHOR
205
206Norbert Csongrádi <bert@cpan.org>
207
dbc6d854 208Peter Siklósi <einon@einon.hu>
325e3466 209
210=head1 LICENSE
211
212You may distribute this code under the same terms as Perl itself.
213
214=cut
215
2161;