1 package MogileFS
::Config
;
4 use MogileFS
::ProcManager
;
9 our @ISA = qw(Exporter);
10 our @EXPORT = qw($DEBUG config set_config FSCK_QUEUE REBAL_QUEUE);
11 our @EXPORT_OK = qw(DEVICE_SUMMARY_CACHE_TIMEOUT);
13 our ($DEFAULT_CONFIG, $MOGSTORED_STREAM_PORT, $DEBUG);
15 $DEFAULT_CONFIG = "/etc/mogilefs/mogilefsd.conf";
16 $MOGSTORED_STREAM_PORT = 7501;
18 use constant FSCK_QUEUE
=> 1;
19 use constant REBAL_QUEUE
=> 2;
20 use constant DEVICE_SUMMARY_CACHE_TIMEOUT
=> 15;
24 my $has_cached_settings = 0;
29 # if a child, propagate to parent
30 if (my $worker = MogileFS
::ProcManager
->is_child) {
31 $worker->send_to_parent(":set_config_from_child $k $v");
32 } elsif (defined $v) {
33 MogileFS
::ProcManager
->send_to_all_children(":set_config_from_parent $k $v");
36 return set_config_no_broadcast
($k, $v);
39 sub set_config_no_broadcast
{
42 return $conf{$k} = $v;
45 set_config
('default_mindevcount', 2);
46 set_config
('min_fidid', 0);
68 $node_timeout, # time in seconds to wait for storage node responses
69 $conn_timeout, # time in seconds to wait for connection to storage node
75 my $default_mindevcount;
80 # Command-line options will override
81 Getopt
::Long
::Configure
( "bundling" );
82 Getopt
::Long
::GetOptions
(
83 'c|config=s' => \
$config,
84 's|skipconfig' => \
$skipconfig,
85 'd|debug+' => \
$cmdline{debug
},
86 'D|daemonize' => \
$cmdline{daemonize
},
87 'dsn=s' => \
$cmdline{db_dsn
},
88 'dbuser=s' => \
$cmdline{db_user
},
89 'dbpass:s' => \
$cmdline{db_pass
},
90 'user=s' => \
$cmdline{user
},
91 'p|confport=i' => \
$cmdline{conf_port
},
92 'l|listen=s@' => \
$cmdline{listen},
93 'w|workers=i' => \
$cmdline{query_jobs
},
94 'no_http' => \
$cmdline{no_http
}, # OLD, we just eat it to shut it up.
95 'workerport=i' => \
$dummy_workerport, # eat it for backwards compat
96 'max_disk_age=i' => \
$cmdline{max_disk_age
},
97 'min_free_space=i' => \
$cmdline{min_free_space
},
98 'default_mindevcount=i' => \
$cmdline{default_mindevcount
},
99 'node_timeout=i' => \
$cmdline{node_timeout
},
100 'conn_timeout=i' => \
$cmdline{conn_timeout
},
101 'max_handles=i' => \
$cmdline{max_handles
},
102 'pidfile=s' => \
$cmdline{pidfile
},
103 'no_schema_check' => \
$cmdline{no_schema_check
},
104 'plugins=s@' => \
$cmdline{plugins
},
105 'repl_use_get_port=i' => \
$cmdline{repl_use_get_port
},
106 'local_network=s' => \
$cmdline{local_network
},
107 'mogstored_stream_port' => \
$cmdline{mogstored_stream_port
},
110 # warn of old/deprecated options
111 warn "The command line option --workerport is no longer needed (and has no necessary replacement)\n"
112 if $dummy_workerport;
114 $config = $DEFAULT_CONFIG if !$config && -r
$DEFAULT_CONFIG;
116 # Read the config file if one was specified
117 if ($config && !$skipconfig) {
118 open my $cf, "<$config" or die "open: $config: $!";
123 \s
+ =? \s
* # space + optional equal + optional space
125 \s
*$ # Trailing space
129 while (defined( my $line = <$cf> )) {
131 next if $line =~ m!^\s*(\#.*)?$!;
132 die "Malformed config file (line $linecount)" unless $line =~ $configLine;
134 my ( $key, $value ) = ( $1, $2 );
135 print STDERR
"Setting '$key' to '$value'\n" if $cmdline{debug
};
136 $cfgfile{$key} = $value;
142 # Fill in defaults for those values which were either loaded from config or
143 # specified on the command line. Command line takes precedence, then values in
144 # the config file, then the defaults.
145 $daemonize = choose_value
( 'daemonize', 0 );
146 $db_dsn = choose_value
( 'db_dsn', "DBI:mysql:mogilefs" );
147 $db_user = choose_value
( 'db_user', "mogile" );
148 $db_pass = choose_value
( 'db_pass', "", 1 );
149 $conf_port = choose_value
( 'conf_port', 7001 );
150 $query_jobs = set_config
("query_jobs",
151 choose_value
( 'listener_jobs', undef) || # undef if not present, then we
152 choose_value
( 'query_jobs', 20 )); # fall back to query_jobs, new name
153 $delete_jobs = choose_value
( 'delete_jobs', 1 );
154 $replicate_jobs = choose_value
( 'replicate_jobs', 1 );
155 $fsck_jobs = choose_value
( 'fsck_jobs', 1 );
156 $reaper_jobs = choose_value
( 'reaper_jobs', 1 );
157 $monitor_jobs = choose_value
( 'monitor_jobs', 1 );
158 $min_free_space = choose_value
( 'min_free_space', 100 );
159 $max_disk_age = choose_value
( 'max_disk_age', 5 );
160 $max_handles = choose_value
( 'max_handles', 0 );
161 $DEBUG = choose_value
( 'debug', $ENV{DEBUG
} || 0 );
162 $pidfile = choose_value
( 'pidfile', "" );
164 choose_value
( 'mogstored_stream_port', $MOGSTORED_STREAM_PORT );
165 choose_value
( 'default_mindevcount', 2 );
166 $node_timeout = choose_value
( 'node_timeout', 2 );
167 $conn_timeout = choose_value
( 'conn_timeout', 2 );
169 choose_value
( 'rebalance_ignore_missing', 0 );
170 $repl_use_get_port = choose_value
( 'repl_use_get_port', 0 );
171 $local_network = choose_value
( 'local_network', '' );
173 choose_value
( 'no_schema_check', 0 );
177 push @plugins, $cfgfile{plugins
} if $cfgfile{plugins
};
178 push @plugins, @
{$cmdline{plugins
}} if $cmdline{plugins
};
180 foreach my $plugin (@plugins) {
181 load_plugins
($plugin);
184 choose_value
('user', '');
186 # fix up config file listen option
187 $cfgfile{listen} = [ split(/\s*,\s*/, $cfgfile{listen}) ] if defined $cfgfile{listen};
189 # now let's fix up the listen option to include the port if it doesn't already; we can't use
190 # choose_value as that uses set_config and that sends to children; this option doesn't apply
191 my $temp_listen = $cmdline{listen} || $cfgfile{listen} || [ '0.0.0.0' ];
192 $conf{listen} = $listen = [ map { /:/ ?
$_ : "$_:$conf{conf_port}" } @
$temp_listen ];
195 ### FUNCTION: choose_value( $name, $default )
197 my ( $name, $default ) = @_;
198 return set_config
($name, $cmdline{$name}) if defined $cmdline{$name};
199 return set_config
($name, $cfgfile{$name}) if defined $cfgfile{$name};
200 return set_config
($name, $default);
205 foreach my $plugin (split(/\s*,\s*/, $plugins)) {
206 my $rv = eval "use MogileFS::Plugin::$plugin; MogileFS::Plugin::$plugin->load; 1;";
207 die "Unable to load $plugin: $@\n" unless $rv;
214 die "No config variable '$k'" unless defined $conf{$k};
219 my $sto = eval { Mgd
::get_store
() };
220 unless ($sto && $sto->ping) {
222 Error
: unable to establish connection with your MogileFS database
.
224 Please verify that you have correctly setup a configuration file
or are
225 providing the correct information
in order to reach the database
and try
226 running the MogileFS server again
. If you haven
\'t setup your database yet
,
229 Details
: [sto
=$sto, err
=$@
]
233 my $sversion = MogileFS
::Config
->server_setting('schema_version') || 0;
234 my $expect_ver = MogileFS
::Store
->latest_schema_version;
235 unless ($sversion == $expect_ver || MogileFS
::Config
->config('no_schema_check')) {
236 die "Server's database schema version of $sversion doesn't match expected value of $expect_ver. Halting.\n\n".
237 "Please run mogdbsetup to upgrade your schema.\n";
240 $sto->pre_daemonize_checks;
242 # If MySQL gets restarted InnoDB may reset its auto_increment counter. If
243 # the first few fids have been deleted, the "reset to max on duplicate"
244 # code won't fire immediately.
245 # Instead, we also trigger it if a configured "min_fidid" is higher than
246 # what we got from innodb.
247 # For bonus points: This value should be periodically updated, in case the
248 # trackers don't go down as often as the database.
249 my $min_fidid = $sto->max_fidid;
250 $min_fidid = 0 unless $min_fidid;
251 set_config
('min_fidid', $min_fidid);
254 # set_server_setting( key, value )
255 # set value to undef to remove whatever is presently stored; returns 1 on success or
257 sub set_server_setting
{
258 my ($class, $key, $val) = @_;
261 my $sto = Mgd
::get_store
();
262 $sto->set_server_setting($key, $val);
266 # get_server_setting( key )
267 # get value of server setting, undef on error (or no result)
269 my ($class, $key) = @_;
270 return Mgd
::get_store
()->server_setting($key);
273 sub cache_server_setting
{
274 my ($class, $key, $val) = @_;
275 $has_cached_settings++ unless $has_cached_settings;
276 if (! defined $val) {
277 delete $server_settings{$key}
278 if exists $server_settings{$key};
280 $server_settings{$key} = $val;
283 sub server_setting_cached
{
284 my ($class, $key, $fallback) = @_;
285 $fallback = 1 unless (defined $fallback);
286 if (!$has_cached_settings && $fallback) {
287 return MogileFS
::Config
->server_setting($key);
289 return $server_settings{$key};
293 my $last_memc_server_fetch = 0;
294 my $have_memc_module = eval "use Cache::Memcached; 1;";
295 sub memcache_client
{
296 return undef unless $have_memc_module;
298 # only reload the server list every 30 seconds
300 return $memc if $last_memc_server_fetch > $now - 30;
302 my @servers = grep(/:\d+$/, split(/\s*,\s*/, MogileFS
::Config
->server_setting_cached("memcache_servers") || ""));
303 $last_memc_server_fetch = $now;
305 return ($memc = undef) unless @servers;
307 $memc ||= Cache
::Memcached
->new;
308 $memc->set_servers(\
@servers);
315 return $cache_hostname ||= Sys
::Hostname
::hostname
();
318 sub server_setting_is_readable
{
319 my ($class, $key) = @_;
320 return 1 if $key eq 'fsck_checksum';
321 return 0 if $key =~ /^fsck_/;
325 # returns subref which cleans (canonicalizes) the value, or dies if invalid format.
326 # my $cleanval = $code->($val);
327 sub server_setting_is_writable
{
328 my ($class, $key) = @_;
331 my $any = sub { $_[0]; };
332 my $del_if_blank = sub { $_[0] || undef };
335 return "0" unless $v;
336 return "0" if $v =~ /^(0|f|off|n)/i;
337 return "1" if $v =~ /^(1|t|on|y)/i;
338 die "Unknown format";
342 return "0" unless $v;
343 return $v if $v =~ /^\d+$/;
344 die "Must be numeric";
350 return $v if $v =~ /$re/;
351 die "Doesn't match acceptable format.";
354 my $valid_netmask = sub {
355 my $n = Net
::Netmask
->new2($_[0]);
356 die "Doesn't match an acceptable netmask" unless $n;
358 my $valid_netmask_list = sub {
359 my @ns = split /[,\s]+/, $_[0];
360 foreach my $n (@ns) {
361 $valid_netmask->($n);
366 # let slave settings go through unmodified, for now.
367 if ($key =~ /^slave_/) { return $del_if_blank };
368 if ($key eq "skip_devcount") { return $bool };
369 if ($key eq "skip_mkcol") { return $bool };
370 if ($key eq "case_sensitive_list_keys") { return $bool };
371 if ($key eq "memcache_servers") { return $any };
372 if ($key eq "memcache_ttl") { return $num };
373 if ($key eq "internal_queue_limit") { return $num };
375 # ReplicationPolicy::MultipleNetworks
376 if ($key eq 'network_zones') { return $any };
377 if ($key =~ /^zone_/) { return $valid_netmask_list };
379 # should probably restrict to (\d+)
380 if ($key =~ /^queue_/) { return $any };
382 if ($key eq "fsck_checksum") {
385 return "off" if $v eq "off";
386 return undef if $v eq "class";
387 return $v if MogileFS
::Checksum
->valid_alg($v);
388 die "Not a valid checksum algorithm";
400 # indent-tabs-mode: nil