diff options
Diffstat (limited to 'scheduler/switch/src/switch.c')
-rw-r--r-- | scheduler/switch/src/switch.c | 398 |
1 files changed, 398 insertions, 0 deletions
diff --git a/scheduler/switch/src/switch.c b/scheduler/switch/src/switch.c new file mode 100644 index 000000000..70b307187 --- /dev/null +++ b/scheduler/switch/src/switch.c @@ -0,0 +1,398 @@ +/* + Copyright (c) 2006, 2007, 2008 Z RESEARCH, Inc. <http://www.zresearch.com> + This file is part of GlusterFS. + + GlusterFS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3 of the License, + or (at your option) any later version. + + GlusterFS is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see + <http://www.gnu.org/licenses/>. +*/ + +#include <sys/time.h> +#include <stdlib.h> +#include <fnmatch.h> + +#ifndef _CONFIG_H +#define _CONFIG_H +#include "config.h" +#endif + +#include "xlator.h" +#include "scheduler.h" + +struct switch_sched_array { + xlator_t *xl; + int32_t eligible; + int32_t considered; +}; + +/* Select one of this struct based on the path's pattern match */ +struct switch_sched_struct { + struct switch_sched_struct *next; + struct switch_sched_array *array; + char path_pattern[256]; + int32_t node_index; /* Index of the node in + this pattern. */ + int32_t num_child; /* Total num of child nodes + with this pattern. */ +}; + +struct switch_struct { + struct switch_sched_struct *cond; + struct switch_sched_array *array; + pthread_mutex_t switch_mutex; + int32_t child_count; +}; + +/* This function should return child node as '*:subvolumes' is inserterd */ +static xlator_t * +switch_get_matching_xl (const char *path, struct switch_sched_struct *cond) +{ + struct switch_sched_struct *trav = cond; + char *pathname = strdup (path); + int index = 0; + + while (trav) { + if (fnmatch (trav->path_pattern, + pathname, FNM_NOESCAPE) == 0) { + free (pathname); + trav->node_index %= trav->num_child; + index = (trav->node_index++) % trav->num_child; + return trav->array[index].xl; + } + trav = trav->next; + } + free (pathname); + return NULL; +} + + +static int32_t +switch_init (xlator_t *xl) +{ + int32_t index = 0; + data_t *data = NULL; + char *child = NULL; + char *tmp = NULL; + char *childs_data = NULL; + xlator_list_t *trav_xl = xl->children; + struct switch_struct *switch_buf = NULL; + + switch_buf = CALLOC (1, sizeof (struct switch_struct)); + ERR_ABORT (switch_buf); + + while (trav_xl) { + index++; + trav_xl = trav_xl->next; + } + switch_buf->child_count = index; + switch_buf->array = CALLOC (index + 1, + sizeof (struct switch_sched_struct)); + ERR_ABORT (switch_buf->array); + trav_xl = xl->children; + index = 0; + + while (trav_xl) { + switch_buf->array[index].xl = trav_xl->xlator; + switch_buf->array[index].eligible = 1; + trav_xl = trav_xl->next; + index++; + } + + data = dict_get (xl->options, "scheduler.read-only-subvolumes"); + if (data) { + childs_data = strdup (data->data); + child = strtok_r (childs_data, ",", &tmp); + while (child) { + for (index = 1; + index < switch_buf->child_count; index++) { + if (strcmp (switch_buf->array[index - 1].xl->name, child) == 0) { + gf_log ("switch", GF_LOG_DEBUG, + "Child '%s' is read-only", + child); + memcpy (&(switch_buf->array[index-1]), + &(switch_buf->array[switch_buf->child_count - 1]), + sizeof (struct switch_sched_array)); + switch_buf->child_count--; + break; + } + } + child = strtok_r (NULL, ",", &tmp); + } + free (childs_data); + } + + data = dict_get (xl->options, "scheduler.local-volume-name"); + if (data) { + /* Means, give preference to that node first */ + gf_log ("switch", GF_LOG_DEBUG, + "local volume defined as %s", data->data); + + /* TODO: parse it properly, have an extra index to + specify that first */ + } + + /* *jpg:child1,child2;*mpg:child3;*:child4,child5,child6 */ + data = dict_get (xl->options, "scheduler.switch.case"); + if (data) { + char *tmp_str = NULL; + char *tmp_str1 = NULL; + char *dup_str = NULL; + char *switch_str = NULL; + char *pattern = NULL; + char *childs = NULL; + struct switch_sched_struct *switch_opt = NULL; + struct switch_sched_struct *trav = NULL; + /* Get the pattern for considering switch case. + "option block-size *avi:10MB" etc */ + switch_str = strtok_r (data->data, ";", &tmp_str); + while (switch_str) { + dup_str = strdup (switch_str); + switch_opt = + CALLOC (1, + sizeof (struct switch_sched_struct)); + ERR_ABORT (switch_opt); + + /* Link it to the main structure */ + if (switch_buf->cond) { + /* there are already few entries */ + trav = switch_buf->cond; + while (trav->next) + trav = trav->next; + trav->next = switch_opt; + } else { + /* First entry */ + switch_buf->cond = switch_opt; + } + pattern = strtok_r (dup_str, ":", &tmp_str1); + childs = strtok_r (NULL, ":", &tmp_str1); + if (strncmp (pattern, "*", 2) == 0) { + gf_log ("switch", GF_LOG_WARNING, + "'*' pattern will be taken by default " + "for all the unconfigured child nodes," + " hence neglecting current option"); + switch_str = strtok_r (NULL, ";", &tmp_str); + free (dup_str); + continue; + } + memcpy (switch_opt->path_pattern, + pattern, strlen (pattern)); + if (childs) { + int32_t idx = 0; + char *tmp1 = NULL; + char *dup_childs = NULL; + /* TODO: get the list of child nodes for + the given pattern */ + dup_childs = strdup (childs); + child = strtok_r (dup_childs, ",", &tmp); + while (child) { + idx++; + child = strtok_r (NULL, ",", &tmp); + } + free (dup_childs); + child = strtok_r (childs, ",", &tmp1); + switch_opt->num_child = idx; + switch_opt->array = + CALLOC (1, idx * sizeof (struct switch_sched_array)); + ERR_ABORT (switch_opt->array); + idx = 0; + child = strtok_r (childs, ",", &tmp); + while (child) { + for (index = 1; + index < switch_buf->child_count; + index++) { + if (strcmp (switch_buf->array[index - 1].xl->name, + child) == 0) { + gf_log ("switch", + GF_LOG_DEBUG, + "'%s' pattern will be scheduled to \"%s\"", + switch_opt->path_pattern, child); + /* + if (switch_buf->array[index-1].considered) { + gf_log ("switch", GF_LOG_DEBUG, + "ambiguity found, exiting"); + return -1; + } + */ + switch_opt->array[idx].xl = switch_buf->array[index-1].xl; + switch_buf->array[index-1].considered = 1; + idx++; + break; + } + } + child = strtok_r (NULL, ",", &tmp1); + } + } else { + /* error */ + gf_log ("switch", GF_LOG_ERROR, + "Check \"scheduler.switch.case\" " + "option in unify volume. Exiting"); + free (switch_buf->array); + free (switch_buf); + return -1; + } + free (dup_str); + switch_str = strtok_r (NULL, ";", &tmp_str); + } + } + /* Now, all the pattern based considerations done, so for all the + * remaining pattern, '*' to all the remaining child nodes + */ + { + struct switch_sched_struct *switch_opt = NULL; + int32_t flag = 0; + int32_t index = 0; + for (index=0; index < switch_buf->child_count; index++) { + /* check for considered flag */ + if (switch_buf->array[index].considered) + continue; + flag++; + } + if (!flag) { + gf_log ("switch", GF_LOG_ERROR, + "No nodes left for pattern '*'. Exiting."); + return -1; + } + switch_opt = CALLOC (1, sizeof (struct switch_sched_struct)); + ERR_ABORT (switch_opt); + if (switch_buf->cond) { + /* there are already few entries */ + struct switch_sched_struct *trav = switch_buf->cond; + while (trav->next) + trav = trav->next; + trav->next = switch_opt; + } else { + /* First entry */ + switch_buf->cond = switch_opt; + } + /* Add the '*' pattern to the array */ + memcpy (switch_opt->path_pattern, "*", 2); + switch_opt->num_child = flag; + switch_opt->array = + CALLOC (1, flag * sizeof (struct switch_sched_array)); + ERR_ABORT (switch_opt->array); + flag = 0; + for (index=0; index < switch_buf->child_count; index++) { + /* check for considered flag */ + if (switch_buf->array[index].considered) + continue; + gf_log ("switch", GF_LOG_DEBUG, + "'%s' pattern will be scheduled to \"%s\"", + switch_opt->path_pattern, + switch_buf->array[index].xl->name); + switch_opt->array[flag].xl = + switch_buf->array[index].xl; + switch_buf->array[index].considered = 1; + flag++; + } + } + + pthread_mutex_init (&switch_buf->switch_mutex, NULL); + + // put it at the proper place + *((long *)xl->private) = (long)switch_buf; + + return 0; +} + +static void +switch_fini (xlator_t *xl) +{ + /* TODO: free all the allocated entries */ + struct switch_struct *switch_buf = NULL; + switch_buf = (struct switch_struct *)*((long *)xl->private); + + pthread_mutex_destroy (&switch_buf->switch_mutex); + free (switch_buf->array); + free (switch_buf); +} + +static xlator_t * +switch_schedule (xlator_t *xl, const void *path) +{ + struct switch_struct *switch_buf = NULL; + switch_buf = (struct switch_struct *)*((long *)xl->private); + + return switch_get_matching_xl (path, switch_buf->cond); +} + + +/** + * notify + */ +void +switch_notify (xlator_t *xl, int32_t event, void *data) +{ + /* TODO: This should be checking in switch_sched_struct */ +#if 0 + struct switch_struct *switch_buf = NULL; + int32_t idx = 0; + + switch_buf = (struct switch_struct *)*((long *)xl->private); + if (!switch_buf) + return; + + for (idx = 0; idx < switch_buf->child_count; idx++) { + if (switch_buf->array[idx].xl == (xlator_t *)data) + break; + } + + switch (event) + { + case GF_EVENT_CHILD_UP: + { + switch_buf->array[idx].eligible = 1; + } + break; + case GF_EVENT_CHILD_DOWN: + { + switch_buf->array[idx].eligible = 0; + } + break; + default: + { + ; + } + break; + } +#endif +} + +static void +switch_update (xlator_t *xl) +{ + return; +} + +struct sched_ops sched = { + .init = switch_init, + .fini = switch_fini, + .update = switch_update, + .schedule = switch_schedule, + .notify = switch_notify +}; + +struct volume_options options[] = { + { .key = { "scheduler.read-only-subvolumes" , + "switch.read-only-subvolumes"}, + .type = GF_OPTION_TYPE_ANY + }, + { .key = { "scheduler.local-volume-name", + "switch.nufa.local-volume-name" }, + .type = GF_OPTION_TYPE_XLATOR + }, + { .key = { "scheduler.switch.case", + "switch.case" }, + .type = GF_OPTION_TYPE_ANY + }, + { .key = {NULL} } +}; |