converted replicant to a role so that we can apply it after ensure_connected properly...
[dbsrgits/DBIx-Class.git] / lib / DBIx / Class / Storage / DBI / Replicated / Pool.pm
1 package DBIx::Class::Storage::DBI::Replicated::Pool;
2
3 use Moose;
4 use MooseX::AttributeHelpers;
5 use DBIx::Class::Storage::DBI::Replicated::Replicant;
6 use List::Util qw(sum);
7
8 =head1 NAME
9
10 DBIx::Class::Storage::DBI::Replicated::Pool; Manage a pool of replicants
11
12 =head1 SYNOPSIS
13
14 This class is used internally by L<DBIx::Class::Storage::DBI::Replicated>.  You
15 shouldn't need to create instances of this class.
16     
17 =head1 DESCRIPTION
18
19 In a replicated storage type, there is at least one replicant to handle the
20 read only traffic.  The Pool class manages this replicant, or list of 
21 replicants, and gives some methods for querying information about their status.
22
23 =head1 ATTRIBUTES
24
25 This class defines the following attributes.
26
27 =head2 replicant_type
28
29 Base class used to instantiate replicants that are in the pool.  Unless you
30 need to subclass L<DBIx::Class::Storage::DBI::Replicated::Replicant> you should
31 just leave this alone.
32
33 =cut
34
35 has 'replicant_type' => (
36     is=>'ro',
37     isa=>'ClassName',
38     required=>1,
39     default=>'DBIx::Class::Storage::DBI',
40     handles=>{
41         'create_replicant' => 'new',
42     },  
43 );
44
45 =head2 replicants
46
47 A hashref of replicant, with the key being the dsn and the value returning the
48 actual replicant storage.  For example if the $dsn element is something like:
49
50     "dbi:SQLite:dbname=dbfile"
51     
52 You could access the specific replicant via:
53
54     $schema->storage->replicants->{'dbname=dbfile'}
55     
56 This attributes also supports the following helper methods
57
58 =over 4
59
60 =item set_replicant($key=>$storage)
61
62 Pushes a replicant onto the HashRef under $key
63
64 =item get_replicant($key)
65
66 Retrieves the named replicant
67
68 =item has_replicants
69
70 Returns true if the Pool defines replicants.
71
72 =item num_replicants
73
74 The number of replicants in the pool
75
76 =item delete_replicant ($key)
77
78 removes the replicant under $key from the pool
79
80 =back
81
82 =cut
83
84 has 'replicants' => (
85     is=>'rw',
86     metaclass => 'Collection::Hash',
87     isa=>'HashRef[DBIx::Class::Storage::DBI]',
88     default=>sub {{}},
89     provides  => {
90                 'set' => 'set_replicant',
91                 'get' => 'get_replicant',            
92                 'empty' => 'has_replicants',
93                 'count' => 'num_replicants',
94                 'delete' => 'delete_replicant',
95         },
96 );
97
98 =head1 METHODS
99
100 This class defines the following methods.
101
102 =head2 connect_replicants ($schema, Array[$connect_info])
103
104 Given an array of $dsn suitable for connected to a database, create an
105 L<DBIx::Class::Storage::DBI::Replicated::Replicant> object and store it in the
106 L</replicants> attribute.
107
108 =cut
109
110 use Data::Dump qw/dump/; 
111
112 sub connect_replicants {
113         my $self = shift @_;
114         my $schema = shift @_;
115         
116         my @newly_created = ();
117         foreach my $connect_info (@_) {
118                 
119                 my $replicant = $self->create_replicant($schema);
120                 $replicant->connect_info($connect_info);        
121                 $replicant->ensure_connected;
122                 
123                 DBIx::Class::Storage::DBI::Replicated::Replicant->meta->apply($replicant);
124                 
125                 my ($key) = ($connect_info->[0]=~m/^dbi\:.+\:(.+)$/);
126                 $self->set_replicant( $key => $replicant);      
127                 push @newly_created, $replicant;
128         }
129         
130         return @newly_created;
131 }
132
133 =head2 connected_replicants
134
135 Returns true if there are connected replicants.  Actually is overloaded to
136 return the number of replicants.  So you can do stuff like:
137
138     if( my $num_connected = $storage->has_connected_replicants ) {
139         print "I have $num_connected connected replicants";
140     } else {
141         print "Sorry, no replicants.";
142     }
143
144 This method will actually test that each replicant in the L</replicants> hashref
145 is actually connected, try not to hit this 10 times a second.
146
147 =cut
148
149 sub connected_replicants {
150         my $self = shift @_;
151         return sum( map {
152                 $_->connected ? 1:0
153         } $self->all_replicants );
154 }
155
156 =head2 active_replicants
157
158 This is an array of replicants that are considered to be active in the pool.
159 This does not check to see if they are connected, but if they are not, DBIC
160 should automatically reconnect them for us when we hit them with a query.
161
162 =cut
163
164 sub active_replicants {
165     my $self = shift @_;
166     return ( grep {$_} map {
167         $_->active ? $_:0
168     } $self->all_replicants );
169 }
170
171 =head2 all_replicants
172
173 Just a simple array of all the replicant storages.  No particular order to the
174 array is given, nor should any meaning be derived.
175
176 =cut
177
178 sub all_replicants {
179         my $self = shift @_;
180         return values %{$self->replicants};
181 }
182
183 =head1 AUTHOR
184
185 John Napiorkowski <john.napiorkowski@takkle.com>
186
187 =head1 LICENSE
188
189 You may distribute this code under the same terms as Perl itself.
190
191 =cut
192
193 1;