refactored the duties of the different balancer classes, added tests and docs
[dbsrgits/DBIx-Class.git] / lib / DBIx / Class / Storage / DBI / Replicated / Balancer.pm
1 package DBIx::Class::Storage::DBI::Replicated::Balancer;
2
3 use Moose;
4
5 =head1 NAME
6
7 DBIx::Class::Storage::DBI::Replicated::Balancer; A Software Load Balancer 
8
9 =head1 SYNOPSIS
10
11 This class is used internally by L<DBIx::Class::Storage::DBI::Replicated>.  You
12 shouldn't need to create instances of this class.
13     
14 =head1 DESCRIPTION
15
16 Given a pool (L<DBIx::Class::Storage::DBI::Replicated::Pool>) of replicated
17 database's (L<DBIx::Class::Storage::DBI::Replicated::Replicant>), defines a
18 method by which query load can be spread out across each replicant in the pool.
19
20 =head1 ATTRIBUTES
21
22 This class defines the following attributes.
23
24 =head2 pool
25
26 The L<DBIx::Class::Storage::DBI::Replicated::Pool> object that we are trying to
27 balance.
28
29 =cut
30
31 has 'pool' => (
32     is=>'ro',
33     isa=>'DBIx::Class::Storage::DBI::Replicated::Pool',
34     required=>1,
35 );
36
37 =head2 current_replicant
38
39 Replicant storages (slaves) handle all read only traffic.  The assumption is
40 that your database will become readbound well before it becomes write bound
41 and that being able to spread your read only traffic around to multiple 
42 databases is going to help you to scale traffic.
43
44 This attribute returns the next slave to handle a read request.  Your L</pool>
45 attribute has methods to help you shuffle through all the available replicants
46 via it's balancer object.
47
48 =cut
49
50 has 'current_replicant' => (
51     is=> 'rw',
52     isa=>'DBIx::Class::Storage::DBI',
53     lazy_build=>1,
54     handles=>[qw/
55         select
56         select_single
57         columns_info_for
58     /],
59 );
60
61 =head1 METHODS
62
63 This class defines the following methods.
64
65 =head2 _build_current_replicant
66
67 Lazy builder for the L</current_replicant_storage> attribute.
68
69 =cut
70
71 sub _build_current_replicant {
72     my $self = shift @_;
73     $self->next_storage($self->pool);
74 }
75
76 =head2 next_storage
77
78 Given a pool object, return the next replicant that will serve queries.  The
79 default behavior is to grap the first replicant it finds but you can write 
80 your own subclasses of L<DBIx::Class::Storage::DBI::Replicated::Balancer> to 
81 support other balance systems.
82
83 =cut
84
85 sub next_storage {
86         my $self = shift @_;
87         return ($self->pool->active_replicants)[0]
88           if $self->pool->active_replicants;
89 }
90
91 =head2 after: select
92
93 Advice on the select attribute.  Each time we use a replicant
94 we need to change it via the storage pool algorithm.  That way we are spreading
95 the load evenly (hopefully) across existing capacity.
96
97 =cut
98
99 after 'select' => sub {
100     my $self = shift @_;
101     my $next_replicant = $self->next_storage;
102     $self->current_replicant($next_replicant);
103 };
104
105 =head2 after: select_single
106
107 Advice on the select_single attribute.  Each time we use a replicant
108 we need to change it via the storage pool algorithm.  That way we are spreading
109 the load evenly (hopefully) across existing capacity.
110
111 =cut
112
113 after 'select_single' => sub {
114     my $self = shift @_;
115     my $next_replicant = $self->next_storage;
116     $self->current_replicant($next_replicant);
117 };
118
119 =head2 after: columns_info_for
120
121 Advice on the current_replicant_storage attribute.  Each time we use a replicant
122 we need to change it via the storage pool algorithm.  That way we are spreading
123 the load evenly (hopefully) across existing capacity.
124
125 =cut
126
127 after 'columns_info_for' => sub {
128     my $self = shift @_;
129     my $next_replicant = $self->next_storage;
130     $self->current_replicant($next_replicant);
131 };
132
133 =head1 AUTHOR
134
135 John Napiorkowski <john.napiorkowski@takkle.com>
136
137 =head1 LICENSE
138
139 You may distribute this code under the same terms as Perl itself.
140
141 =cut
142
143 1;