File Coverage

blib/lib/MogileFS/Server.pm
Criterion Covered Total %
statement 55 57 96.4
branch n/a
condition n/a
subroutine 19 19 100.0
pod n/a
total 74 76 97.3


line stmt bran cond sub pod time code
1             package MogileFS::Server;
2 7     7   218942 use strict;
  7         21  
  7         276  
3 7     7   40 use warnings;
  7         13  
  7         279  
4 7     7   39 use vars qw($VERSION);
  7         19  
  7         618  
5             $VERSION = "2.17";
6              
7             =head1 NAME
8              
9             MogileFS::Server - MogileFS (distributed filesystem) server
10              
11             =head1 SYNOPSIS
12              
13             $s = MogileFS::Server->server;
14             $s->run;
15              
16             =cut
17              
18 7     7   7755 use IO::Socket;
  7         287920  
  7         39  
19 7     7   5382 use Symbol;
  7         14  
  7         543  
20 7     7   8580 use POSIX;
  7         98307  
  7         58  
21 7     7   32344 use File::Copy ();
  7         59367  
  7         203  
22 7     7   61 use Carp;
  7         15  
  7         541  
23 7     7   41 use File::Basename ();
  7         15  
  7         98  
24 7     7   97 use File::Path ();
  7         13  
  7         95  
25 7     7   8635 use Sys::Syslog ();
  7         120642  
  7         235  
26 7     7   7232 use Time::HiRes ();
  7         11019  
  7         199  
27 7     7   7076 use Net::Netmask;
  7         76527  
  7         845  
28 7     7   16042 use LWP::UserAgent;
  7         425534  
  7         287  
29 7     7   90 use List::Util;
  7         13  
  7         728  
30 7     7   46 use Socket ();
  7         22  
  7         147  
31              
32 7     7   13381 use MogileFS::Util qw(daemonize);
  7         27  
  7         734  
33 7     7   4399 use MogileFS::Sys;
  7         18  
  7         219  
34 7     7   4348 use MogileFS::Config;
  0            
  0            
35              
36             use MogileFS::ProcManager;
37             use MogileFS::Connection::Client;
38             use MogileFS::Connection::Worker;
39              
40             use MogileFS::Worker::Query;
41             use MogileFS::Worker::Delete;
42             use MogileFS::Worker::Replicate;
43             use MogileFS::Worker::Reaper;
44             use MogileFS::Worker::Monitor;
45             use MogileFS::Worker::Fsck;
46              
47             use MogileFS::HTTPFile;
48             use MogileFS::Class;
49             use MogileFS::Device;
50             use MogileFS::Host;
51             use MogileFS::FID;
52             use MogileFS::Domain;
53             use MogileFS::DevFID;
54              
55             use MogileFS::Store;
56             use MogileFS::Store::MySQL; # FIXME: don't load this until after reading their config, but before fork.
57              
58             use MogileFS::ReplicationPolicy::MultipleHosts;
59              
60             my $server; # server singleton
61             sub server {
62             my ($pkg) = @_;
63             return $server ||= bless {}, $pkg;
64             }
65              
66             # --------------------------------------------------------------------------
67             # instance methods:
68             # --------------------------------------------------------------------------
69              
70             sub run {
71             my $self = shift;
72              
73             MogileFS::Config->load_config;
74              
75             # don't run as root
76             die "mogilefsd cannot be run as root\n"
77             if $< == 0 && MogileFS->config('user') ne "root";
78              
79             MogileFS::Config->check_database;
80             daemonize() if MogileFS->config("daemonize");
81              
82             MogileFS::ProcManager->set_min_workers('queryworker' => MogileFS->config('query_jobs'));
83             MogileFS::ProcManager->set_min_workers('delete' => MogileFS->config('delete_jobs'));
84             MogileFS::ProcManager->set_min_workers('replicate' => MogileFS->config('replicate_jobs'));
85             MogileFS::ProcManager->set_min_workers('reaper' => MogileFS->config('reaper_jobs'));
86             MogileFS::ProcManager->set_min_workers('monitor' => MogileFS->config('monitor_jobs'));
87             MogileFS::ProcManager->set_min_workers('fsck' => 1);
88              
89             # open up our log
90             Sys::Syslog::openlog('mogilefsd', 'pid', 'daemon');
91             Mgd::log('info', 'beginning run');
92              
93             unless (MogileFS::ProcManager->write_pidfile) {
94             Mgd::log('info', "Couldn't write pidfile, ending run");
95             Sys::Syslog::closelog();
96             exit 1;
97             }
98              
99             # Install signal handlers.
100             $SIG{TERM} = sub {
101             my @children = MogileFS::ProcManager->child_pids;
102             print STDERR scalar @children, " children to kill.\n" if $DEBUG;
103             my $count = kill( 'TERM' => @children );
104             print STDERR "Sent SIGTERM to $count children.\n" if $DEBUG;
105             MogileFS::ProcManager->remove_pidfile;
106             Mgd::log('info', 'ending run due to SIGTERM');
107             Sys::Syslog::closelog();
108              
109             exit 0;
110             };
111              
112             $SIG{INT} = sub {
113             my @children = MogileFS::ProcManager->child_pids;
114             print STDERR scalar @children, " children to kill.\n" if $DEBUG;
115             my $count = kill( 'INT' => @children );
116             print STDERR "Sent SIGINT to $count children.\n" if $DEBUG;
117             MogileFS::ProcManager->remove_pidfile;
118             Mgd::log('info', 'ending run due to SIGINT');
119             exit 0;
120             };
121             $SIG{PIPE} = 'IGNORE'; # catch them by hand
122              
123             # setup server sockets to listen for client connections
124             my @servers;
125             foreach my $listen (@{ MogileFS->config('listen') }) {
126             my $server = IO::Socket::INET->new(LocalAddr => $listen,
127             Type => SOCK_STREAM,
128             Proto => 'tcp',
129             Blocking => 0,
130             Reuse => 1,
131             Listen => 10 )
132             or die "Error creating socket: $@\n";
133              
134             # save sub to accept a client
135             push @servers, $server;
136             Danga::Socket->AddOtherFds( fileno($server) => sub {
137             my $csock = $server->accept
138             or return;
139             MogileFS::Connection::Client->new($csock);
140             } );
141             }
142              
143             MogileFS::ProcManager->push_pre_fork_cleanup(sub {
144             # so children don't hold server connection open
145             close($_) foreach @servers;
146             });
147              
148             # setup the post event loop callback to spawn jobs, and the timeout
149             Danga::Socket->DebugLevel(3);
150             Danga::Socket->SetLoopTimeout( 250 ); # 250 milliseconds
151             Danga::Socket->SetPostLoopCallback(MogileFS::ProcManager->PostEventLoopChecker);
152              
153             # and now, actually start listening for events
154             eval {
155             print( "Starting event loop for frontend job on pid $$.\n" ) if $DEBUG;
156             Danga::Socket->EventLoop();
157             };
158              
159             if ($@) {
160             Mgd::log('err', "crash log: $@");
161             exit 1;
162             }
163             Mgd::log('info', 'ending run');
164             Sys::Syslog::closelog();
165             exit(0);
166             }
167              
168             # --------------------------------------------------------------------------
169              
170             package MogileFS;
171             # just so MogileFS->config($key) will work:
172             use MogileFS::Config qw(config);
173              
174             my %hooks;
175              
176             sub register_worker_command {
177             # just pass this through to the Worker class
178             return MogileFS::Worker::Query::register_command(@_);
179             }
180              
181             sub register_global_hook {
182             $hooks{$_[0]} = $_[1];
183             return 1;
184             }
185              
186             sub unregister_global_hook {
187             delete $hooks{$_[0]};
188             return 1;
189             }
190              
191             sub run_global_hook {
192             my $hookname = shift;
193             my $ref = $hooks{$hookname};
194             return $ref->(@_) if defined $ref;
195             return undef;
196             }
197              
198             # --------------------------------------------------------------------------
199              
200             package Mgd; # conveniently short name
201             use strict;
202             use warnings;
203             use MogileFS::Config;
204             use MogileFS::Util qw(error fatal debug); # for others calling Mgd::foo()
205              
206             sub server {
207             return MogileFS::Server->server;
208             }
209              
210             # database checking/connecting
211             sub validate_dbh { Mgd::get_store()->recheck_dbh }
212             sub get_dbh { return Mgd::get_store()->dbh }
213              
214             # the eventual replacement for callers asking for a dbh directly:
215             # they'll ask for the current store, which is a database abstraction
216             # layer.
217             my ($store, $store_pid);
218             sub get_store {
219             return $store if $store && $store_pid == $$;
220             $store_pid = $$;
221             return $store = MogileFS::Store->new;
222             }
223              
224             # only for t/ scripts to explicitly set a store, without loading in a config
225             sub set_store {
226             my ($s) = @_;
227             $store = $s;
228             $store_pid = $$;
229             }
230              
231             # log stuff to syslog or the screen
232             sub log {
233             # simple logging functionality
234             if (! $MogileFS::Config::daemonize) {
235             # syslog acts like printf so we have to use printf and append a \n
236             shift; # ignore the first parameter (info, warn, critical, etc)
237             my $mask = shift; # format string
238             $mask .= "\n" unless $mask =~ /\n$/;
239             my $message = @_ ? sprintf($mask, @_) : $mask;
240             print $message;
241             } else {
242             # just pass the parameters to syslog
243             Sys::Syslog::syslog(@_);
244             }
245             }
246              
247             1;
248             __END__