File Coverage

blib/lib/MogileFS/Host.pm
Criterion Covered Total %
statement 54 81 66.6
branch 4 10 40.0
condition 8 46 17.3
subroutine 22 34 64.7
pod 0 23 0.0
total 88 194 45.3


line stmt bran cond sub pod time code
1             package MogileFS::Host;
2 21     21   106 use strict;
  21         37  
  21         459  
3 21     21   86 use warnings;
  21         30  
  21         434  
4 21     21   83 use MogileFS::Util qw(throw);
  21         35  
  21         779  
5 21     21   95 use Net::Netmask;
  21         38  
  21         1499  
6 21     21   119 use Carp qw(croak);
  21         32  
  21         891  
7 21     21   6682 use MogileFS::Connection::Mogstored;
  21         43  
  21         490  
8 21     21   7152 use MogileFS::Connection::HTTP;
  21         59  
  21         623  
9 21     21   8345 use MogileFS::ConnectionPool;
  21         77  
  21         18240  
10             our $http_pool;
11              
12             =head1
13              
14             MogileFS::Host - host class
15              
16             =cut
17              
18             # Centralized here instead of three places.
19             my @observed_fields = qw/observed_state/;
20             my @fields = (qw/hostid hostname hostip status http_port http_get_port altip altmask/,
21             @observed_fields);
22              
23             # TODO: Validate a few things: state, observed state.
24             sub new_from_args {
25 69     69 0 926 my ($class, $args, $dev_factory) = @_;
26             my $self = bless {
27             dev_factory => $dev_factory,
28 69         93 %{$args},
  69         267  
29             }, $class;
30              
31             $self->{mask} = ($self->{altip} && $self->{altmask}) ?
32 69 50 33     213 Net::Netmask->new2($self->{altmask}) : undef;
33              
34 69         163 return $self;
35             }
36              
37             sub valid_state {
38 0     0 0 0 my ($class, $state) = @_;
39 0   0     0 return $state && $state =~ /\A(?:alive|dead|down|readonly)\z/;
40             }
41              
42             # Instance methods:
43              
44 198     198 0 1321 sub id { $_[0]{hostid} }
45 68     68 0 118 sub name { $_[0]{hostname} }
46 0     0 0 0 sub hostname { $_[0]{hostname} }
47 0     0 0 0 sub hostip { $_[0]{hostip} }
48 52     52 0 140 sub status { $_[0]{status} }
49 14     14 0 72 sub http_port { $_[0]{http_port} }
50              
51             sub http_get_port {
52 1   33 1 0 6 return $_[0]->{http_get_port} || $_[0]->{http_port};
53             }
54              
55             sub ip {
56 15     15 0 59 my $self = shift;
57 15 50 33     92 if ($self->{mask} && $self->{altip} &&
      0        
      0        
58             ($MogileFS::REQ_altzone || ($MogileFS::REQ_client_ip &&
59             $self->{mask}->match($MogileFS::REQ_client_ip)))) {
60 0         0 return $self->{altip};
61             } else {
62 15         214 return $self->{hostip};
63             }
64             }
65              
66             sub fields {
67 0     0 0 0 my $self = shift;
68 0 0       0 my @tofetch = @_ ? @_ : @fields;
69 0         0 return { map { $_ => $self->{$_} } @tofetch };
  0         0  
70             }
71              
72             sub observed_fields {
73 0     0 0 0 return $_[0]->fields(@observed_fields);
74             }
75              
76             sub alive {
77 52     52 0 74 return $_[0]->status eq 'alive';
78             }
79              
80             sub readonly {
81 0     0 0 0 return $_[0]->status eq 'readonly';
82             }
83              
84             sub should_read_from {
85 0   0 0 0 0 return $_[0]->alive || $_[0]->readonly;
86             }
87              
88             sub observed_reachable {
89 52     52 0 61 my $self = shift;
90 52   33     195 return $self->{observed_state} && $self->{observed_state} eq 'reachable';
91             }
92              
93             sub observed_unreachable {
94 0     0 0 0 my $self = shift;
95 0   0     0 return $self->{observed_state} && $self->{observed_state} eq 'unreachable';
96             }
97              
98             # returns/creates a MogileFS::Connection::Mogstored object to the
99             # host's mogstored management/side-channel port (which starts
100             # unconnected, and only connects when you ask it to, with its sock
101             # method)
102             sub mogstored_conn {
103 0     0 0 0 my $self = shift;
104             return $self->{mogstored_conn} ||=
105 0   0     0 MogileFS::Connection::Mogstored->new($self->ip, $self->sidechannel_port);
106             }
107              
108             sub sidechannel_port {
109             # TODO: let this be configurable per-host? currently it's configured
110             # once for all machines.
111 0     0 0 0 MogileFS->config("mogstored_stream_port");
112             }
113              
114             # starts an HTTP request on the given $port with $method to $path
115             # Calls cb with an HTTP::Response object when done
116             sub _http_conn {
117 15     15   70 my ($self, $port, $method, $path, $opts, $cb) = @_;
118 15         118 _init_pools();
119              
120             $http_pool->start($opts->{ip} || $self->ip, $port, sub {
121 16     16   118 $_[0]->start($method, $path, $opts, $cb);
122 15   33     159 });
123             }
124              
125             # Returns a ready, blocking HTTP connection
126             # This is only used by replicate
127             sub http_conn_get {
128 0     0 0 0 my ($self, $opts) = @_;
129 0   0     0 my $ip = $opts->{ip} || $self->ip;
130 0   0     0 my $port = $opts->{port} || $self->http_port;
131              
132 0         0 _init_pools();
133 0         0 my $conn = $http_pool->conn_get($ip, $port);
134 0 0       0 $conn->sock->blocking(1) if $conn;
135 0         0 return $conn;
136             }
137              
138             # Returns a blocking HTTP connection back to the pool.
139             # This is the inverse of http_conn_get, and should be called when
140             # done using a connection (iff the connection is really still alive)
141             # (and makes it non-blocking for future use)
142             # This is only used by replicate.
143             sub http_conn_put {
144 0     0 0 0 my ($self, $conn) = @_;
145 0         0 $conn->sock->blocking(0);
146 0         0 $http_pool->conn_put($conn);
147             }
148              
149             sub http_get {
150 1     1 0 478 my ($self, $method, $path, $opts, $cb) = @_;
151 1   50     7 $opts ||= {};
152 1         4 $self->_http_conn($self->http_get_port, $method, $path, $opts, $cb);
153             }
154              
155             sub http {
156 14     14 0 72530 my ($self, $method, $path, $opts, $cb) = @_;
157 14   50     151 $opts ||= {};
158 14   33     145 my $port = delete $opts->{port} || $self->http_port;
159 14         60 $self->_http_conn($port, $method, $path, $opts, $cb);
160             }
161              
162             # FIXME - make these customizable
163             sub _init_pools {
164 16 100   16   94 return if $http_pool;
165 1         6 my $opts = {
166             total_capacity => MogileFS->config("conn_pool_size"),
167             };
168              
169 1         7 $http_pool = MogileFS::ConnectionPool->new("MogileFS::Connection::HTTP", $opts);
170             }
171              
172             1;