light: allow limiting the sync parallelism

This commit is contained in:
Thomas Schoebel-Theuer 2014-02-15 17:48:54 +01:00
parent 09a1cd3b32
commit 2fc05b5373
4 changed files with 198 additions and 21 deletions

View File

@ -108,6 +108,16 @@ EXPORT_SYMBOL_GPL(global_free_space_3);
int global_free_space_4 = CONFIG_MARS_MIN_SPACE_4;
EXPORT_SYMBOL_GPL(global_free_space_4);
int _global_sync_want = 0;
int global_sync_want = 0;
EXPORT_SYMBOL_GPL(global_sync_want);
int global_sync_nr = 0;
EXPORT_SYMBOL_GPL(global_sync_nr);
int global_sync_limit = 0;
EXPORT_SYMBOL_GPL(global_sync_limit);
int mars_rollover_interval = CONFIG_MARS_ROLLOVER_INTERVAL;
EXPORT_SYMBOL_GPL(mars_rollover_interval);
@ -427,6 +437,10 @@ enum {
CL_GLOBAL_TODO,
CL_GLOBAL_TODO_DELETE,
CL_GLOBAL_TODO_DELETED,
CL_DEFAULTS0,
CL_DEFAULTS,
CL_DEFAULTS_ITEMS0,
CL_DEFAULTS_ITEMS,
// replacement for DNS in kernelspace
CL_IPS,
CL_PEERS,
@ -441,10 +455,10 @@ enum {
CL_RESOURCE,
CL_RESOURCE_USERSPACE,
CL_RESOURCE_USERSPACE_ITEMS,
CL_DEFAULTS0,
CL_DEFAULTS,
CL_DEFAULTS_ITEMS0,
CL_DEFAULTS_ITEMS,
CL_RES_DEFAULTS0,
CL_RES_DEFAULTS,
CL_RES_DEFAULTS_ITEMS0,
CL_RES_DEFAULTS_ITEMS,
CL_TODO,
CL_TODO_ITEMS,
CL_ACTUAL,
@ -474,6 +488,7 @@ enum {
#define MAX_INFOS 4
struct mars_rotate {
struct list_head rot_head;
struct mars_global *global;
struct copy_brick *sync_brick;
struct mars_dent *replay_link;
@ -496,6 +511,7 @@ struct mars_rotate {
const char *fetch_peer;
const char *preferred_peer;
const char *parent_path;
const char *parent_rest;
const char *fetch_next_origin;
struct say_channel *log_say;
struct copy_brick *fetch_brick;
@ -527,12 +543,16 @@ struct mars_rotate {
bool created_hole;
bool is_log_damaged;
bool has_emergency;
bool wants_sync;
bool gets_sync;
spinlock_t inf_lock;
bool infs_is_dirty[MAX_INFOS];
struct trans_logger_info infs[MAX_INFOS];
struct key_value_pair msgs[sizeof(rot_keys) / sizeof(char*)];
};
static LIST_HEAD(rot_anchor);
///////////////////////////////////////////////////////////////////////
// TUNING
@ -2523,6 +2543,7 @@ void rot_destruct(void *_rot)
{
struct mars_rotate *rot = _rot;
if (likely(rot)) {
list_del_init(&rot->rot_head);
write_info_links(rot);
del_channel(rot->log_say);
rot->log_say = NULL;
@ -2530,11 +2551,13 @@ void rot_destruct(void *_rot)
brick_string_free(rot->fetch_peer);
brick_string_free(rot->preferred_peer);
brick_string_free(rot->parent_path);
brick_string_free(rot->parent_rest);
brick_string_free(rot->fetch_next_origin);
rot->fetch_path = NULL;
rot->fetch_peer = NULL;
rot->preferred_peer = NULL;
rot->parent_path = NULL;
rot->parent_rest = NULL;
rot->fetch_next_origin = NULL;
clear_vals(rot->msgs);
}
@ -2588,6 +2611,7 @@ int make_log_init(void *buf, struct mars_dent *dent)
rot->global = global;
parent->d_private = rot;
parent->d_private_destruct = rot_destruct;
list_add_tail(&rot->rot_head, &rot_anchor);
assign_keys(rot->msgs, rot_keys);
}
@ -2610,14 +2634,17 @@ int make_log_init(void *buf, struct mars_dent *dent)
rot->split_brain_serial = 0;
rot->fetch_next_serial = 0;
rot->has_error = false;
rot->wants_sync = false;
rot->has_symlinks = true;
brick_string_free(rot->preferred_peer);
rot->preferred_peer = NULL;
if (dent->new_link)
sscanf(dent->new_link, "%lld", &rot->dev_size);
if (!rot->parent_path)
if (!rot->parent_path) {
rot->parent_path = brick_strdup(parent_path);
rot->parent_rest = brick_strdup(parent->d_rest);
}
if (unlikely(!rot->log_say)) {
char *name = path_make("%s/logstatus-%s", parent_path, my_id());
@ -4031,12 +4058,13 @@ static int make_sync(void *buf, struct mars_dent *dent)
}
rot = dent->d_parent->d_private;
if (rot) {
rot->forbid_replay = false;
rot->has_symlinks = true;
rot->allow_update = true;
rot->syncstatus_dent = dent;
}
status = -ENOENT;
CHECK_PTR(rot, done);
rot->forbid_replay = false;
rot->has_symlinks = true;
rot->allow_update = true;
rot->syncstatus_dent = dent;
/* Sync necessary?
*/
@ -4136,6 +4164,14 @@ static int make_sync(void *buf, struct mars_dent *dent)
MARS_DBG("initial sync '%s' => '%s' do_start = %d\n", src, dst, do_start);
rot->wants_sync = (do_start != 0);
if (rot->wants_sync && global_sync_limit > 0) {
do_start = rot->gets_sync;
if (!rot->gets_sync) {
MARS_INF_TO(rot->log_say, "won't start sync because of parallelism limit %d\n", global_sync_limit);
}
}
{
const char *argv[2] = { src, dst };
status = __make_copy(global, dent, do_start ? switch_path : "", copy_path, dent->d_parent->d_path, argv, find_key(rot->msgs, "inf-sync"), start_pos, end_pos, mars_fast_fullsync > 0, true, &copy);
@ -4437,6 +4473,71 @@ int kill_res(void *buf, struct mars_dent *dent)
return 0;
}
static
int make_defaults(void *buf, struct mars_dent *dent)
{
if (!dent->new_link)
goto done;
MARS_DBG("name = '%s' value = '%s'\n", dent->d_name, dent->new_link);
if (!strcmp(dent->d_name, "sync-limit")) {
sscanf(dent->new_link, "%d", &global_sync_limit);
} else if (!strcmp(dent->d_name, "sync-pref-list")) {
const char *start;
struct list_head *tmp;
int len;
int want_count = 0;
int get_count = 0;
for (tmp = rot_anchor.next; tmp != &rot_anchor; tmp = tmp->next) {
struct mars_rotate *rot = container_of(tmp, struct mars_rotate, rot_head);
if (rot->wants_sync)
want_count++;
else
rot->gets_sync = false;
if (rot->sync_brick && rot->sync_brick->power.led_on)
get_count++;
}
global_sync_want = want_count;
global_sync_nr = get_count;
// prefer mentioned resources in the right order
for (start = dent->new_link; *start && get_count < global_sync_limit; start += len) {
len = 1;
while (start[len] && start[len] != ',')
len++;
for (tmp = rot_anchor.next; tmp != &rot_anchor; tmp = tmp->next) {
struct mars_rotate *rot = container_of(tmp, struct mars_rotate, rot_head);
if (rot->wants_sync && rot->parent_rest && !strncmp(start, rot->parent_rest, len)) {
rot->gets_sync = true;
get_count++;
MARS_DBG("new get_count = %d res = '%s' wants_sync = %d gets_sync = %d\n",
get_count, rot->parent_rest, rot->wants_sync, rot->gets_sync);
break;
}
}
if (start[len])
len++;
}
// fill up with unmentioned resources
for (tmp = rot_anchor.next; tmp != &rot_anchor && get_count < global_sync_limit; tmp = tmp->next) {
struct mars_rotate *rot = container_of(tmp, struct mars_rotate, rot_head);
if (rot->wants_sync && !rot->gets_sync) {
rot->gets_sync = true;
get_count++;
}
MARS_DBG("new get_count = %d res = '%s' wants_sync = %d gets_sync = %d\n",
get_count, rot->parent_rest, rot->wants_sync, rot->gets_sync);
}
MARS_DBG("final want_count = %d get_count = %d\n", want_count, get_count);
} else {
MARS_DBG("unimplemented default '%s'\n", dent->d_name);
}
done:
return 0;
}
///////////////////////////////////////////////////////////////////////
/* Please keep the order the same as in the enum.
@ -4472,6 +4573,38 @@ static const struct light_class light_classes[] = {
.cl_father = CL_GLOBAL_USERSPACE,
},
/* Subdirectory for defaults...
*/
[CL_DEFAULTS0] = {
.cl_name = "defaults",
.cl_len = 8,
.cl_type = 'd',
.cl_hostcontext = false,
.cl_father = CL_ROOT,
},
[CL_DEFAULTS] = {
.cl_name = "defaults-",
.cl_len = 9,
.cl_type = 'd',
.cl_hostcontext = true,
.cl_father = CL_ROOT,
},
/* ... and its contents
*/
[CL_DEFAULTS_ITEMS0] = {
.cl_name = "",
.cl_len = 0, // catch any
.cl_type = 'l',
.cl_father = CL_DEFAULTS0,
},
[CL_DEFAULTS_ITEMS] = {
.cl_name = "",
.cl_len = 0, // catch any
.cl_type = 'l',
.cl_father = CL_DEFAULTS,
.cl_forward = make_defaults,
},
/* Subdirectory for global controlling items...
*/
[CL_GLOBAL_TODO] = {
@ -4609,14 +4742,14 @@ static const struct light_class light_classes[] = {
/* Subdirectory for defaults...
*/
[CL_DEFAULTS0] = {
[CL_RES_DEFAULTS0] = {
.cl_name = "defaults",
.cl_len = 8,
.cl_type = 'd',
.cl_hostcontext = false,
.cl_father = CL_RESOURCE,
},
[CL_DEFAULTS] = {
[CL_RES_DEFAULTS] = {
.cl_name = "defaults-",
.cl_len = 9,
.cl_type = 'd',
@ -4625,17 +4758,17 @@ static const struct light_class light_classes[] = {
},
/* ... and its contents
*/
[CL_DEFAULTS_ITEMS0] = {
[CL_RES_DEFAULTS_ITEMS0] = {
.cl_name = "",
.cl_len = 0, // catch any
.cl_type = 'l',
.cl_father = CL_DEFAULTS0,
.cl_father = CL_RES_DEFAULTS0,
},
[CL_DEFAULTS_ITEMS] = {
[CL_RES_DEFAULTS_ITEMS] = {
.cl_name = "",
.cl_len = 0, // catch any
.cl_type = 'l',
.cl_father = CL_DEFAULTS,
.cl_father = CL_RES_DEFAULTS,
},
/* Subdirectory for controlling items...

View File

@ -308,6 +308,9 @@ ctl_table mars_table[] = {
INT_ENTRY("required_free_space_2_gb", global_free_space_2, 0600),
INT_ENTRY("required_free_space_3_gb", global_free_space_3, 0600),
INT_ENTRY("required_free_space_4_gb", global_free_space_4, 0600),
INT_ENTRY("sync_want", global_sync_want, 0400),
INT_ENTRY("sync_nr", global_sync_nr, 0400),
INT_ENTRY("sync_limit", global_sync_limit, 0600),
INT_ENTRY("mars_emergency_mode", mars_emergency_mode, 0600),
INT_ENTRY("mars_reset_emergency", mars_reset_emergency, 0600),
INT_ENTRY("mars_keep_msg_s", mars_keep_msg, 0600),

View File

@ -20,6 +20,9 @@ extern int global_free_space_1;
extern int global_free_space_2;
extern int global_free_space_3;
extern int global_free_space_4;
extern int global_sync_want;
extern int global_sync_nr;
extern int global_sync_limit;
extern int mars_rollover_interval;
extern int mars_scan_interval;
extern int mars_propagate_interval;

View File

@ -1124,6 +1124,32 @@ sub set_link_cmd {
}
}
sub set_sync_pref_list {
my ($cmd, $list) = @_;
my $todo_dir = "$mars/defaults-$host";
ldie "directory '$todo_dir' does not exist\n" unless -d $todo_dir;
my $dst = "$todo_dir/sync-pref-list";
if ($cmd =~ m/^get-/) {
my $value = get_link($dst);
lprint "$value\n";
return;
}
set_link($list, $dst);
}
sub set_sync_limit_value {
my ($cmd, $value) = @_;
my $todo_dir = "$mars/defaults-$host";
ldie "directory '$todo_dir' does not exist\n" unless -d $todo_dir;
my $dst = "$todo_dir/sync-limit";
if ($cmd =~ m/^get-/) {
my $value = get_link($dst);
lprint "$value\n";
return;
}
set_link($value, $dst);
}
sub _create_cluster {
my ($cmd) = @_;
system("mkdir $mars") unless -d $mars;
@ -1144,6 +1170,8 @@ sub _create_cluster {
system("mkdir $mars/userspace") unless -d "$mars/userspace";
system("mkdir $mars/defaults") unless -d "$mars/defaults";
system("mkdir $mars/defaults-$host") unless -d "$mars/defaults-$host";
set_link("0", "$mars/defaults-$host/sync-limit");
set_link("(none)", "$mars/defaults-$host/sync-pref-list");
system("mkdir $mars/todo-global") unless -d "$mars/todo-global";
mkdir("$mars/actual-$host") unless -d "$mars/actual-$host";
set_link($ip, "$mars/ips/ip-$host");
@ -2052,6 +2080,10 @@ my %cmd_table =
"log-purge-all" => \&log_purge_res,
"fake-sync" => \&fake_local_res,
"set-link" => \&set_link_cmd,
"set-sync-pref-list"=> \&set_sync_pref_list,
"get-sync-pref-list"=> \&set_sync_pref_list,
"set-sync-limit-value"=> \&set_sync_limit_value,
"get-sync-limit-value"=> \&set_sync_limit_value,
"delete-file" => \&delete_file_cmd,
"set-emergency-limit" => \&emergency_limit_res,
"get-emergency-limit" => \&emergency_limit_res,
@ -2204,8 +2236,13 @@ if (!(-d $mars) && $cmd !~ m/(create|join)-cluster|cat/) {
}
my $res = "";
if ($cmd eq "show") {
if ($cmd =~ "show") {
$res = shift @args;
} elsif ($cmd =~ m/^set-.*-list$/) {
$res = shift @args || helplist "comma-separated list argument is missing\n";
} elsif ($cmd =~ m/^set-.*-value$/) {
$res = shift @args || helplist "numeric argument is missing\n";
ldie "argument '$res' isn't numeric\n" unless $res =~ m/^[0-9.]+$/;
} elsif (!($cmd =~ m/^(create|leave|wait)-cluster|cat|[a-z]+-file|^[sg]et-/)) {
$res = shift @args || helplist "resource argument is missing\n";
check_id($res);
@ -2219,9 +2256,10 @@ my %checked_res;
sub do_one_res {
my $func = shift;
my ($cmd, $res) = @_;
if (!$checked_res{"$cmd$res"}) {
$res = check_res($res) unless $cmd =~ m/^(join|create|leave|wait)-cluster|create-resource|show|cat|[a-z]+-file|set-link$/;
check_res_member($res) unless $cmd =~ m/^(join|create|delete)-(cluster|resource)|(leave|wait)-cluster|show|cat|[a-z]+-file|set-link$/;
if ($cmd =~ m/^cat|-file$|-list$|-link$|-value$/) { # no resource argument
} elsif (!$checked_res{"$cmd$res"}) {
$res = check_res($res) unless (!$res || $cmd =~ m/^(join|create|leave|wait)-cluster|create-resource|show/);
check_res_member($res) unless (!$res || $cmd =~ m/^(join|create|delete)-(cluster|resource)|(leave|wait)-cluster|show/);
detect_splitbrain($res, 1);
$checked_res{"$cmd$res"} = 1;
}