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);
36 use MogileFS
::ProcManager
;
37 use MogileFS
::Connection
::Client
;
38 use MogileFS
::Connection
::Worker
;
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 use MogileFS
::Worker
::JobMaster
;
48 use MogileFS
::Factory
::Domain
;
49 use MogileFS
::Factory
::Class
;
50 use MogileFS
::Factory
::Host
;
51 use MogileFS
::Factory
::Device
;
57 use MogileFS
::HTTPFile
;
63 use MogileFS
::ReplicationPolicy
::MultipleHosts
;
65 my $server; # server singleton
68 return $server ||= bless {}, $pkg;
71 # --------------------------------------------------------------------------
73 # --------------------------------------------------------------------------
78 MogileFS
::Config
->load_config;
81 die "mogilefsd cannot be run as root\n"
82 if $< == 0 && MogileFS
->config('user') ne "root";
84 MogileFS
::Config
->check_database;
85 daemonize
() if MogileFS
->config("daemonize");
87 MogileFS
::ProcManager
->set_min_workers('monitor' => 1);
90 Sys
::Syslog
::openlog
('mogilefsd', 'pid', 'daemon');
91 Mgd
::log('info', 'beginning run');
93 unless (MogileFS
::ProcManager
->write_pidfile) {
94 Mgd
::log('info', "Couldn't write pidfile, ending run");
95 Sys
::Syslog
::closelog
();
99 # Install signal handlers.
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
();
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');
121 $SIG{PIPE
} = 'IGNORE'; # catch them by hand
123 # setup server sockets to listen for client connections
125 foreach my $listen (@
{ MogileFS
->config('listen') }) {
126 my $server = IO
::Socket
::INET
->new(LocalAddr
=> $listen,
132 or die "Error creating socket: $@\n";
133 $server->sockopt(SO_KEEPALIVE
, 1);
135 # save sub to accept a client
136 push @servers, $server;
137 Danga
::Socket
->AddOtherFds( fileno($server) => sub {
138 while (my $csock = $server->accept) {
139 MogileFS
::Connection
::Client
->new($csock);
144 MogileFS
::ProcManager
->push_pre_fork_cleanup(sub {
145 # so children don't hold server connection open
146 close($_) foreach @servers;
149 # setup the post event loop callback to spawn jobs, and the timeout
150 Danga
::Socket
->DebugLevel(3);
151 Danga
::Socket
->SetLoopTimeout( 250 ); # 250 milliseconds
152 Danga
::Socket
->SetPostLoopCallback(MogileFS
::ProcManager
->PostEventLoopChecker);
154 # and now, actually start listening for events
156 print( "Starting event loop for frontend job on pid $$.\n" ) if $DEBUG;
157 Danga
::Socket
->EventLoop();
161 Mgd
::log('err', "crash log: $@");
164 Mgd
::log('info', 'ending run');
165 Sys
::Syslog
::closelog
();
169 # --------------------------------------------------------------------------
172 # just so MogileFS->config($key) will work:
173 use MogileFS
::Config
qw(config);
177 sub register_worker_command
{
178 # just pass this through to the Worker class
179 return MogileFS
::Worker
::Query
::register_command
(@_);
182 sub register_global_hook
{
183 $hooks{$_[0]} = $_[1];
187 sub unregister_global_hook
{
188 delete $hooks{$_[0]};
192 sub run_global_hook
{
193 my $hookname = shift;
194 my $ref = $hooks{$hookname};
195 return $ref->(@_) if defined $ref;
199 # --------------------------------------------------------------------------
201 package Mgd
; # conveniently short name
204 use MogileFS
::Config
;
205 use MogileFS
::Util
qw(error fatal debug); # for others calling Mgd::foo()
208 return MogileFS
::Server
->server;
211 # database checking/connecting
213 my $sto = Mgd
::get_store
();
214 my $had_dbh = $sto->have_dbh;
217 eval { $dbh = $sto->dbh };
218 # Doesn't matter what the failure was; workers should retry later.
219 error
("Error validating master DB: $@") if $@
&& $had_dbh;
222 sub get_dbh
{ return Mgd
::get_store
()->dbh }
224 # the eventual replacement for callers asking for a dbh directly:
225 # they'll ask for the current store, which is a database abstraction
227 my ($store, $store_pid);
229 return $store if $store && $store_pid == $$;
231 return $store = MogileFS
::Store
->new;
236 $store->dbh->disconnect();
243 # only for t/ scripts to explicitly set a store, without loading in a config
251 return MogileFS
::Factory
::Domain
->get_factory;
255 return MogileFS
::Factory
::Class
->get_factory;
259 return MogileFS
::Factory
::Host
->get_factory;
263 return MogileFS
::Factory
::Device
->get_factory;
266 # log stuff to syslog or the screen
268 # simple logging functionality
269 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
.