682e46845548b9a86f030ea7ee1c3279123256c4
[catagits/Catalyst-Model-DBIC-Schema.git] / lib / Catalyst / TraitFor / Model / DBIC / Schema / Replicated.pm
1 package Catalyst::TraitFor::Model::DBIC::Schema::Replicated;
2
3 ## WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
4 ## If you make changes to this code and don't actually go and test it
5 ## on a real replicated environment I will rip you an new hole.  The
6 ## test suite DOES NOT properly test this.  --JNAP
7
8 use namespace::autoclean;
9 use Moose::Role;
10 use Carp::Clan '^Catalyst::Model::DBIC::Schema';
11
12 use Catalyst::Model::DBIC::Schema::Types qw/ConnectInfos LoadedClass/;
13 use MooseX::Types::Moose qw/Str HashRef/;
14
15 use Module::Runtime;
16
17 =head1 NAME
18
19 Catalyst::TraitFor::Model::DBIC::Schema::Replicated - Replicated storage support for
20 L<Catalyst::Model::DBIC::Schema>
21
22 =head1 SYNOPSiS
23
24     __PACKAGE__->config({
25         traits => ['Replicated']
26         connect_info =>
27             ['dbi:mysql:master', 'user', 'pass'],
28         replicants => [
29             ['dbi:mysql:slave1', 'user', 'pass'],
30             ['dbi:mysql:slave2', 'user', 'pass'],
31             ['dbi:mysql:slave3', 'user', 'pass'],
32         ],
33         balancer_args => {
34           master_read_weight => 0.3
35         }
36     });
37
38 =head1 DESCRIPTION
39
40 Sets your storage_type to L<DBIx::Class::Storage::DBI::Replicated> and connects
41 replicants provided in config. See that module for supported resultset
42 attributes.
43
44 The default L<DBIx::Class::Storage::DBI::Replicated/balancer_type> is
45 C<::Random>.
46
47 Sets the
48 L<DBIx::Class::Storage::DBI::Replicated::Balancer::Random/master_read_weight> to
49 C<1> by default, meaning that you have the same chance of reading from master as
50 you do from replicants. Set to C<0> to turn off reads from master.
51
52 =head1 CONFIG PARAMETERS
53
54 =head2 replicants
55
56 Array of connect_info settings for every replicant.
57
58 The following can be set via L<Catalyst::Model::DBIC::Schema/connect_info>, or
59 as their own parameters. If set via separate parameters, they will override the
60 settings in C<connect_info>.
61
62 =head2 pool_type
63
64 See L<DBIx::Class::Storage::DBI::Replicated/pool_type>.
65
66 =head2 pool_args
67
68 See L<DBIx::Class::Storage::DBI::Replicated/pool_args>.
69
70 =head2 balancer_type
71
72 See L<DBIx::Class::Storage::DBI::Replicated/balancer_type>.
73
74 =head2 balancer_args
75
76 See L<DBIx::Class::Storage::DBI::Replicated/balancer_args>.
77
78 =cut
79
80 has replicants => (
81     is => 'ro', isa => ConnectInfos, coerce => 1, required => 1
82 );
83
84 # If you change LoadedClass with LoadableClass I will rip you a new hole,
85 # it doesn't work exactly the same - JNAP
86
87 has pool_type => (is => 'ro', isa => LoadedClass);
88 has pool_args => (is => 'ro', isa => HashRef);
89 has balancer_type => (is => 'ro', isa => Str);
90 has balancer_args => (is => 'ro', isa => HashRef);
91
92 after setup => sub {
93     my $self = shift;
94
95 # check storage_type compatibility (if configured)
96     if (my $storage_type = $self->storage_type) {
97         my $class = $storage_type =~ /^::/ ?
98             "DBIx::Class::Storage$storage_type"
99             : $storage_type;
100
101             # For some odd reason if you try to use 'use_module' as an export
102             # the code breaks.  I guess something odd about MR and all these
103             # runtime loaded crazy trait code.  Please don't "tidy the code up" -JNAP
104             Module::Runtime::use_module($class);
105
106         croak "This storage_type cannot be used with replication"
107             unless $class->isa('DBIx::Class::Storage::DBI::Replicated');
108     } else {
109         $self->storage_type('::DBI::Replicated');
110     }
111
112     my $connect_info = $self->connect_info;
113
114     $connect_info->{pool_type} = $self->pool_type
115         if $self->pool_type;
116
117     $connect_info->{pool_args} = $self->pool_args
118         if $self->pool_args;
119
120     $connect_info->{balancer_type} = $self->balancer_type ||
121         $connect_info->{balancer_type} || '::Random';
122
123     $connect_info->{balancer_args} = $self->balancer_args ||
124         $connect_info->{balancer_args} || {};
125
126     $connect_info->{balancer_args}{master_read_weight} = 1
127         unless exists $connect_info->{balancer_args}{master_read_weight};
128 };
129
130 sub BUILD {}
131
132 after BUILD => sub {
133     my $self = shift;
134
135     $self->storage->connect_replicants(map [ $_ ], @{ $self->replicants });
136 };
137
138 =head1 SEE ALSO
139
140 L<Catalyst::Model::DBIC::Schema>, L<DBIx::Class>,
141 L<DBIx::Class::Storage::DBI::Replicated>,
142 L<Catalyst::TraitFor::Model::DBIC::Schema::Caching>
143
144 =head1 AUTHOR
145
146 See L<Catalyst::Model::DBIC::Schema/AUTHOR> and
147 L<Catalyst::Model::DBIC::Schema/CONTRIBUTORS>.
148
149 =head1 COPYRIGHT
150
151 See L<Catalyst::Model::DBIC::Schema/COPYRIGHT>.
152
153 =head1 LICENSE
154
155 This program is free software, you can redistribute it and/or modify it
156 under the same terms as Perl itself.
157
158 =cut
159
160 1;