1 package MogileFS
::Server
;
9 MogileFS::Server - MogileFS (distributed filesystem) server
13 $s = MogileFS::Server->server;
23 use File::Basename ();
30 use Socket qw(SO_KEEPALIVE);
32 use MogileFS
::Util
qw(daemonize);
35 use MogileFS
::ProcManager
;
36 use MogileFS
::Connection
::Client
;
37 use MogileFS
::Connection
::Worker
;
39 use MogileFS
::Worker
::Query
;
40 use MogileFS
::Worker
::Delete
;
41 use MogileFS
::Worker
::Replicate
;
42 use MogileFS
::Worker
::Reaper
;
43 use MogileFS
::Worker
::Monitor
;
44 use MogileFS
::Worker
::Fsck
;
45 use MogileFS
::Worker
::JobMaster
;
47 use MogileFS
::Factory
::Domain
;
48 use MogileFS
::Factory
::Class
;
49 use MogileFS
::Factory
::Host
;
50 use MogileFS
::Factory
::Device
;
56 use MogileFS
::HTTPFile
;
62 use MogileFS
::ReplicationPolicy
::MultipleHosts
;
64 my $server; # server singleton
67 return $server ||= bless {}, $pkg;
70 # --------------------------------------------------------------------------
72 # --------------------------------------------------------------------------
77 MogileFS
::Config
->load_config;
80 die "mogilefsd cannot be run as root\n"
81 if $< == 0 && MogileFS
->config('user') ne "root";
83 MogileFS
::Config
->check_database;
84 daemonize
() if MogileFS
->config("daemonize");
86 MogileFS
::ProcManager
->set_min_workers('monitor' => 1);
89 Sys
::Syslog
::openlog
('mogilefsd', 'pid', 'daemon');
90 Mgd
::log('info', 'beginning run');
92 unless (MogileFS
::ProcManager
->write_pidfile) {
93 Mgd
::log('info', "Couldn't write pidfile, ending run");
94 Sys
::Syslog
::closelog
();
98 # Install signal handlers.
100 my @children = MogileFS
::ProcManager
->child_pids;
101 print STDERR
scalar @children, " children to kill.\n" if $DEBUG;
102 my $count = kill( 'TERM' => @children );
103 print STDERR
"Sent SIGTERM to $count children.\n" if $DEBUG;
104 MogileFS
::ProcManager
->remove_pidfile;
105 Mgd
::log('info', 'ending run due to SIGTERM');
106 Sys
::Syslog
::closelog
();
112 my @children = MogileFS
::ProcManager
->child_pids;
113 print STDERR
scalar @children, " children to kill.\n" if $DEBUG;
114 my $count = kill( 'INT' => @children );
115 print STDERR
"Sent SIGINT to $count children.\n" if $DEBUG;
116 MogileFS
::ProcManager
->remove_pidfile;
117 Mgd
::log('info', 'ending run due to SIGINT');
120 $SIG{PIPE
} = 'IGNORE'; # catch them by hand
122 # setup server sockets to listen for client connections
124 foreach my $listen (@
{ MogileFS
->config('listen') }) {
125 my $server = IO
::Socket
::INET
->new(LocalAddr
=> $listen,
131 or die "Error creating socket: $@\n";
132 $server->sockopt(SO_KEEPALIVE
, 1);
134 # save sub to accept a client
135 push @servers, $server;
136 Danga
::Socket
->AddOtherFds( fileno($server) => sub {
137 while (my $csock = $server->accept) {
138 MogileFS
::Connection
::Client
->new($csock);
143 MogileFS
::ProcManager
->push_pre_fork_cleanup(sub {
144 # so children don't hold server connection open
145 close($_) foreach @servers;
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);
153 # and now, actually start listening for events
155 print( "Starting event loop for frontend job on pid $$.\n" ) if $DEBUG;
156 Danga
::Socket
->EventLoop();
160 Mgd
::log('err', "crash log: $@");
163 Mgd
::log('info', 'ending run');
164 Sys
::Syslog
::closelog
();
168 # --------------------------------------------------------------------------
171 # just so MogileFS->config($key) will work:
172 use MogileFS
::Config
qw(config);
176 sub register_worker_command
{
177 # just pass this through to the Worker class
178 return MogileFS
::Worker
::Query
::register_command
(@_);
181 sub register_global_hook
{
182 $hooks{$_[0]} = $_[1];
186 sub unregister_global_hook
{
187 delete $hooks{$_[0]};
191 sub run_global_hook
{
192 my $hookname = shift;
193 my $ref = $hooks{$hookname};
194 return $ref->(@_) if defined $ref;
198 # --------------------------------------------------------------------------
200 package Mgd
; # conveniently short name
203 use MogileFS
::Config
;
204 use MogileFS
::Util
qw(error fatal debug); # for others calling Mgd::foo()
207 return MogileFS
::Server
->server;
210 # database checking/connecting
212 my $sto = Mgd
::get_store
();
213 my $had_dbh = $sto->have_dbh;
216 eval { $dbh = $sto->dbh };
217 # Doesn't matter what the failure was; workers should retry later.
218 error
("Error validating master DB: $@") if $@
&& $had_dbh;
221 sub get_dbh
{ return Mgd
::get_store
()->dbh }
223 # the eventual replacement for callers asking for a dbh directly:
224 # they'll ask for the current store, which is a database abstraction
226 my ($store, $store_pid);
228 return $store if $store && $store_pid == $$;
230 return $store = MogileFS
::Store
->new;
235 $store->dbh->disconnect();
242 # only for t/ scripts to explicitly set a store, without loading in a config
250 return MogileFS
::Factory
::Domain
->get_factory;
254 return MogileFS
::Factory
::Class
->get_factory;
258 return MogileFS
::Factory
::Host
->get_factory;
262 return MogileFS
::Factory
::Device
->get_factory;
265 # log stuff to syslog or the screen
267 # simple logging functionality
268 if (! $MogileFS::Config
::daemonize
) {
270 # syslog acts like printf so we have to use printf and append a \n
271 shift; # ignore the first parameter (info, warn, critical, etc)
272 my $mask = shift; # format string
273 $mask .= "\n" unless $mask =~ /\n$/;
274 my $message = @_ ?
sprintf($mask, @_) : $mask;
275 print '[', scalar localtime(), '] ', $message;
277 # just pass the parameters to syslog
278 Sys
::Syslog
::syslog
(@_);
284 #Just for MakeMaker's kinda lame regexp for ABSTRACT_FROM
286 mogilefs
::server
- MogileFS
(distributed filesystem
) server
.